anantham-v2 2.0.3 → 2.0.5
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/bin/anantham.js +10 -1
- package/dist/bin/anantham.js.map +1 -1
- package/dist/cli/command-registry.d.ts.map +1 -1
- package/dist/cli/command-registry.js +178 -99
- package/dist/cli/command-registry.js.map +1 -1
- package/dist/domain/tui.d.ts +1 -1
- package/dist/domain/tui.d.ts.map +1 -1
- package/dist/domain/tui.js +1 -0
- package/dist/domain/tui.js.map +1 -1
- package/dist/persistence/index.d.ts +2 -0
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +2 -0
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/model-catalog-cache.d.ts +92 -0
- package/dist/persistence/model-catalog-cache.d.ts.map +1 -0
- package/dist/persistence/model-catalog-cache.js +430 -0
- package/dist/persistence/model-catalog-cache.js.map +1 -0
- package/dist/persistence/openrouter-key-validator.d.ts +40 -0
- package/dist/persistence/openrouter-key-validator.d.ts.map +1 -0
- package/dist/persistence/openrouter-key-validator.js +183 -0
- package/dist/persistence/openrouter-key-validator.js.map +1 -0
- package/dist/persistence/token-metrics-manager.d.ts +8 -2
- package/dist/persistence/token-metrics-manager.d.ts.map +1 -1
- package/dist/persistence/token-metrics-manager.js +60 -7
- package/dist/persistence/token-metrics-manager.js.map +1 -1
- package/dist/persistence/user-config-manager.d.ts +33 -9
- package/dist/persistence/user-config-manager.d.ts.map +1 -1
- package/dist/persistence/user-config-manager.js +133 -11
- package/dist/persistence/user-config-manager.js.map +1 -1
- package/dist/tui/index.d.ts +1 -0
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +1 -0
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/model-accordion-browser.d.ts +80 -0
- package/dist/tui/model-accordion-browser.d.ts.map +1 -0
- package/dist/tui/model-accordion-browser.js +487 -0
- package/dist/tui/model-accordion-browser.js.map +1 -0
- package/dist/tui/model-catalog-cache.d.ts +7 -0
- package/dist/tui/model-catalog-cache.d.ts.map +1 -0
- package/dist/tui/model-catalog-cache.js +7 -0
- package/dist/tui/model-catalog-cache.js.map +1 -0
- package/dist/tui/teamwork-preview-canvas.d.ts +63 -0
- package/dist/tui/teamwork-preview-canvas.d.ts.map +1 -0
- package/dist/tui/teamwork-preview-canvas.js +294 -0
- package/dist/tui/teamwork-preview-canvas.js.map +1 -0
- package/dist/tui/terminal-layout.d.ts +56 -2
- package/dist/tui/terminal-layout.d.ts.map +1 -1
- package/dist/tui/terminal-layout.js +258 -22
- package/dist/tui/terminal-layout.js.map +1 -1
- package/dist/tui/terminal-logo-renderer.d.ts +63 -0
- package/dist/tui/terminal-logo-renderer.d.ts.map +1 -0
- package/dist/tui/terminal-logo-renderer.js +304 -0
- package/dist/tui/terminal-logo-renderer.js.map +1 -0
- package/dist/tui/token-usage-tracker.d.ts +8 -0
- package/dist/tui/token-usage-tracker.d.ts.map +1 -0
- package/dist/tui/token-usage-tracker.js +8 -0
- package/dist/tui/token-usage-tracker.js.map +1 -0
- package/dist/tui/tui-controller.d.ts +13 -0
- package/dist/tui/tui-controller.d.ts.map +1 -1
- package/dist/tui/tui-controller.js +116 -6
- package/dist/tui/tui-controller.js.map +1 -1
- package/dist/tui/tui-renderer.d.ts +3 -1
- package/dist/tui/tui-renderer.d.ts.map +1 -1
- package/dist/tui/tui-renderer.js +31 -41
- package/dist/tui/tui-renderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import { UserConfigManager } from "./user-config-manager.js";
|
|
5
|
+
/**
|
|
6
|
+
* Normalizes an OpenRouter model ID into a standardized provider string.
|
|
7
|
+
*/
|
|
8
|
+
export function normalizeProvider(rawId) {
|
|
9
|
+
const cleanId = rawId.startsWith("openrouter/") ? rawId.slice("openrouter/".length) : rawId;
|
|
10
|
+
const parts = cleanId.split("/");
|
|
11
|
+
if (parts.length >= 2 && parts[0]) {
|
|
12
|
+
const p = parts[0].toLowerCase();
|
|
13
|
+
if (p === "openai")
|
|
14
|
+
return "openai";
|
|
15
|
+
if (p === "anthropic")
|
|
16
|
+
return "anthropic";
|
|
17
|
+
if (p === "google")
|
|
18
|
+
return "google";
|
|
19
|
+
if (p === "deepseek")
|
|
20
|
+
return "deepseek";
|
|
21
|
+
if (p === "meta-llama" || p === "meta" || p === "llama")
|
|
22
|
+
return "meta-llama";
|
|
23
|
+
if (p === "virtuals")
|
|
24
|
+
return "virtuals";
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
return "other";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses per-token pricing to price per 1 Million tokens.
|
|
31
|
+
*/
|
|
32
|
+
export function parsePricePerM(rawPrice) {
|
|
33
|
+
if (rawPrice === undefined || rawPrice === null)
|
|
34
|
+
return 0;
|
|
35
|
+
const num = typeof rawPrice === "number" ? rawPrice : parseFloat(String(rawPrice));
|
|
36
|
+
if (isNaN(num) || num <= 0)
|
|
37
|
+
return 0;
|
|
38
|
+
const perM = num * 1_000_000;
|
|
39
|
+
return Number(perM.toFixed(4));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Persistent cache manager for OpenRouter live catalog models.
|
|
43
|
+
* Saves to ~/.antigravity/models_cache.json with 1-hour TTL and fallback to ~/.anantham/models_cache.json.
|
|
44
|
+
*/
|
|
45
|
+
export class ModelCatalogCache {
|
|
46
|
+
static instance;
|
|
47
|
+
storageDir;
|
|
48
|
+
storagePath;
|
|
49
|
+
fallbackStorageDir;
|
|
50
|
+
fallbackStoragePath;
|
|
51
|
+
ttlMs;
|
|
52
|
+
memoryCache = null;
|
|
53
|
+
static DEFAULT_TTL_MS = 3_600_000; // 1 hour
|
|
54
|
+
/**
|
|
55
|
+
* Curated high-performance fallback models across the 6 major providers.
|
|
56
|
+
*/
|
|
57
|
+
static CURATED_MODELS = [
|
|
58
|
+
// Anthropic
|
|
59
|
+
{
|
|
60
|
+
id: "anthropic/claude-3.5-sonnet",
|
|
61
|
+
name: "Claude 3.5 Sonnet",
|
|
62
|
+
provider: "anthropic",
|
|
63
|
+
contextLength: 200_000,
|
|
64
|
+
promptPricePerM: 3.0,
|
|
65
|
+
completionPricePerM: 15.0,
|
|
66
|
+
description: "Anthropic's flagship intelligent and balanced reasoning model",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "anthropic/claude-3.7-sonnet",
|
|
70
|
+
name: "Claude 3.7 Sonnet",
|
|
71
|
+
provider: "anthropic",
|
|
72
|
+
contextLength: 200_000,
|
|
73
|
+
promptPricePerM: 3.0,
|
|
74
|
+
completionPricePerM: 15.0,
|
|
75
|
+
description: "Anthropic's premier hybrid reasoning and coding model",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "anthropic/claude-3.5-haiku",
|
|
79
|
+
name: "Claude 3.5 Haiku",
|
|
80
|
+
provider: "anthropic",
|
|
81
|
+
contextLength: 200_000,
|
|
82
|
+
promptPricePerM: 0.8,
|
|
83
|
+
completionPricePerM: 4.0,
|
|
84
|
+
description: "Ultra-fast lightweight model with near-Sonnet performance",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "anthropic/claude-3-opus",
|
|
88
|
+
name: "Claude 3 Opus",
|
|
89
|
+
provider: "anthropic",
|
|
90
|
+
contextLength: 200_000,
|
|
91
|
+
promptPricePerM: 15.0,
|
|
92
|
+
completionPricePerM: 75.0,
|
|
93
|
+
description: "Anthropic's highest-power model for complex creative and scientific work",
|
|
94
|
+
},
|
|
95
|
+
// OpenAI
|
|
96
|
+
{
|
|
97
|
+
id: "openai/gpt-4o",
|
|
98
|
+
name: "GPT-4o",
|
|
99
|
+
provider: "openai",
|
|
100
|
+
contextLength: 128_000,
|
|
101
|
+
promptPricePerM: 2.5,
|
|
102
|
+
completionPricePerM: 10.0,
|
|
103
|
+
description: "OpenAI versatile high-intelligence multimodal flagship",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "openai/gpt-4o-mini",
|
|
107
|
+
name: "GPT-4o Mini",
|
|
108
|
+
provider: "openai",
|
|
109
|
+
contextLength: 128_000,
|
|
110
|
+
promptPricePerM: 0.15,
|
|
111
|
+
completionPricePerM: 0.6,
|
|
112
|
+
description: "Affordable, fast, lightweight model for high-frequency tasks",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "openai/o1",
|
|
116
|
+
name: "o1 Reasoning",
|
|
117
|
+
provider: "openai",
|
|
118
|
+
contextLength: 200_000,
|
|
119
|
+
promptPricePerM: 15.0,
|
|
120
|
+
completionPricePerM: 60.0,
|
|
121
|
+
description: "Deep chain-of-thought model designed for math, coding, and science",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "openai/o3-mini",
|
|
125
|
+
name: "o3 Mini",
|
|
126
|
+
provider: "openai",
|
|
127
|
+
contextLength: 200_000,
|
|
128
|
+
promptPricePerM: 1.1,
|
|
129
|
+
completionPricePerM: 4.4,
|
|
130
|
+
description: "Fast reasoning model optimized for STEM and coding workflows",
|
|
131
|
+
},
|
|
132
|
+
// Google
|
|
133
|
+
{
|
|
134
|
+
id: "google/gemini-2.5-pro",
|
|
135
|
+
name: "Gemini 2.5 Pro",
|
|
136
|
+
provider: "google",
|
|
137
|
+
contextLength: 1_000_000,
|
|
138
|
+
promptPricePerM: 1.25,
|
|
139
|
+
completionPricePerM: 5.0,
|
|
140
|
+
description: "Google's ultra-long context reasoning and multimodal powerhouse",
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "google/gemini-2.0-flash",
|
|
144
|
+
name: "Gemini 2.0 Flash",
|
|
145
|
+
provider: "google",
|
|
146
|
+
contextLength: 1_000_000,
|
|
147
|
+
promptPricePerM: 0.1,
|
|
148
|
+
completionPricePerM: 0.4,
|
|
149
|
+
description: "Low-latency multimodal model with 1M context window",
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: "google/gemini-1.5-pro",
|
|
153
|
+
name: "Gemini 1.5 Pro",
|
|
154
|
+
provider: "google",
|
|
155
|
+
contextLength: 2_000_000,
|
|
156
|
+
promptPricePerM: 1.25,
|
|
157
|
+
completionPricePerM: 5.0,
|
|
158
|
+
description: "2M token context window for massive codebase ingestion",
|
|
159
|
+
},
|
|
160
|
+
// DeepSeek
|
|
161
|
+
{
|
|
162
|
+
id: "deepseek/deepseek-r1",
|
|
163
|
+
name: "DeepSeek R1",
|
|
164
|
+
provider: "deepseek",
|
|
165
|
+
contextLength: 64_000,
|
|
166
|
+
promptPricePerM: 0.55,
|
|
167
|
+
completionPricePerM: 2.19,
|
|
168
|
+
description: "Open-weights reasoning model with exceptional STEM performance",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: "deepseek/deepseek-chat",
|
|
172
|
+
name: "DeepSeek V3",
|
|
173
|
+
provider: "deepseek",
|
|
174
|
+
contextLength: 64_000,
|
|
175
|
+
promptPricePerM: 0.14,
|
|
176
|
+
completionPricePerM: 0.28,
|
|
177
|
+
description: "High-efficiency MoE language model with top benchmark scores",
|
|
178
|
+
},
|
|
179
|
+
// Meta / Llama
|
|
180
|
+
{
|
|
181
|
+
id: "meta-llama/llama-3.3-70b-instruct",
|
|
182
|
+
name: "Llama 3.3 70B Instruct",
|
|
183
|
+
provider: "meta-llama",
|
|
184
|
+
contextLength: 128_000,
|
|
185
|
+
promptPricePerM: 0.12,
|
|
186
|
+
completionPricePerM: 0.3,
|
|
187
|
+
description: "Industry-standard open model with state-of-the-art 70B weights",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: "meta-llama/llama-3.1-405b-instruct",
|
|
191
|
+
name: "Llama 3.1 405B Instruct",
|
|
192
|
+
provider: "meta-llama",
|
|
193
|
+
contextLength: 128_000,
|
|
194
|
+
promptPricePerM: 0.8,
|
|
195
|
+
completionPricePerM: 0.8,
|
|
196
|
+
description: "Frontier open-weights 405B parameter instruction model",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
id: "meta-llama/llama-3.1-8b-instruct",
|
|
200
|
+
name: "Llama 3.1 8B Instruct",
|
|
201
|
+
provider: "meta-llama",
|
|
202
|
+
contextLength: 128_000,
|
|
203
|
+
promptPricePerM: 0.05,
|
|
204
|
+
completionPricePerM: 0.05,
|
|
205
|
+
description: "Compact, extremely fast open model for low-latency agent loops",
|
|
206
|
+
},
|
|
207
|
+
// Virtuals
|
|
208
|
+
{
|
|
209
|
+
id: "virtuals/game-agent",
|
|
210
|
+
name: "Virtuals GAME Agent",
|
|
211
|
+
provider: "virtuals",
|
|
212
|
+
contextLength: 32_000,
|
|
213
|
+
promptPricePerM: 0.5,
|
|
214
|
+
completionPricePerM: 1.5,
|
|
215
|
+
description: "On-chain autonomous agent execution model",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "virtuals/sentient-ai",
|
|
219
|
+
name: "Virtuals Sentient AI",
|
|
220
|
+
provider: "virtuals",
|
|
221
|
+
contextLength: 32_000,
|
|
222
|
+
promptPricePerM: 1.0,
|
|
223
|
+
completionPricePerM: 3.0,
|
|
224
|
+
description: "Interactive autonomous agent persona and simulation model",
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
constructor(customStorageDir, ttlMs = ModelCatalogCache.DEFAULT_TTL_MS, customFallbackDir) {
|
|
228
|
+
this.storageDir = customStorageDir || path.join(os.homedir(), ".antigravity");
|
|
229
|
+
this.storagePath = path.join(this.storageDir, "models_cache.json");
|
|
230
|
+
this.fallbackStorageDir = customFallbackDir || (customStorageDir ? customStorageDir : path.join(os.homedir(), ".anantham"));
|
|
231
|
+
this.fallbackStoragePath = path.join(this.fallbackStorageDir, "models_cache.json");
|
|
232
|
+
this.ttlMs = ttlMs;
|
|
233
|
+
this.loadFromDisk();
|
|
234
|
+
}
|
|
235
|
+
static getInstance(customStorageDir, ttlMs, customFallbackDir) {
|
|
236
|
+
if (!ModelCatalogCache.instance || customStorageDir !== undefined || customFallbackDir !== undefined) {
|
|
237
|
+
ModelCatalogCache.instance = new ModelCatalogCache(customStorageDir, ttlMs, customFallbackDir);
|
|
238
|
+
}
|
|
239
|
+
return ModelCatalogCache.instance;
|
|
240
|
+
}
|
|
241
|
+
static resetInstance() {
|
|
242
|
+
ModelCatalogCache.instance = undefined;
|
|
243
|
+
}
|
|
244
|
+
getStorageDir() {
|
|
245
|
+
return this.storageDir;
|
|
246
|
+
}
|
|
247
|
+
getStoragePath() {
|
|
248
|
+
return this.storagePath;
|
|
249
|
+
}
|
|
250
|
+
getFallbackStoragePath() {
|
|
251
|
+
return this.fallbackStoragePath;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Reads cached models from disk if present and valid.
|
|
255
|
+
* Checks primary path first (~/.antigravity/models_cache.json), then fallback (~/.anantham/models_cache.json).
|
|
256
|
+
*/
|
|
257
|
+
loadFromDisk() {
|
|
258
|
+
// 1. Primary cache path
|
|
259
|
+
try {
|
|
260
|
+
if (fs.existsSync(this.storagePath)) {
|
|
261
|
+
const raw = fs.readFileSync(this.storagePath, "utf-8");
|
|
262
|
+
const parsed = JSON.parse(raw);
|
|
263
|
+
if (parsed &&
|
|
264
|
+
typeof parsed.fetchedAt === "number" &&
|
|
265
|
+
Array.isArray(parsed.models) &&
|
|
266
|
+
parsed.models.length > 0) {
|
|
267
|
+
this.memoryCache = parsed;
|
|
268
|
+
return parsed;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// Primary cache read failed, attempt fallback
|
|
274
|
+
}
|
|
275
|
+
// 2. Fallback cache path
|
|
276
|
+
try {
|
|
277
|
+
if (this.fallbackStoragePath !== this.storagePath && fs.existsSync(this.fallbackStoragePath)) {
|
|
278
|
+
const raw = fs.readFileSync(this.fallbackStoragePath, "utf-8");
|
|
279
|
+
const parsed = JSON.parse(raw);
|
|
280
|
+
if (parsed &&
|
|
281
|
+
typeof parsed.fetchedAt === "number" &&
|
|
282
|
+
Array.isArray(parsed.models) &&
|
|
283
|
+
parsed.models.length > 0) {
|
|
284
|
+
this.memoryCache = parsed;
|
|
285
|
+
return parsed;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Fallback cache read failed
|
|
291
|
+
}
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Synchronously returns cached models from memory or disk if available.
|
|
296
|
+
*/
|
|
297
|
+
getCachedModels() {
|
|
298
|
+
if (this.memoryCache && Array.isArray(this.memoryCache.models)) {
|
|
299
|
+
return this.memoryCache.models;
|
|
300
|
+
}
|
|
301
|
+
const loaded = this.loadFromDisk();
|
|
302
|
+
return loaded ? loaded.models : null;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Checks whether the current cache is within its valid TTL window.
|
|
306
|
+
*/
|
|
307
|
+
isCacheFresh() {
|
|
308
|
+
if (!this.memoryCache) {
|
|
309
|
+
this.loadFromDisk();
|
|
310
|
+
}
|
|
311
|
+
if (!this.memoryCache) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
const age = Date.now() - this.memoryCache.fetchedAt;
|
|
315
|
+
return age >= 0 && age < (this.memoryCache.ttlMs || this.ttlMs);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Saves models atomically to memory and disk using a temporary file and atomic rename.
|
|
319
|
+
*/
|
|
320
|
+
saveModels(models) {
|
|
321
|
+
const data = {
|
|
322
|
+
fetchedAt: Date.now(),
|
|
323
|
+
ttlMs: this.ttlMs,
|
|
324
|
+
models,
|
|
325
|
+
};
|
|
326
|
+
this.memoryCache = data;
|
|
327
|
+
try {
|
|
328
|
+
if (!fs.existsSync(this.storageDir)) {
|
|
329
|
+
fs.mkdirSync(this.storageDir, { recursive: true });
|
|
330
|
+
}
|
|
331
|
+
const tmpPath = path.join(this.storageDir, `models_cache.json.tmp.${Date.now()}.${Math.random().toString(36).slice(2, 8)}`);
|
|
332
|
+
fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
333
|
+
try {
|
|
334
|
+
fs.renameSync(tmpPath, this.storagePath);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
// Windows fallback: if renameSync encounters locking, copy and unlink
|
|
338
|
+
fs.copyFileSync(tmpPath, this.storagePath);
|
|
339
|
+
try {
|
|
340
|
+
fs.unlinkSync(tmpPath);
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
// Ignore temp cleanup errors
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
// Non-critical cache write failure
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Clears in-memory and on-disk cache.
|
|
353
|
+
*/
|
|
354
|
+
clearCache() {
|
|
355
|
+
this.memoryCache = null;
|
|
356
|
+
try {
|
|
357
|
+
if (fs.existsSync(this.storagePath)) {
|
|
358
|
+
fs.unlinkSync(this.storagePath);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
// Ignore cleanup error
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Fetches the model catalog:
|
|
367
|
+
* 1. Returns fresh cache if not forceRefresh.
|
|
368
|
+
* 2. Tries live OpenRouter API fetch with configured key.
|
|
369
|
+
* 3. Falls back to disk cache if available.
|
|
370
|
+
* 4. Falls back to built-in curated models across all 6 providers.
|
|
371
|
+
*/
|
|
372
|
+
async getModels(forceRefresh = false) {
|
|
373
|
+
if (!forceRefresh && this.isCacheFresh()) {
|
|
374
|
+
const cached = this.getCachedModels();
|
|
375
|
+
if (cached && cached.length > 0) {
|
|
376
|
+
return cached;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const apiKey = UserConfigManager.getInstance().getApiKey("openrouter") || process.env.OPENROUTER_API_KEY;
|
|
380
|
+
try {
|
|
381
|
+
const headers = {
|
|
382
|
+
"HTTP-Referer": "https://anantham.ai",
|
|
383
|
+
"X-Title": "Anantham V2",
|
|
384
|
+
};
|
|
385
|
+
if (apiKey) {
|
|
386
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
387
|
+
}
|
|
388
|
+
const response = await fetch("https://openrouter.ai/api/v1/models", {
|
|
389
|
+
method: "GET",
|
|
390
|
+
headers,
|
|
391
|
+
signal: AbortSignal.timeout(8000),
|
|
392
|
+
});
|
|
393
|
+
if (!response.ok) {
|
|
394
|
+
throw new Error(`OpenRouter models API returned HTTP ${response.status}: ${response.statusText}`);
|
|
395
|
+
}
|
|
396
|
+
const json = (await response.json());
|
|
397
|
+
if (json && Array.isArray(json.data) && json.data.length > 0) {
|
|
398
|
+
const normalized = json.data.map((m) => {
|
|
399
|
+
const provider = normalizeProvider(m.id);
|
|
400
|
+
const promptPricePerM = parsePricePerM(m.pricing?.prompt);
|
|
401
|
+
const completionPricePerM = parsePricePerM(m.pricing?.completion);
|
|
402
|
+
const contextLength = typeof m.context_length === "number" ? m.context_length : 4096;
|
|
403
|
+
return {
|
|
404
|
+
id: m.id,
|
|
405
|
+
name: m.name && m.name.trim().length > 0 ? m.name : m.id,
|
|
406
|
+
provider,
|
|
407
|
+
contextLength,
|
|
408
|
+
promptPricePerM,
|
|
409
|
+
completionPricePerM,
|
|
410
|
+
description: m.description,
|
|
411
|
+
};
|
|
412
|
+
});
|
|
413
|
+
this.saveModels(normalized);
|
|
414
|
+
return normalized;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// Network fetch failure or timeout: proceed to fallbacks
|
|
419
|
+
}
|
|
420
|
+
// Fallback 1: Disk or memory cache (even if expired)
|
|
421
|
+
const existing = this.getCachedModels();
|
|
422
|
+
if (existing && existing.length > 0) {
|
|
423
|
+
return existing;
|
|
424
|
+
}
|
|
425
|
+
// Fallback 2: Comprehensive curated models across all 6 providers
|
|
426
|
+
this.saveModels(ModelCatalogCache.CURATED_MODELS);
|
|
427
|
+
return ModelCatalogCache.CURATED_MODELS;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
//# sourceMappingURL=model-catalog-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-catalog-cache.js","sourceRoot":"","sources":["../../src/persistence/model-catalog-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anantham V2 / Antigravity CLI Harness — OpenRouter Key Validation Handshake
|
|
3
|
+
* Validates API key authenticity and parses account metadata before persistence.
|
|
4
|
+
*/
|
|
5
|
+
export interface OpenRouterKeyMetadata {
|
|
6
|
+
label: string;
|
|
7
|
+
limit: number | null;
|
|
8
|
+
usage: number;
|
|
9
|
+
is_free_tier: boolean;
|
|
10
|
+
rateLimit?: {
|
|
11
|
+
requests?: number;
|
|
12
|
+
interval?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface OpenRouterKeyValidationResult {
|
|
16
|
+
valid: boolean;
|
|
17
|
+
metadata?: OpenRouterKeyMetadata;
|
|
18
|
+
error?: string;
|
|
19
|
+
status?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface KeyValidationOptions {
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
fetchFn?: typeof fetch;
|
|
24
|
+
referer?: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}
|
|
28
|
+
export declare const DEFAULT_OPENROUTER_REFERER = "https://github.com/antigravity/cli";
|
|
29
|
+
export declare const DEFAULT_OPENROUTER_TITLE = "Antigravity CLI";
|
|
30
|
+
export declare const OPENROUTER_AUTH_KEY_ENDPOINT = "https://openrouter.ai/api/v1/auth/key";
|
|
31
|
+
/**
|
|
32
|
+
* Validates an OpenRouter API key against the auth key verification endpoint.
|
|
33
|
+
*
|
|
34
|
+
* Headers required:
|
|
35
|
+
* - Authorization: Bearer <API_KEY>
|
|
36
|
+
* - HTTP-Referer: https://github.com/antigravity/cli
|
|
37
|
+
* - X-Title: Antigravity CLI
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateOpenRouterKey(apiKey: string, options?: KeyValidationOptions): Promise<OpenRouterKeyValidationResult>;
|
|
40
|
+
//# sourceMappingURL=openrouter-key-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter-key-validator.d.ts","sourceRoot":"","sources":["../../src/persistence/openrouter-key-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,eAAO,MAAM,0BAA0B,uCAAuC,CAAC;AAC/E,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAC1D,eAAO,MAAM,4BAA4B,0CAA0C,CAAC;AAmCpF;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,6BAA6B,CAAC,CAwLxC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anantham V2 / Antigravity CLI Harness — OpenRouter Key Validation Handshake
|
|
3
|
+
* Validates API key authenticity and parses account metadata before persistence.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_OPENROUTER_REFERER = "https://github.com/antigravity/cli";
|
|
6
|
+
export const DEFAULT_OPENROUTER_TITLE = "Antigravity CLI";
|
|
7
|
+
export const OPENROUTER_AUTH_KEY_ENDPOINT = "https://openrouter.ai/api/v1/auth/key";
|
|
8
|
+
/**
|
|
9
|
+
* Validates an OpenRouter API key against the auth key verification endpoint.
|
|
10
|
+
*
|
|
11
|
+
* Headers required:
|
|
12
|
+
* - Authorization: Bearer <API_KEY>
|
|
13
|
+
* - HTTP-Referer: https://github.com/antigravity/cli
|
|
14
|
+
* - X-Title: Antigravity CLI
|
|
15
|
+
*/
|
|
16
|
+
export async function validateOpenRouterKey(apiKey, options) {
|
|
17
|
+
const trimmedKey = apiKey ? apiKey.trim() : "";
|
|
18
|
+
if (!trimmedKey) {
|
|
19
|
+
return {
|
|
20
|
+
valid: false,
|
|
21
|
+
error: "API key cannot be empty or invalid",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const timeoutMs = options?.timeoutMs ?? 10_000;
|
|
25
|
+
const referer = options?.referer ?? DEFAULT_OPENROUTER_REFERER;
|
|
26
|
+
const title = options?.title ?? DEFAULT_OPENROUTER_TITLE;
|
|
27
|
+
const fetchImpl = options?.fetchFn ?? globalThis.fetch;
|
|
28
|
+
if (typeof fetchImpl !== "function") {
|
|
29
|
+
return {
|
|
30
|
+
valid: false,
|
|
31
|
+
error: "Fetch API is unavailable in current runtime environment",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (options?.signal?.aborted) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
error: "OpenRouter key validation aborted by caller",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
42
|
+
const onExternalAbort = () => controller.abort();
|
|
43
|
+
if (options?.signal) {
|
|
44
|
+
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
45
|
+
}
|
|
46
|
+
let response;
|
|
47
|
+
try {
|
|
48
|
+
response = await fetchImpl(OPENROUTER_AUTH_KEY_ENDPOINT, {
|
|
49
|
+
method: "GET",
|
|
50
|
+
headers: {
|
|
51
|
+
Authorization: `Bearer ${trimmedKey}`,
|
|
52
|
+
"HTTP-Referer": referer,
|
|
53
|
+
"X-Title": title,
|
|
54
|
+
},
|
|
55
|
+
signal: controller.signal,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (err?.name === "AbortError" || controller.signal.aborted) {
|
|
60
|
+
if (options?.signal?.aborted) {
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
error: "OpenRouter key validation aborted by caller",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
valid: false,
|
|
68
|
+
error: `Network timeout validating OpenRouter key (${timeoutMs}ms exceeded)`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
valid: false,
|
|
73
|
+
error: `Network error validating OpenRouter key: ${err?.message || String(err)}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
if (options?.signal) {
|
|
79
|
+
options.signal.removeEventListener("abort", onExternalAbort);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!response || typeof response.status !== "number") {
|
|
83
|
+
return {
|
|
84
|
+
valid: false,
|
|
85
|
+
error: "No response received from OpenRouter auth API",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (response.status === 401) {
|
|
89
|
+
return {
|
|
90
|
+
valid: false,
|
|
91
|
+
status: 401,
|
|
92
|
+
error: "Invalid or revoked OpenRouter API key",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (response.status === 403) {
|
|
96
|
+
return {
|
|
97
|
+
valid: false,
|
|
98
|
+
status: 403,
|
|
99
|
+
error: "OpenRouter API key lacks required permissions",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (response.status === 429) {
|
|
103
|
+
return {
|
|
104
|
+
valid: false,
|
|
105
|
+
status: 429,
|
|
106
|
+
error: "OpenRouter rate limit exceeded during validation",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
return {
|
|
111
|
+
valid: false,
|
|
112
|
+
status: response.status,
|
|
113
|
+
error: `OpenRouter authentication service returned HTTP ${response.status}: ${response.statusText || "Error"}`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
let json;
|
|
117
|
+
try {
|
|
118
|
+
json = (await response.json());
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return {
|
|
122
|
+
valid: false,
|
|
123
|
+
status: response.status,
|
|
124
|
+
error: "Invalid JSON response from OpenRouter auth API",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (!json || typeof json !== "object") {
|
|
128
|
+
return {
|
|
129
|
+
valid: false,
|
|
130
|
+
status: response.status,
|
|
131
|
+
error: "Invalid JSON response payload from OpenRouter auth API",
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// Handle HTTP 200 error payloads (e.g. { error: { message: "..." } } or { data: { error: "..." } })
|
|
135
|
+
const errorObj = json.error ?? json.data?.error;
|
|
136
|
+
if (errorObj) {
|
|
137
|
+
const errorMessage = typeof errorObj === "string"
|
|
138
|
+
? errorObj
|
|
139
|
+
: typeof errorObj === "object" && typeof errorObj?.message === "string"
|
|
140
|
+
? errorObj.message
|
|
141
|
+
: "OpenRouter authentication failed with error payload";
|
|
142
|
+
return {
|
|
143
|
+
valid: false,
|
|
144
|
+
status: response.status,
|
|
145
|
+
error: errorMessage,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Parse metadata from either { data: { ... } } envelope or top-level fields
|
|
149
|
+
const payload = json.data && typeof json.data === "object" ? json.data : json;
|
|
150
|
+
const label = typeof payload.label === "string" && payload.label
|
|
151
|
+
? payload.label
|
|
152
|
+
: (typeof payload.name === "string" && payload.name ? payload.name : "Default Key");
|
|
153
|
+
let limit = null;
|
|
154
|
+
if (payload.limit !== undefined && payload.limit !== null) {
|
|
155
|
+
const num = Number(payload.limit);
|
|
156
|
+
limit = Number.isNaN(num) ? null : num;
|
|
157
|
+
}
|
|
158
|
+
let usage = 0;
|
|
159
|
+
if (payload.usage !== undefined && payload.usage !== null) {
|
|
160
|
+
const num = Number(payload.usage);
|
|
161
|
+
usage = Number.isNaN(num) ? 0 : num;
|
|
162
|
+
}
|
|
163
|
+
const is_free_tier = Boolean(payload.is_free_tier);
|
|
164
|
+
let rateLimit;
|
|
165
|
+
if (payload.rate_limit && typeof payload.rate_limit === "object") {
|
|
166
|
+
rateLimit = {
|
|
167
|
+
requests: typeof payload.rate_limit.requests === "number" ? payload.rate_limit.requests : undefined,
|
|
168
|
+
interval: typeof payload.rate_limit.interval === "string" ? payload.rate_limit.interval : undefined,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
valid: true,
|
|
173
|
+
status: response.status,
|
|
174
|
+
metadata: {
|
|
175
|
+
label,
|
|
176
|
+
limit,
|
|
177
|
+
usage,
|
|
178
|
+
is_free_tier,
|
|
179
|
+
...(rateLimit ? { rateLimit } : {}),
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=openrouter-key-validator.js.map
|