loom-agent 1.3.3 → 1.5.0
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 +189 -0
- package/README.md +9 -7
- package/package.json +2 -2
- package/src/core/agents.js +14 -1
- package/src/core/cli.js +30 -2
- package/src/core/hooks.js +28 -14
- package/src/core/memory.js +54 -6
- package/src/core/permissions.js +17 -4
- package/src/core/plugin-cmd.js +88 -1
- package/src/core/sandbox.js +61 -1
- package/src/core/session.js +262 -36
- package/src/core/transcript-undo.js +74 -0
- package/src/core/update.js +116 -6
- package/src/mcp/connector-presets.js +105 -0
- package/src/providers/anthropic.js +122 -25
- package/src/providers/google.js +19 -11
- package/src/providers/nvidia.js +45 -33
- package/src/providers/openai-compat.js +59 -27
- package/src/providers/openai.js +42 -18
- package/src/providers/openrouter.js +56 -26
- package/src/tools/index.js +193 -30
- package/src/tui/App.tsx +249 -35
- package/src/tui/components/Modals.tsx +64 -19
- package/src/tui/mcp-presets.ts +4 -65
- package/src/tui/store.ts +6 -1
|
@@ -52,7 +52,7 @@ function formatTools(tools) {
|
|
|
52
52
|
}));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function buildRequest(messages, options) {
|
|
55
|
+
function buildRequest(messages, options, providerId) {
|
|
56
56
|
const body = {
|
|
57
57
|
model: options.model,
|
|
58
58
|
messages: formatMessages(messages, options),
|
|
@@ -60,6 +60,12 @@ function buildRequest(messages, options) {
|
|
|
60
60
|
max_tokens: options.maxTokens || 8192,
|
|
61
61
|
temperature: options.temperature ?? 0.7,
|
|
62
62
|
};
|
|
63
|
+
// OpenRouter/TokenRouter prompt caching: top-level "cache_control" true
|
|
64
|
+
// (auto-detects prefix-cache-capable models, ignores it otherwise). Cuts
|
|
65
|
+
// input cost on cache hits (~10% of full price) after the first turn.
|
|
66
|
+
if (providerId === 'openrouter' || providerId === 'tokenrouter') {
|
|
67
|
+
body.cache_control = true;
|
|
68
|
+
}
|
|
63
69
|
// Reasoning models (o1/o3/o4/gpt-5, tagged 'reasoning' by the session):
|
|
64
70
|
// push the effort to "high" so the model reasons deeply on every step —
|
|
65
71
|
// opencode-style multi-pass thinking. Other reasoning families (DeepSeek
|
|
@@ -110,27 +116,43 @@ function sanitizeErrBody(msg) {
|
|
|
110
116
|
function wrapErr(err, modelId, envKeyHint, baseURL) {
|
|
111
117
|
const raw = err.message || 'Unknown error';
|
|
112
118
|
const msg = sanitizeErrBody(raw);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
// Carry the HTTP status + Retry-After onto the wrapped error so the
|
|
120
|
+
// session loop can tell a rate-limit (wait+retry) from a quota switch.
|
|
121
|
+
const out = /** @type {any} */ (!err.status ? new Error(`${envKeyHint || 'API'} error: ${msg}`) : (() => {
|
|
122
|
+
const status = Number(err.status);
|
|
123
|
+
const hint = String(envKeyHint || 'api').toLowerCase();
|
|
124
|
+
if (status === 401) {
|
|
125
|
+
return new Error(`${envKeyHint || 'API'} 401 Unauthorized: the API key is invalid or expired. Run /connect ${hint} and paste a new key.`);
|
|
126
|
+
}
|
|
127
|
+
if (status === 403) {
|
|
128
|
+
return new Error(`${envKeyHint || 'API'} 403 Forbidden: the API key is not authorized for ${modelId || 'this model'}. You may need to accept the model's terms on the provider site or use a key with access. Run /connect ${hint} to change the key.`);
|
|
129
|
+
}
|
|
130
|
+
if (status === 402) return new Error(`${envKeyHint || 'API'} quota exceeded (${err.status}). The model may not be available on your billing tier for model ${(modelId || '?')}.`);
|
|
131
|
+
if (status === 404) {
|
|
132
|
+
const modelHint = modelId ? ` ${modelId}` : '';
|
|
133
|
+
return new Error(`${envKeyHint || 'API'} 404: model${modelHint} does not exist (or was removed) on this provider. Try /models and pick a listed model, or /model ${modelId ? 'to switch' : ''}.`);
|
|
134
|
+
}
|
|
135
|
+
if (err.error && err.error.message) return new Error(`${envKeyHint || 'API'} error ${status}: ${sanitizeErrBody(err.error.message)}`);
|
|
136
|
+
if (err.body && err.body.message) return new Error(`${envKeyHint || 'API'} error ${status}: ${sanitizeErrBody(err.body.message)}`);
|
|
137
|
+
if (!msg || msg.indexOf('no body') >= 0) {
|
|
138
|
+
const modelHint = modelId ? ` (model: ${modelId})` : '';
|
|
139
|
+
return new Error(`${envKeyHint || 'API'} error ${status}${modelHint}. Check model name or URL:\n${baseURL || '(default)'}`);
|
|
140
|
+
}
|
|
141
|
+
return new Error(`${envKeyHint || 'API'} error ${status}: ${msg}`);
|
|
142
|
+
})());
|
|
143
|
+
out.status = err.status ? Number(err.status) : undefined;
|
|
144
|
+
// Retry-After from the openai SDK error headers (seconds or HTTP-date).
|
|
145
|
+
const hdrs = err.headers;
|
|
146
|
+
const ra = hdrs && (typeof hdrs.get === 'function' ? hdrs.get('retry-after') : hdrs['retry-after']);
|
|
147
|
+
if (ra) {
|
|
148
|
+
const secs = Number(ra);
|
|
149
|
+
if (Number.isFinite(secs) && secs >= 0) out.retryAfterMs = Math.min(secs * 1000, 60000);
|
|
150
|
+
else {
|
|
151
|
+
const t = Date.parse(ra);
|
|
152
|
+
if (Number.isFinite(t)) out.retryAfterMs = Math.min(Math.max(0, t - Date.now()), 60000);
|
|
153
|
+
}
|
|
132
154
|
}
|
|
133
|
-
return
|
|
155
|
+
return out;
|
|
134
156
|
}
|
|
135
157
|
|
|
136
158
|
async function retryWithBackoff(fn, maxTries, envKeyHint) {
|
|
@@ -142,10 +164,20 @@ async function retryWithBackoff(fn, maxTries, envKeyHint) {
|
|
|
142
164
|
lastErr = err;
|
|
143
165
|
if (isAbortError(err)) throw err;
|
|
144
166
|
const status = err.status || err.code;
|
|
145
|
-
if (status !== 429 && status !== 503 && status !== 502) throw lastErr;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
if (status !== 429 && status !== 503 && status !== 502 && status !== 529) throw lastErr;
|
|
168
|
+
{
|
|
169
|
+
// Honor Retry-After when the provider sends one (even on the first
|
|
170
|
+
// retry); otherwise the first retry is immediate (transient blip)
|
|
171
|
+
// and later ones back off exponentially. Jitter avoids a thundering
|
|
172
|
+
// herd of parallel retries.
|
|
173
|
+
let delay = attempt > 0 ? Math.min(1000 * Math.pow(3, attempt - 1), 30000) : 0;
|
|
174
|
+
const hdrs = err.headers;
|
|
175
|
+
const ra = hdrs && (typeof hdrs.get === 'function' ? hdrs.get('retry-after') : hdrs['retry-after']);
|
|
176
|
+
if (ra) {
|
|
177
|
+
const secs = Number(ra);
|
|
178
|
+
if (Number.isFinite(secs) && secs >= 0) delay = Math.min(secs * 1000, 60000);
|
|
179
|
+
}
|
|
180
|
+
await new Promise((resolve) => setTimeout(resolve, delay + (delay > 0 ? Math.floor(Math.random() * 250) : 0)));
|
|
149
181
|
}
|
|
150
182
|
}
|
|
151
183
|
}
|
|
@@ -194,7 +226,7 @@ function createOpenAICompatProvider({ getKey, providerId, envKeyHint, clientFact
|
|
|
194
226
|
|
|
195
227
|
async function chat(messages, options = {}) {
|
|
196
228
|
const client = getClient();
|
|
197
|
-
const req = buildRequest(messages, options);
|
|
229
|
+
const req = buildRequest(messages, options, providerId);
|
|
198
230
|
const requestOpts = { signal: options.signal };
|
|
199
231
|
try {
|
|
200
232
|
const resp = await retryWithBackoff(() => client.chat.completions.create(req, requestOpts), 4, envKeyHint);
|
|
@@ -207,7 +239,7 @@ function createOpenAICompatProvider({ getKey, providerId, envKeyHint, clientFact
|
|
|
207
239
|
|
|
208
240
|
async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
209
241
|
const client = getClient();
|
|
210
|
-
const req = { ...buildRequest(messages, options), stream: true, stream_options: { include_usage: true } };
|
|
242
|
+
const req = { ...buildRequest(messages, options, providerId), stream: true, stream_options: { include_usage: true } };
|
|
211
243
|
const requestOpts = { signal: options.signal };
|
|
212
244
|
try {
|
|
213
245
|
const s = await retryWithBackoff(() => client.chat.completions.create(req, requestOpts), 4, envKeyHint);
|
package/src/providers/openai.js
CHANGED
|
@@ -11,24 +11,48 @@ const provider = {
|
|
|
11
11
|
envKeyHint: 'OPENAI',
|
|
12
12
|
}),
|
|
13
13
|
models: [
|
|
14
|
-
//
|
|
15
|
-
{ id: 'gpt-
|
|
16
|
-
{ id: 'gpt-
|
|
17
|
-
{ id: 'gpt-
|
|
18
|
-
{ id: 'gpt-
|
|
19
|
-
|
|
20
|
-
// GPT-
|
|
21
|
-
{ id: 'gpt-
|
|
22
|
-
{ id: 'gpt-
|
|
23
|
-
{ id: 'gpt-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
{ id: '
|
|
27
|
-
{ id: '
|
|
28
|
-
{ id: '
|
|
29
|
-
{ id: '
|
|
30
|
-
{ id: '
|
|
31
|
-
|
|
14
|
+
// ── GPT-6 Series ──
|
|
15
|
+
{ id: 'gpt-6-astra', name: 'GPT-6 Astra', provider: 'openai', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 10, priceOut: 50 },
|
|
16
|
+
{ id: 'gpt-6-sol', name: 'GPT-6 Sol', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 10 },
|
|
17
|
+
{ id: 'gpt-6.1-sol', name: 'GPT-6.1 Sol', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 10 },
|
|
18
|
+
{ id: 'gpt-6-luna', name: 'GPT-6 Luna', provider: 'openai', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.1, priceOut: 0.5 },
|
|
19
|
+
|
|
20
|
+
// ── GPT-5.6 / 5.5 / 5.4 ──
|
|
21
|
+
{ id: 'gpt-5.6', name: 'GPT-5.6', provider: 'openai', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 4, priceOut: 20 },
|
|
22
|
+
{ id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 4, priceOut: 20 },
|
|
23
|
+
{ id: 'gpt-5.6-terra', name: 'GPT-5.6 Terra', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 12 },
|
|
24
|
+
{ id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna', provider: 'openai', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.2, priceOut: 1.2 },
|
|
25
|
+
{ id: 'gpt-5.5', name: 'GPT-5.5', provider: 'openai', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 5, priceOut: 30 },
|
|
26
|
+
{ id: 'gpt-5.5-pro', name: 'GPT-5.5 Pro', provider: 'openai', tags: ['reasoning', 'pro'], context: 1050000, priceIn: 30, priceOut: 180 },
|
|
27
|
+
{ id: 'gpt-5.4', name: 'GPT-5.4', provider: 'openai', tags: ['reasoning'], context: 1050000, priceIn: 2.5, priceOut: 15 },
|
|
28
|
+
{ id: 'gpt-5.4-mini', name: 'GPT-5.4 Mini', provider: 'openai', tags: ['fast', 'reasoning'], context: 400000, priceIn: 0.75, priceOut: 4.5 },
|
|
29
|
+
{ id: 'gpt-5.4-nano', name: 'GPT-5.4 Nano', provider: 'openai', tags: ['cheap', 'fast', 'reasoning'], context: 400000, priceIn: 0.2, priceOut: 1.25 },
|
|
30
|
+
{ id: 'gpt-5.4-pro', name: 'GPT-5.4 Pro', provider: 'openai', tags: ['reasoning', 'pro'], context: 1050000, priceIn: 30, priceOut: 180 },
|
|
31
|
+
|
|
32
|
+
// ── GPT-5 Codex (coding) ──
|
|
33
|
+
{ id: 'gpt-5.3-codex', name: 'GPT-5.3 Codex', provider: 'openai', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
|
|
34
|
+
{ id: 'gpt-5.3-codex-spark', name: 'GPT-5.3 Codex Spark', provider: 'openai', tags: ['coding', 'fast', 'reasoning'], context: 128000, priceIn: 1.75, priceOut: 14 },
|
|
35
|
+
|
|
36
|
+
// ── GPT-5 Series ──
|
|
37
|
+
{ id: 'gpt-5.2', name: 'GPT-5.2', provider: 'openai', tags: ['reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
|
|
38
|
+
{ id: 'gpt-5.1', name: 'GPT-5.1', provider: 'openai', tags: ['reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
|
|
39
|
+
{ id: 'gpt-5', name: 'GPT-5', provider: 'openai', tags: ['frontier', 'reasoning'], context: 400000, priceIn: 1.25, priceOut: 10 },
|
|
40
|
+
{ id: 'gpt-5-mini', name: 'GPT-5 Mini', provider: 'openai', tags: ['fast', 'reasoning'], context: 400000, priceIn: 0.25, priceOut: 2 },
|
|
41
|
+
{ id: 'gpt-5-nano', name: 'GPT-5 Nano', provider: 'openai', tags: ['cheap', 'fast', 'reasoning'], context: 400000, priceIn: 0.05, priceOut: 0.4 },
|
|
42
|
+
{ id: 'gpt-5-pro', name: 'GPT-5 Pro', provider: 'openai', tags: ['reasoning', 'pro'], context: 400000, priceIn: 15, priceOut: 120 },
|
|
43
|
+
|
|
44
|
+
// ── O-Series (Reasoning, legacy) ──
|
|
45
|
+
{ id: 'o3', name: 'o3', provider: 'openai', tags: ['reasoning', 'legacy'], context: 200000, priceIn: 2, priceOut: 8 },
|
|
46
|
+
{ id: 'o3-pro', name: 'o3 Pro', provider: 'openai', tags: ['reasoning', 'pro', 'legacy'], context: 200000, priceIn: 20, priceOut: 80 },
|
|
47
|
+
{ id: 'o3-mini', name: 'o3 Mini', provider: 'openai', tags: ['reasoning', 'fast', 'legacy'], context: 200000, priceIn: 1.1, priceOut: 4.4 },
|
|
48
|
+
{ id: 'o4-mini', name: 'o4 Mini', provider: 'openai', tags: ['reasoning', 'fast', 'legacy'], context: 200000, priceIn: 1.1, priceOut: 4.4 },
|
|
49
|
+
|
|
50
|
+
// ── GPT-4.1 / 4o (legacy) ──
|
|
51
|
+
{ id: 'gpt-4.1', name: 'GPT-4.1', provider: 'openai', tags: ['legacy'], context: 1047576, priceIn: 2, priceOut: 8 },
|
|
52
|
+
{ id: 'gpt-4.1-mini', name: 'GPT-4.1 Mini', provider: 'openai', tags: ['fast', 'legacy'], context: 1047576, priceIn: 0.4, priceOut: 1.6 },
|
|
53
|
+
{ id: 'gpt-4.1-nano', name: 'GPT-4.1 Nano', provider: 'openai', tags: ['cheap', 'fast', 'legacy'], context: 1047576, priceIn: 0.1, priceOut: 0.4 },
|
|
54
|
+
{ id: 'gpt-4o', name: 'GPT-4o', provider: 'openai', tags: ['legacy', 'multimodal'], context: 128000, priceIn: 2.5, priceOut: 10 },
|
|
55
|
+
{ id: 'gpt-4o-mini', name: 'GPT-4o Mini', provider: 'openai', tags: ['fast', 'multimodal', 'legacy'], context: 128000, priceIn: 0.15, priceOut: 0.6 },
|
|
32
56
|
],
|
|
33
57
|
};
|
|
34
58
|
|
|
@@ -12,32 +12,62 @@ const provider = {
|
|
|
12
12
|
envKeyHint: 'OPENROUTER',
|
|
13
13
|
}),
|
|
14
14
|
models: [
|
|
15
|
-
// Anthropic
|
|
16
|
-
{ id: 'anthropic/claude-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
{ id: '
|
|
20
|
-
{ id: '
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{ id: '
|
|
26
|
-
{ id: '
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{ id: '
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{ id: '
|
|
38
|
-
{ id: '
|
|
39
|
-
|
|
40
|
-
|
|
15
|
+
// ── Anthropic ──
|
|
16
|
+
{ id: 'anthropic/claude-opus-5.5', name: 'Claude Opus 5.5 (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1000000, priceIn: 4, priceOut: 20 },
|
|
17
|
+
{ id: 'anthropic/claude-opus-4.8', name: 'Claude Opus 4.8 (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1000000, priceIn: 5, priceOut: 25 },
|
|
18
|
+
{ id: 'anthropic/claude-sonnet-5.5', name: 'Claude Sonnet 5.5 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1000000, priceIn: 2, priceOut: 10 },
|
|
19
|
+
{ id: 'anthropic/claude-sonnet-4.6', name: 'Claude Sonnet 4.6 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1000000, priceIn: 3, priceOut: 15 },
|
|
20
|
+
{ id: 'anthropic/claude-haiku-5.5', name: 'Claude Haiku 5.5 (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'reasoning'], context: 1000000, priceIn: 0.1, priceOut: 0.5 },
|
|
21
|
+
|
|
22
|
+
// ── OpenAI ──
|
|
23
|
+
{ id: 'openai/gpt-6-astra', name: 'GPT-6 Astra (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 10, priceOut: 50 },
|
|
24
|
+
{ id: 'openai/gpt-6-sol', name: 'GPT-6 Sol (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 10 },
|
|
25
|
+
{ id: 'openai/gpt-6-luna', name: 'GPT-6 Luna (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.1, priceOut: 0.5 },
|
|
26
|
+
{ id: 'openai/gpt-5.6-sol', name: 'GPT-5.6 Sol (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1050000, priceIn: 4, priceOut: 20 },
|
|
27
|
+
{ id: 'openai/gpt-5.6-terra', name: 'GPT-5.6 Terra (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1050000, priceIn: 2, priceOut: 12 },
|
|
28
|
+
{ id: 'openai/gpt-5.6-luna', name: 'GPT-5.6 Luna (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'cheap', 'reasoning'], context: 1050000, priceIn: 0.2, priceOut: 1.2 },
|
|
29
|
+
{ id: 'openai/gpt-5.5', name: 'GPT-5.5 (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1050000, priceIn: 5, priceOut: 30 },
|
|
30
|
+
{ id: 'openai/gpt-5.4', name: 'GPT-5.4 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1050000, priceIn: 2.5, priceOut: 15 },
|
|
31
|
+
{ id: 'openai/gpt-5.3-codex', name: 'GPT-5.3 Codex (via OpenRouter)', provider: 'openrouter', tags: ['coding', 'reasoning'], context: 400000, priceIn: 1.75, priceOut: 14 },
|
|
32
|
+
{ id: 'openai/o3', name: 'o3 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning', 'legacy'], context: 200000, priceIn: 2, priceOut: 8 },
|
|
33
|
+
|
|
34
|
+
// ── Google ──
|
|
35
|
+
{ id: 'google/gemini-4-argon', name: 'Gemini 4 Argon (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1048576, priceIn: 2, priceOut: 10 },
|
|
36
|
+
{ id: 'google/gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro Preview (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1048576, priceIn: 2, priceOut: 12 },
|
|
37
|
+
{ id: 'google/gemini-3.8-flash', name: 'Gemini 3.8 Flash (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.82, priceOut: 4.12 },
|
|
38
|
+
{ id: 'google/gemini-3.5-flash', name: 'Gemini 3.5 Flash (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1048576, priceIn: 1.5, priceOut: 9 },
|
|
39
|
+
|
|
40
|
+
// ── DeepSeek ──
|
|
41
|
+
{ id: 'deepseek/deepseek-v4.1-flash', name: 'DeepSeek V4.1 Flash (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.04, priceOut: 0.64 },
|
|
42
|
+
{ id: 'deepseek/deepseek-v4-pro', name: 'DeepSeek V4 Pro (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1048576, priceIn: 0.3, priceOut: 0.59 },
|
|
43
|
+
|
|
44
|
+
// ── Moonshot / Z.ai / Qwen / MiniMax ──
|
|
45
|
+
{ id: 'moonshotai/kimi-k3', name: 'Kimi K3 (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 1048576, priceIn: 0.3, priceOut: 11.94 },
|
|
46
|
+
{ id: 'moonshotai/kimi-k2.6', name: 'Kimi K2.6 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 262144, priceIn: 0.65, priceOut: 3.41 },
|
|
47
|
+
{ id: 'z-ai/glm-5.3', name: 'GLM-5.3 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1048576, priceIn: 0.08, priceOut: 4.8 },
|
|
48
|
+
{ id: 'z-ai/glm-5.3-flash', name: 'GLM-5.3 Flash (via OpenRouter)', provider: 'openrouter', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.03, priceOut: 0.58 },
|
|
49
|
+
{ id: 'qwen/qwen3.5-397b-a17b', name: 'Qwen3.5 397B A17B (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 262144, priceIn: 0.5, priceOut: 3.6 },
|
|
50
|
+
{ id: 'qwen/qwen3-coder', name: 'Qwen3 Coder 480B (via OpenRouter)', provider: 'openrouter', tags: ['coding'], context: 262144, priceIn: 0.3, priceOut: 1 },
|
|
51
|
+
{ id: 'qwen/qwen3-coder-flash', name: 'Qwen3 Coder Flash (via OpenRouter)', provider: 'openrouter', tags: ['coding', 'fast'], context: 1000000, priceIn: 0.2, priceOut: 0.98 },
|
|
52
|
+
{ id: 'minimax/minimax-m3', name: 'MiniMax M3 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1048576, priceIn: 0.3, priceOut: 1.2 },
|
|
53
|
+
|
|
54
|
+
// ── xAI / Meta / Mistral / Cohere / Writer ──
|
|
55
|
+
{ id: 'x-ai/grok-4.7', name: 'Grok 4.7 (via OpenRouter)', provider: 'openrouter', tags: ['frontier', 'reasoning'], context: 500000, priceIn: 2, priceOut: 6 },
|
|
56
|
+
{ id: 'x-ai/grok-4.3', name: 'Grok 4.3 (via OpenRouter)', provider: 'openrouter', tags: ['reasoning'], context: 1000000, priceIn: 1.25, priceOut: 2.5 },
|
|
57
|
+
{ id: 'meta-llama/llama-4-maverick', name: 'Llama 4 Maverick (via OpenRouter)', provider: 'openrouter', tags: [], context: 1048576, priceIn: 0.19, priceOut: 0.65 },
|
|
58
|
+
{ id: 'meta-llama/llama-4-scout', name: 'Llama 4 Scout (via OpenRouter)', provider: 'openrouter', tags: ['fast'], context: 1310720, priceIn: 0.1, priceOut: 0.3 },
|
|
59
|
+
{ id: 'mistralai/mistral-large-4-0', name: 'Mistral Large 4 (via OpenRouter)', provider: 'openrouter', tags: ['frontier'], context: 1048576, priceIn: 0.68, priceOut: 2.09 },
|
|
60
|
+
{ id: 'cohere/command-a', name: 'Command A (via OpenRouter)', provider: 'openrouter', tags: [], context: 256000, priceIn: 2.5, priceOut: 10 },
|
|
61
|
+
{ id: 'writer/palmyra-x5', name: 'Palmyra X5 (via OpenRouter)', provider: 'openrouter', tags: [], context: 1040000, priceIn: 0.6, priceOut: 6 },
|
|
62
|
+
|
|
63
|
+
// ── Free tiers (genuinely free slugs) ──
|
|
64
|
+
{ id: 'nvidia/nemotron-3-super-120b-a12b:free', name: 'Nemotron 3 Super (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'reasoning'], context: 262144, priceIn: 0, priceOut: 0 },
|
|
65
|
+
{ id: 'nvidia/nemotron-3-ultra-550b-a55b:free', name: 'Nemotron 3 Ultra (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'reasoning'], context: 1000000, priceIn: 0, priceOut: 0 },
|
|
66
|
+
{ id: 'nvidia/nemotron-3.5-lightning:free', name: 'Nemotron 3.5 Lightning (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'fast', 'reasoning'], context: 1000000, priceIn: 0, priceOut: 0 },
|
|
67
|
+
{ id: 'nvidia/nemotron-3.5-super-vl:free', name: 'Nemotron 3.5 Super VL (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'vision', 'reasoning'], context: 1000000, priceIn: 0, priceOut: 0 },
|
|
68
|
+
{ id: 'google/gemma-4-31b-it:free', name: 'Gemma 4 31B (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'reasoning'], context: 262144, priceIn: 0, priceOut: 0 },
|
|
69
|
+
{ id: 'google/gemma-4-26b-a4b-it:free', name: 'Gemma 4 26B A4B (free, via OpenRouter)', provider: 'openrouter', tags: ['free', 'fast', 'reasoning'], context: 262144, priceIn: 0, priceOut: 0 },
|
|
70
|
+
],
|
|
41
71
|
};
|
|
42
72
|
|
|
43
73
|
module.exports = provider;
|