loom-agent 1.3.3 → 1.6.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 +236 -1
- package/README.md +9 -7
- package/package.json +2 -2
- package/src/config/settings.js +10 -5
- 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 +272 -37
- 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 +127 -25
- package/src/providers/google.js +19 -11
- package/src/providers/nvidia.js +54 -33
- package/src/providers/openai-compat.js +59 -27
- package/src/providers/openai.js +45 -18
- package/src/providers/openrouter.js +56 -26
- package/src/providers/tokenrouter.js +4 -1
- 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/components/SubagentPanel.tsx +1 -1
- package/src/tui/mcp-presets.ts +4 -65
- package/src/tui/store.ts +6 -1
package/src/core/update.js
CHANGED
|
@@ -1,6 +1,116 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// Startup update check — a quiet, non-blocking "is there a newer version of
|
|
2
|
+
// loom-agent on npm?" probe that runs once per day and prints at most one line
|
|
3
|
+
// to stderr before the TUI/REPL takes over the terminal.
|
|
4
|
+
//
|
|
5
|
+
// Design constraints:
|
|
6
|
+
// - Non-blocking: runs concurrently with `main()`, never gates startup, and
|
|
7
|
+
// any failure (offline, registry down, malformed body) is swallowed — this
|
|
8
|
+
// must never break the app or add latency to first render.
|
|
9
|
+
// - Throttled: one network probe per 24h, tracked by a stamp file so it
|
|
10
|
+
// survives across runs.
|
|
11
|
+
// - Silent when up-to-date; silent when disabled via LOOM_NO_UPDATE_CHECK.
|
|
12
|
+
// Only prints when a strictly newer version is actually available.
|
|
13
|
+
// - Compare is a plain semver-ish tuple compare (major.minor.patch), not a
|
|
14
|
+
// library — enough for the "newer than installed?" question without a dep.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
|
|
20
|
+
const PKG = require('../../package.json');
|
|
21
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24h between probes
|
|
22
|
+
const FETCH_TIMEOUT_MS = 4000; // fail fast — this is best-effort only
|
|
23
|
+
|
|
24
|
+
function stampFile() {
|
|
25
|
+
const dir = process.env.LOOM_CONFIG_DIR || path.join(os.homedir(), '.loom');
|
|
26
|
+
return path.join(dir, 'update-check.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Extract a comparable version tuple. Returns null for anything unparseable.
|
|
30
|
+
function parseVersion(v) {
|
|
31
|
+
if (typeof v !== 'string') return null;
|
|
32
|
+
const m = v.trim().match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
33
|
+
if (!m) return null;
|
|
34
|
+
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// True when `latest` is strictly newer than `current`. Pre-release / build
|
|
38
|
+
// suffixes are ignored (treated as the base triple) — good enough here.
|
|
39
|
+
function isNewer(latest, current) {
|
|
40
|
+
const a = parseVersion(latest);
|
|
41
|
+
const b = parseVersion(current);
|
|
42
|
+
if (!a || !b) return false;
|
|
43
|
+
for (let i = 0; i < 3; i++) {
|
|
44
|
+
if (a[i] > b[i]) return true;
|
|
45
|
+
if (a[i] < b[i]) return false;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Read the last-check timestamp; returns 0 if absent/corrupt (so the very
|
|
51
|
+
// first run after install always checks).
|
|
52
|
+
function lastCheckAt() {
|
|
53
|
+
try {
|
|
54
|
+
const raw = fs.readFileSync(stampFile(), 'utf8');
|
|
55
|
+
const n = Number(JSON.parse(raw).at);
|
|
56
|
+
return Number.isFinite(n) ? n : 0;
|
|
57
|
+
} catch {
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function markChecked() {
|
|
63
|
+
try {
|
|
64
|
+
const file = stampFile();
|
|
65
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
66
|
+
fs.writeFileSync(file, JSON.stringify({ at: Date.now(), checked: PKG.version }));
|
|
67
|
+
} catch {
|
|
68
|
+
// Throttle stamp is best-effort — a failure just means we probe again
|
|
69
|
+
// next run, never breaks startup.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Probe npm for the latest `loom-agent` version and, if it's newer than the
|
|
75
|
+
* installed one, print a one-line upgrade hint to stderr. Throttled to one
|
|
76
|
+
* probe per 24h. Never throws, never blocks, and returns the newer version
|
|
77
|
+
* string (or null) so tests can assert the decision without inspecting
|
|
78
|
+
* stderr.
|
|
79
|
+
*
|
|
80
|
+
* @returns {Promise<string|null>} latest version when an upgrade exists, else null
|
|
81
|
+
*/
|
|
82
|
+
async function updateCheck() {
|
|
83
|
+
if (process.env.LOOM_NO_UPDATE_CHECK) return null;
|
|
84
|
+
|
|
85
|
+
const now = Date.now();
|
|
86
|
+
if (now - lastCheckAt() < CHECK_INTERVAL_MS) return null;
|
|
87
|
+
|
|
88
|
+
// Claim the slot BEFORE the fetch: even if the network call fails we don't
|
|
89
|
+
// want to retry on every startup when offline.
|
|
90
|
+
markChecked();
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const ctrl = new AbortController();
|
|
94
|
+
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
95
|
+
let res;
|
|
96
|
+
try {
|
|
97
|
+
res = await fetch('https://registry.npmjs.org/loom-agent/latest', { signal: ctrl.signal });
|
|
98
|
+
} finally {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
}
|
|
101
|
+
if (!res || !res.ok) return null;
|
|
102
|
+
const body = /** @type {{version?: unknown}} */ (await res.json());
|
|
103
|
+
const latest = typeof body?.version === 'string' ? body.version : null;
|
|
104
|
+
if (!isNewer(latest, PKG.version)) return null;
|
|
105
|
+
|
|
106
|
+
process.stderr.write(
|
|
107
|
+
`\n[loom] New version available: ${PKG.version} → ${latest}\n` +
|
|
108
|
+
`[loom] Upgrade with: npm install -g ${PKG.name}@latest\n\n`
|
|
109
|
+
);
|
|
110
|
+
return latest;
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = { updateCheck, isNewer, parseVersion };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Hosting / cloud-service connector presets — platforms you "connect" your
|
|
2
|
+
// project to rather than dev-tool servers. Surfaced under /connectors (and
|
|
3
|
+
// `loom add connector`), not /mcp. Lives in the core layer so the CLI
|
|
4
|
+
// (`loom add connector <preset> -e KEY=V`) and the TUI picker share one
|
|
5
|
+
// catalog; the TUI re-exports this list from src/tui/mcp-presets.ts.
|
|
6
|
+
//
|
|
7
|
+
// Each preset: id, label, package (npx-run) or command (full override, e.g.
|
|
8
|
+
// docker / npx mcp-remote), description, args (may reference $KEY env
|
|
9
|
+
// placeholders resolved at add time), env defaults, prompts (guided key
|
|
10
|
+
// entry + the required-key set for CLI expansion), and an optional
|
|
11
|
+
// optionalArgsPrompt (non-secret trailing arg, e.g. --project-ref).
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} ConnectorPrompt
|
|
15
|
+
* @property {string} key
|
|
16
|
+
* @property {string} label
|
|
17
|
+
* @property {boolean} [mask]
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} OptionalArgsPrompt
|
|
22
|
+
* @property {string|null} flag
|
|
23
|
+
* @property {string} label
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} ConnectorPreset
|
|
28
|
+
* @property {string} id
|
|
29
|
+
* @property {string} label
|
|
30
|
+
* @property {string} [package]
|
|
31
|
+
* @property {string} [command]
|
|
32
|
+
* @property {string} description
|
|
33
|
+
* @property {string[]} args
|
|
34
|
+
* @property {Record<string, string>} env
|
|
35
|
+
* @property {ConnectorPrompt[]} prompts
|
|
36
|
+
* @property {OptionalArgsPrompt} [optionalArgsPrompt]
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/** @type {ConnectorPreset[]} */
|
|
40
|
+
const CONNECTOR_PRESETS = [
|
|
41
|
+
{
|
|
42
|
+
id: 'supabase',
|
|
43
|
+
label: 'Supabase',
|
|
44
|
+
package: '@supabase/mcp-server-supabase',
|
|
45
|
+
description: 'Query schema, run SQL, manage Supabase projects',
|
|
46
|
+
args: ['--access-token', '$SUPABASE_ACCESS_TOKEN'],
|
|
47
|
+
env: { SUPABASE_ACCESS_TOKEN: '' },
|
|
48
|
+
prompts: [
|
|
49
|
+
{ key: 'SUPABASE_ACCESS_TOKEN', label: 'Personal access token (supabase.com/dashboard/account/tokens)', mask: true },
|
|
50
|
+
],
|
|
51
|
+
optionalArgsPrompt: { flag: '--project-ref', label: 'Project ref (optional, e.g. abcdefghijklmnop) — Enter to skip' },
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'nextjs',
|
|
55
|
+
label: 'Next.js',
|
|
56
|
+
package: 'nextjs-mcp-server',
|
|
57
|
+
description: 'Next.js project introspection (routes, pages, config)',
|
|
58
|
+
args: [],
|
|
59
|
+
env: {},
|
|
60
|
+
prompts: [],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'railway',
|
|
64
|
+
label: 'Railway',
|
|
65
|
+
package: '@railway/mcp-server',
|
|
66
|
+
description: 'Railway deploys, services, variables',
|
|
67
|
+
args: [],
|
|
68
|
+
env: { RAILWAY_API_TOKEN: '' },
|
|
69
|
+
prompts: [
|
|
70
|
+
{ key: 'RAILWAY_API_TOKEN', label: 'API token (railway.app/account/tokens)', mask: true },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'vercel',
|
|
75
|
+
label: 'Vercel',
|
|
76
|
+
command: 'npx',
|
|
77
|
+
args: ['-y', 'mcp-remote', 'https://mcp.vercel.com'],
|
|
78
|
+
description: 'Vercel deployments and projects (remote MCP endpoint, OAuth)',
|
|
79
|
+
env: {},
|
|
80
|
+
prompts: [],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'netlify',
|
|
84
|
+
label: 'Netlify',
|
|
85
|
+
command: 'npx',
|
|
86
|
+
args: ['-y', 'mcp-remote', 'https://api.netlify.com/mcp'],
|
|
87
|
+
description: 'Netlify sites, deploys, and environment vars (remote MCP endpoint, OAuth)',
|
|
88
|
+
env: {},
|
|
89
|
+
prompts: [],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'cloudflare',
|
|
93
|
+
label: 'Cloudflare',
|
|
94
|
+
package: '@cloudflare/mcp-server-cloudflare',
|
|
95
|
+
description: 'Workers, DNS, and account management',
|
|
96
|
+
args: [],
|
|
97
|
+
env: { CLOUDFLARE_API_TOKEN: '', CLOUDFLARE_ACCOUNT_ID: '' },
|
|
98
|
+
prompts: [
|
|
99
|
+
{ key: 'CLOUDFLARE_API_TOKEN', label: 'API token (dash.cloudflare.com/profile/api-tokens)', mask: true },
|
|
100
|
+
{ key: 'CLOUDFLARE_ACCOUNT_ID', label: 'Account ID (dash.cloudflare.com — right sidebar)', mask: false },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
module.exports = { CONNECTOR_PRESETS };
|
|
@@ -54,9 +54,17 @@ function buildBody(messages, options) {
|
|
|
54
54
|
// resumed/hand-edited sessions rather than failing the whole turn.
|
|
55
55
|
const tcid = m.toolCallId || m.tool_call_id;
|
|
56
56
|
if (tcid) {
|
|
57
|
+
// is_error marks a failed tool call so the model treats the string
|
|
58
|
+
// content as an error report, not a successful result (parity with
|
|
59
|
+
// the OpenAI-compat is_error/tool-result semantics).
|
|
57
60
|
out.push({
|
|
58
61
|
role: 'user',
|
|
59
|
-
content: [{
|
|
62
|
+
content: [{
|
|
63
|
+
type: 'tool_result',
|
|
64
|
+
tool_use_id: tcid,
|
|
65
|
+
content: String(m.content),
|
|
66
|
+
...(m.isError ? { is_error: true } : {}),
|
|
67
|
+
}],
|
|
60
68
|
});
|
|
61
69
|
}
|
|
62
70
|
continue;
|
|
@@ -156,29 +164,69 @@ function normalizeBlocks(contentBlocks) {
|
|
|
156
164
|
return { content: textParts.join(''), toolCalls };
|
|
157
165
|
}
|
|
158
166
|
|
|
167
|
+
// Retry-After header (seconds) or rate-limit reset timestamps → wait ms.
|
|
168
|
+
function retryAfterMs(resp) {
|
|
169
|
+
const ra = resp && resp.headers && resp.headers.get('retry-after');
|
|
170
|
+
if (ra) {
|
|
171
|
+
const secs = Number(ra);
|
|
172
|
+
if (Number.isFinite(secs) && secs >= 0) return Math.min(secs * 1000, 60000);
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Retryable: rate limits (429) and transient server errors (5xx/529).
|
|
178
|
+
function isRetryableStatus(status) {
|
|
179
|
+
return status === 429 || status === 529 || (status >= 500 && status < 600);
|
|
180
|
+
}
|
|
181
|
+
|
|
159
182
|
async function post(body, options) {
|
|
160
183
|
const key = getKey();
|
|
161
184
|
if (!key) throw new Error("Anthropic API key not set. Use /connect anthropic or set ANTHROPIC_API_KEY.");
|
|
162
185
|
const apiUrl = getApiUrl();
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
'
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (resp.status
|
|
178
|
-
|
|
179
|
-
|
|
186
|
+
const maxTries = 4;
|
|
187
|
+
let resp = null;
|
|
188
|
+
for (let attempt = 0; attempt < maxTries; attempt++) {
|
|
189
|
+
resp = await fetch(apiUrl, {
|
|
190
|
+
method: 'POST',
|
|
191
|
+
headers: {
|
|
192
|
+
'Content-Type': 'application/json',
|
|
193
|
+
'x-api-key': key,
|
|
194
|
+
'anthropic-version': '2023-06-01',
|
|
195
|
+
},
|
|
196
|
+
body: JSON.stringify(body),
|
|
197
|
+
signal: options.signal,
|
|
198
|
+
});
|
|
199
|
+
if (resp.ok) return resp;
|
|
200
|
+
if (!isRetryableStatus(resp.status) || attempt === maxTries - 1) break;
|
|
201
|
+
// Honor the provider's Retry-After (seconds); else exponential backoff
|
|
202
|
+
// with jitter so parallel retries don't stampede.
|
|
203
|
+
const waitMs = retryAfterMs(resp) ?? Math.min(1000 * Math.pow(2, attempt), 30000);
|
|
204
|
+
const jitter = Math.floor(Math.random() * 250);
|
|
205
|
+
await new Promise((r) => setTimeout(r, waitMs + jitter));
|
|
206
|
+
if (options.signal && options.signal.aborted) {
|
|
207
|
+
const abortErr = new Error('Request aborted');
|
|
208
|
+
abortErr.name = 'AbortError';
|
|
209
|
+
throw abortErr;
|
|
210
|
+
}
|
|
180
211
|
}
|
|
181
|
-
|
|
212
|
+
if (!resp) throw new Error('Anthropic API error: no response');
|
|
213
|
+
/** @type {any} */
|
|
214
|
+
const err = await resp.json().catch(() => ({}));
|
|
215
|
+
const detail = err.error?.message || resp.statusText;
|
|
216
|
+
if (resp.status === 401) throw new Error("Anthropic 401 Unauthorized: the API key is invalid or expired. Run /connect anthropic and paste a new key.");
|
|
217
|
+
if (resp.status === 403) throw new Error("Anthropic 403 Forbidden: the API key is not authorized for this model. Check the model name and your account access.");
|
|
218
|
+
const e = new Error(`Anthropic API error ${resp.status}: ${detail}`);
|
|
219
|
+
/** @type {any} */ (e).status = resp.status;
|
|
220
|
+
/** @type {any} */ (e).retryAfterMs = retryAfterMs(resp);
|
|
221
|
+
throw e;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Anthropic stop_reason → the finishReason vocabulary the session loop knows
|
|
225
|
+
// ('length' drives truncation auto-continue; 'tool_use'/'end_turn' are no-ops).
|
|
226
|
+
function mapStopReason(stopReason) {
|
|
227
|
+
if (stopReason === 'max_tokens') return 'length';
|
|
228
|
+
if (stopReason === 'tool_use') return 'tool_calls';
|
|
229
|
+
return stopReason || undefined;
|
|
182
230
|
}
|
|
183
231
|
|
|
184
232
|
async function chat(messages, options = {}) {
|
|
@@ -186,7 +234,11 @@ async function chat(messages, options = {}) {
|
|
|
186
234
|
const resp = await post(body, options);
|
|
187
235
|
/** @type {any} */
|
|
188
236
|
const data = await resp.json();
|
|
189
|
-
return {
|
|
237
|
+
return {
|
|
238
|
+
...normalizeBlocks(data.content || []),
|
|
239
|
+
usage: data.usage,
|
|
240
|
+
finishReason: mapStopReason(data.stop_reason),
|
|
241
|
+
};
|
|
190
242
|
}
|
|
191
243
|
|
|
192
244
|
async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
@@ -198,6 +250,8 @@ async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
|
198
250
|
let content = '';
|
|
199
251
|
let reasoning = '';
|
|
200
252
|
let usage = null;
|
|
253
|
+
let finishReason;
|
|
254
|
+
let sawEnd = false;
|
|
201
255
|
const toolAcc = new Map();
|
|
202
256
|
|
|
203
257
|
for await (const chunk of resp.body) {
|
|
@@ -210,7 +264,25 @@ async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
|
210
264
|
if (raw === '[DONE]') continue;
|
|
211
265
|
let evt;
|
|
212
266
|
try { evt = JSON.parse(raw); } catch { continue; }
|
|
213
|
-
|
|
267
|
+
// Mid-stream error events (content filter, overloaded after start)
|
|
268
|
+
// previously vanished — the turn dead-ended with empty content. Throw
|
|
269
|
+
// so the session retry/error path handles it.
|
|
270
|
+
if (evt.type === 'error') {
|
|
271
|
+
const emsg = evt.error?.message || 'unknown stream error';
|
|
272
|
+
const e = new Error(`Anthropic stream error: ${emsg}`);
|
|
273
|
+
/** @type {any} */ (e).status = evt.error?.type === 'overloaded_error' ? 529 : undefined;
|
|
274
|
+
throw e;
|
|
275
|
+
}
|
|
276
|
+
if (evt.type === 'message_start' && evt.message?.usage) {
|
|
277
|
+
// message_start carries input_tokens (prompt) — without it, a turn
|
|
278
|
+
// that ends in message_delta only undercounts input to zero.
|
|
279
|
+
usage = { ...evt.message.usage };
|
|
280
|
+
}
|
|
281
|
+
if (evt.type === 'message_delta') {
|
|
282
|
+
if (evt.usage) usage = { ...(usage || {}), ...evt.usage };
|
|
283
|
+
if (evt.delta && evt.delta.stop_reason) finishReason = mapStopReason(evt.delta.stop_reason);
|
|
284
|
+
sawEnd = true;
|
|
285
|
+
}
|
|
214
286
|
if (evt.type === 'content_block_start' && evt.content_block?.type === 'tool_use') {
|
|
215
287
|
toolAcc.set(evt.index, { id: evt.content_block.id, name: evt.content_block.name, input: '' });
|
|
216
288
|
} else if (evt.type === 'content_block_delta') {
|
|
@@ -229,6 +301,14 @@ async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
|
229
301
|
}
|
|
230
302
|
}
|
|
231
303
|
|
|
304
|
+
// A stream that never delivered message_delta AND produced nothing was
|
|
305
|
+
// truncated (network reset mid-body). Surface it as an error instead of a
|
|
306
|
+
// silent empty reply. Partial content with no trailing message_delta is
|
|
307
|
+
// kept (the session can continue from it).
|
|
308
|
+
if (!sawEnd && !usage && !content && !toolAcc.size) {
|
|
309
|
+
throw new Error('Anthropic stream truncated: connection ended before message_delta');
|
|
310
|
+
}
|
|
311
|
+
|
|
232
312
|
const toolCalls = [];
|
|
233
313
|
for (const acc of toolAcc.values()) {
|
|
234
314
|
let input = {};
|
|
@@ -236,13 +316,35 @@ async function stream(messages, options = {}, onDelta, onReasoning) {
|
|
|
236
316
|
toolCalls.push({ id: acc.id, name: acc.name, input });
|
|
237
317
|
}
|
|
238
318
|
|
|
239
|
-
return { content, reasoning, toolCalls, usage };
|
|
319
|
+
return { content, reasoning, toolCalls, usage, finishReason };
|
|
240
320
|
}
|
|
241
321
|
|
|
322
|
+
// Current Anthropic lineup, verified against the models.dev registry
|
|
323
|
+
// (2026-10-17). Dated snapshots kept for back-compat with saved configs.
|
|
242
324
|
const models = [
|
|
243
|
-
|
|
244
|
-
{ id: 'claude-opus-
|
|
245
|
-
{ id: 'claude-
|
|
325
|
+
// ── Opus ──
|
|
326
|
+
{ id: 'claude-opus-5-5', name: 'Claude Opus 5.5', provider: 'anthropic', context: 1000000, priceIn: 4, priceOut: 20, tags: ['frontier', 'reasoning'] },
|
|
327
|
+
{ id: 'claude-opus-5', name: 'Claude Opus 5', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
|
|
328
|
+
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
|
|
329
|
+
{ id: 'claude-opus-4-5', name: 'Claude Opus 4.5', provider: 'anthropic', context: 200000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
|
|
330
|
+
{ id: 'claude-fable-5-1', name: 'Claude Fable 5.1', provider: 'anthropic', context: 1000000, priceIn: 10, priceOut: 50, tags: ['frontier', 'reasoning'] },
|
|
331
|
+
{ id: 'claude-fable-5', name: 'Claude Fable 5', provider: 'anthropic', context: 1000000, priceIn: 10, priceOut: 50, tags: ['frontier', 'reasoning'] },
|
|
332
|
+
{ id: 'claude-opus-4-7', name: 'Claude Opus 4.7', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
|
|
333
|
+
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6', provider: 'anthropic', context: 1000000, priceIn: 5, priceOut: 25, tags: ['frontier', 'reasoning'] },
|
|
334
|
+
// ── Sonnet ──
|
|
335
|
+
{ id: 'claude-sonnet-5-5', name: 'Claude Sonnet 5.5', provider: 'anthropic', context: 1000000, priceIn: 2, priceOut: 10, tags: ['reasoning'] },
|
|
336
|
+
{ id: 'claude-sonnet-5', name: 'Claude Sonnet 5', provider: 'anthropic', context: 1000000, priceIn: 2, priceOut: 10, tags: ['reasoning'] },
|
|
337
|
+
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', provider: 'anthropic', context: 1000000, priceIn: 3, priceOut: 15, tags: ['reasoning'] },
|
|
338
|
+
{ id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5', provider: 'anthropic', context: 200000, priceIn: 3, priceOut: 15, tags: ['reasoning'] },
|
|
339
|
+
// ── Haiku ──
|
|
340
|
+
{ id: 'claude-haiku-5-5', name: 'Claude Haiku 5.5', provider: 'anthropic', context: 1000000, priceIn: 0.1, priceOut: 0.5, tags: ['fast', 'cheap', 'reasoning'] },
|
|
341
|
+
{ id: 'claude-haiku-4-5', name: 'Claude Haiku 4.5', provider: 'anthropic', context: 200000, priceIn: 1, priceOut: 5, tags: ['fast', 'reasoning'] },
|
|
342
|
+
// ── Legacy snapshots ──
|
|
343
|
+
// Retired models verified against Anthropic's model-deprecations page
|
|
344
|
+
// (2026-10-17): claude-sonnet-4-20250514 and claude-opus-4-20250514 were
|
|
345
|
+
// retired 2026-06-15, claude-3-5-haiku-20241022 retired 2026-02-19 — they
|
|
346
|
+
// 404 and are no longer listed. claude-mythos-5/5.1 exist but are limited
|
|
347
|
+
// to verified organizations, so they are not offered in the picker.
|
|
246
348
|
];
|
|
247
349
|
|
|
248
350
|
module.exports = { chat, stream, models, buildBody, normalizeBlocks };
|
package/src/providers/google.js
CHANGED
|
@@ -12,17 +12,25 @@ const provider = {
|
|
|
12
12
|
envKeyHint: 'GOOGLE',
|
|
13
13
|
}),
|
|
14
14
|
models: [
|
|
15
|
-
// ──
|
|
16
|
-
{ id: 'gemini-
|
|
17
|
-
{ id: 'gemini-
|
|
18
|
-
|
|
19
|
-
{ id: 'gemini-
|
|
20
|
-
{ id: 'gemini-
|
|
21
|
-
|
|
22
|
-
{ id: 'gemini-
|
|
23
|
-
{ id: 'gemini-1
|
|
24
|
-
// ──
|
|
25
|
-
{ id: '
|
|
15
|
+
// ── Gemini 4 / 3.x (current) ──
|
|
16
|
+
{ id: 'gemini-4-argon', name: 'Gemini 4 Argon', provider: 'google', tags: ['frontier', 'reasoning'], context: 1048576, priceIn: 2, priceOut: 10 },
|
|
17
|
+
{ id: 'gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro Preview', provider: 'google', tags: ['frontier', 'reasoning'], context: 1048576, priceIn: 2, priceOut: 12 },
|
|
18
|
+
{ id: 'gemini-3.8-flash', name: 'Gemini 3.8 Flash', provider: 'google', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.75, priceOut: 3.75 },
|
|
19
|
+
{ id: 'gemini-3.7-flash', name: 'Gemini 3.7 Flash', provider: 'google', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.75, priceOut: 3.75 },
|
|
20
|
+
{ id: 'gemini-3.6-flash', name: 'Gemini 3.6 Flash', provider: 'google', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.75, priceOut: 3.75 },
|
|
21
|
+
{ id: 'gemini-3.5-flash', name: 'Gemini 3.5 Flash', provider: 'google', tags: ['reasoning'], context: 1048576, priceIn: 1.5, priceOut: 9 },
|
|
22
|
+
{ id: 'gemini-3.5-flash-lite', name: 'Gemini 3.5 Flash Lite', provider: 'google', tags: ['fast', 'cheap', 'reasoning'], context: 1048576, priceIn: 0.3, priceOut: 2.5 },
|
|
23
|
+
{ id: 'gemini-3.1-flash-lite', name: 'Gemini 3.1 Flash Lite', provider: 'google', tags: ['fast', 'cheap', 'reasoning'], context: 1048576, priceIn: 0.25, priceOut: 1.5 },
|
|
24
|
+
// ── Aliases ──
|
|
25
|
+
{ id: 'gemini-flash-latest', name: 'Gemini Flash (Latest)', provider: 'google', tags: ['fast', 'reasoning'], context: 1048576, priceIn: 0.75, priceOut: 3.75 },
|
|
26
|
+
{ id: 'gemini-flash-lite-latest', name: 'Gemini Flash-Lite (Latest)', provider: 'google', tags: ['fast', 'cheap', 'reasoning'], context: 1048576, priceIn: 0.3, priceOut: 2.5 },
|
|
27
|
+
// ── Gemini 2.5 (stable) ──
|
|
28
|
+
{ id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro', provider: 'google', tags: ['frontier'], context: 1048576, priceIn: 1.25, priceOut: 10 },
|
|
29
|
+
{ id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash', provider: 'google', tags: ['fast'], context: 1048576, priceIn: 0.3, priceOut: 2.5 },
|
|
30
|
+
{ id: 'gemini-2.5-flash-lite', name: 'Gemini 2.5 Flash-Lite', provider: 'google', tags: ['fast', 'cheap'], context: 1048576, priceIn: 0.1, priceOut: 0.4 },
|
|
31
|
+
// ── Gemma (open weights) ──
|
|
32
|
+
{ id: 'gemma-4-31b-it', name: 'Gemma 4 31B IT', provider: 'google', tags: ['reasoning'], context: 262144, priceIn: 0.2, priceOut: 0.8 },
|
|
33
|
+
{ id: 'gemma-4-26b-a4b-it', name: 'Gemma 4 26B A4B IT', provider: 'google', tags: ['fast', 'reasoning'], context: 262144, priceIn: 0.2, priceOut: 0.8 },
|
|
26
34
|
],
|
|
27
35
|
};
|
|
28
36
|
|
package/src/providers/nvidia.js
CHANGED
|
@@ -5,10 +5,23 @@ function getKey() {
|
|
|
5
5
|
return getApiKey('nvidia') || process.env.NVIDIA_API_KEY || process.env.NVIDIA_NIM_API_KEY;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
// Model IDs below are a curated subset of NVIDIA's live GET /v1/models
|
|
9
|
-
// (fetched
|
|
10
|
-
//
|
|
11
|
-
//
|
|
8
|
+
// Model IDs below are a curated subset of NVIDIA's live GET /v1/models
|
|
9
|
+
// registry (fetched + cross-checked against models.dev 2026-10-17, 81 live
|
|
10
|
+
// models; only chat/completions-capable IDs kept — embeddings, rerankers,
|
|
11
|
+
// safety/guard, document-parse, video/vision-specialist and reward models
|
|
12
|
+
// are excluded). Stale IDs — e.g. meta/llama-3.1-8b-instruct,
|
|
13
|
+
// deepseek-ai/deepseek-v4-flash-0731, z-ai/glm-5.2, openai/gpt-oss-120b —
|
|
14
|
+
// return 404/410 and were removed. Re-verify against /v1/models before
|
|
15
|
+
// adding any ID.
|
|
16
|
+
//
|
|
17
|
+
// NOTE (probed 2026-10-17): GET /v1/models is the GLOBAL catalog — a chat
|
|
18
|
+
// POST can still fail with `Function '<id>': Not found for account '<key>'`,
|
|
19
|
+
// i.e. the model exists but the key's account hasn't enabled it. On one
|
|
20
|
+
// sample key only 9/54 of these IDs answered a chat call (37 account-gated
|
|
21
|
+
// 404s, ~6 hang to timeout, 2 return 503 capacity errors), so the picker
|
|
22
|
+
// may offer models that 404 for a given account. Availability is
|
|
23
|
+
// per-account, so the full curated list stays; NVIDIA's own errors carry
|
|
24
|
+
// the account hint.
|
|
12
25
|
const provider = {
|
|
13
26
|
...createOpenAICompatProvider({
|
|
14
27
|
getKey,
|
|
@@ -17,38 +30,34 @@ const provider = {
|
|
|
17
30
|
}),
|
|
18
31
|
models: [
|
|
19
32
|
// ── DeepSeek ──
|
|
20
|
-
{ id: 'deepseek-ai/deepseek-v4-flash
|
|
33
|
+
{ id: 'deepseek-ai/deepseek-v4.1-flash', name: 'DeepSeek V4.1 Flash', provider: 'nvidia', tags: ['reasoning', 'fast'], context: 1000000, priceIn: 0.14, priceOut: 0.28 },
|
|
21
34
|
{ id: 'deepseek-ai/deepseek-coder-6.7b-instruct', name: 'DeepSeek Coder 6.7B', provider: 'nvidia', tags: ['coding'], context: 16384, priceIn: 0.10, priceOut: 0.10 },
|
|
22
35
|
|
|
23
36
|
// ── Meta Llama ──
|
|
24
|
-
{ id: 'meta/llama-3.1-8b-instruct', name: 'Llama 3.1 8B Instruct', provider: 'nvidia', tags: ['fast'], context: 128000, priceIn: 0.05, priceOut: 0.08 },
|
|
25
|
-
{ id: 'meta/llama-3.1-70b-instruct', name: 'Llama 3.1 70B Instruct', provider: 'nvidia', tags: ['general'], context: 128000, priceIn: 0.35, priceOut: 0.40 },
|
|
26
|
-
{ id: 'meta/llama-3.2-3b-instruct', name: 'Llama 3.2 3B Instruct', provider: 'nvidia', tags: ['fast'], context: 128000, priceIn: 0.02, priceOut: 0.02 },
|
|
27
37
|
{ id: 'meta/llama-3.2-11b-vision-instruct', name: 'Llama 3.2 11B Vision', provider: 'nvidia', tags: ['vision', 'fast'], context: 128000, priceIn: 0.055, priceOut: 0.055 },
|
|
28
38
|
{ id: 'meta/llama-3.2-90b-vision-instruct', name: 'Llama 3.2 90B Vision', provider: 'nvidia', tags: ['vision'], context: 128000, priceIn: 0.35, priceOut: 0.40 },
|
|
29
|
-
{ id: 'meta/
|
|
39
|
+
{ id: 'meta/muse-glimmer-30b', name: 'Llama Muse Glimmer 30B', provider: 'nvidia', tags: ['creative', 'reasoning'], context: 131072, priceIn: 0.20, priceOut: 0.20 },
|
|
30
40
|
{ id: 'meta/codellama-70b', name: 'CodeLlama 70B', provider: 'nvidia', tags: ['coding'], context: 16384, priceIn: 0.30, priceOut: 0.30 },
|
|
31
|
-
{ id: 'meta/
|
|
41
|
+
{ id: 'meta/llama2-70b', name: 'Llama 2 70B', provider: 'nvidia', tags: ['legacy'], context: 4096, priceIn: 0.20, priceOut: 0.20 },
|
|
32
42
|
|
|
33
43
|
// ── NVIDIA Nemotron ──
|
|
34
|
-
{ id: 'nvidia/
|
|
35
|
-
{ id: 'nvidia/
|
|
36
|
-
{ id: 'nvidia/
|
|
37
|
-
{ id: 'nvidia/llama-3.3-nemotron-super-49b-v1.5', name: 'Nemotron Super 49B v1.5', provider: 'nvidia', tags: ['reasoning'], context: 128000, priceIn: 0.25, priceOut: 0.90 },
|
|
38
|
-
{ id: 'nvidia/nemotron-3-ultra-550b-a55b', name: 'Nemotron 3 Ultra 550B', provider: 'nvidia', tags: ['frontier'], context: 256000, priceIn: 2.00, priceOut: 8.00 },
|
|
39
|
-
{ id: 'nvidia/nemotron-3-super-120b-a12b', name: 'Nemotron 3 Super 120B', provider: 'nvidia', tags: ['frontier'], context: 256000, priceIn: 1.00, priceOut: 4.00 },
|
|
40
|
-
{ id: 'nvidia/nemotron-3-nano-30b-a3b', name: 'Nemotron 3 Nano 30B', provider: 'nvidia', tags: ['fast'], context: 128000, priceIn: 0.10, priceOut: 0.40 },
|
|
41
|
-
{ id: 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning', name: 'Nemotron 3 Nano Omni (Reasoning)', provider: 'nvidia', tags: ['reasoning', 'small'], context: 128000, priceIn: 0.10, priceOut: 0.40 },
|
|
42
|
-
{ id: 'nvidia/nemotron-4-340b-instruct', name: 'Nemotron-4 340B Instruct', provider: 'nvidia', tags: ['frontier'], context: 4096, priceIn: 1.00, priceOut: 3.00 },
|
|
43
|
-
{ id: 'nvidia/nemotron-mini-4b-instruct', name: 'Nemotron Mini 4B', provider: 'nvidia', tags: ['fast'], context: 32768, priceIn: 0.03, priceOut: 0.03 },
|
|
44
|
+
{ id: 'nvidia/nemotron-3-ultra-550b-a55b', name: 'Nemotron 3 Ultra 550B', provider: 'nvidia', tags: ['frontier', 'reasoning'], context: 1000000, priceIn: 0.50, priceOut: 2.50 },
|
|
45
|
+
{ id: 'nvidia/nemotron-3-super-120b-a12b', name: 'Nemotron 3 Super 120B', provider: 'nvidia', tags: ['reasoning'], context: 262144, priceIn: 0.25, priceOut: 1.00 },
|
|
46
|
+
{ id: 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning', name: 'Nemotron 3 Nano Omni (Reasoning)', provider: 'nvidia', tags: ['reasoning', 'fast'], context: 256000, priceIn: 0.10, priceOut: 0.40 },
|
|
44
47
|
{ id: 'nvidia/nemotron-nano-3-30b-a3b', name: 'Nemotron Nano 3 30B', provider: 'nvidia', tags: ['fast'], context: 128000, priceIn: 0.10, priceOut: 0.40 },
|
|
45
|
-
{ id: 'nvidia/nemotron-
|
|
46
|
-
{ id: 'nvidia/
|
|
48
|
+
{ id: 'nvidia/nemotron-3.5-lightning-30b-a3b', name: 'Nemotron 3.5 Lightning 30B', provider: 'nvidia', tags: ['reasoning', 'fast'], context: 262144, priceIn: 0.10, priceOut: 0.40 },
|
|
49
|
+
{ id: 'nvidia/nemotron-3.5-super-vl-120b-a12b', name: 'Nemotron 3.5 Super VL 120B', provider: 'nvidia', tags: ['vision', 'reasoning'], context: 1000000, priceIn: 0.25, priceOut: 1.00 },
|
|
50
|
+
{ id: 'nvidia/llama-3.1-nemotron-ultra-253b-v1', name: 'Nemotron Ultra 253B', provider: 'nvidia', tags: ['frontier', 'reasoning'], context: 128000, priceIn: 1.50, priceOut: 6.00 },
|
|
51
|
+
{ id: 'nvidia/llama-3.1-nemotron-70b-instruct', name: 'Llama 3.1 Nemotron 70B', provider: 'nvidia', tags: ['general'], context: 128000, priceIn: 0.35, priceOut: 0.40 },
|
|
52
|
+
{ id: 'nvidia/llama-3.1-nemotron-51b-instruct', name: 'Llama 3.1 Nemotron 51B', provider: 'nvidia', tags: ['general'], context: 128000, priceIn: 0.20, priceOut: 0.80 },
|
|
53
|
+
{ id: 'nvidia/llama3-chatqa-1.5-70b', name: 'Llama3 ChatQA 1.5 70B', provider: 'nvidia', tags: ['general'], context: 8192, priceIn: 0.30, priceOut: 0.30 },
|
|
54
|
+
{ id: 'nvidia/mistral-nemo-minitron-8b-8k-instruct', name: 'Mistral NeMo Minitron 8B', provider: 'nvidia', tags: ['fast'], context: 8192, priceIn: 0.05, priceOut: 0.05 },
|
|
55
|
+
{ id: 'nvidia/nemotron-4-340b-instruct', name: 'Nemotron-4 340B Instruct', provider: 'nvidia', tags: ['frontier', 'legacy'], context: 4096, priceIn: 1.00, priceOut: 3.00 },
|
|
47
56
|
|
|
48
57
|
// ── Mistral ──
|
|
49
|
-
{ id: 'mistralai/mistral-7b-instruct-v0.3', name: 'Mistral 7B Instruct', provider: 'nvidia', tags: ['fast'], context: 32768, priceIn: 0.05, priceOut: 0.05 },
|
|
50
58
|
{ id: 'mistralai/mistral-large', name: 'Mistral Large', provider: 'nvidia', tags: ['frontier'], context: 128000, priceIn: 2.00, priceOut: 6.00 },
|
|
51
59
|
{ id: 'mistralai/mistral-large-2-instruct', name: 'Mistral Large 2 Instruct', provider: 'nvidia', tags: ['frontier'], context: 128000, priceIn: 2.00, priceOut: 6.00 },
|
|
60
|
+
{ id: 'mistralai/mistral-7b-instruct-v0.3', name: 'Mistral 7B Instruct', provider: 'nvidia', tags: ['fast'], context: 65536, priceIn: 0.05, priceOut: 0.05 },
|
|
52
61
|
{ id: 'mistralai/codestral-22b-instruct-v0.1', name: 'Codestral 22B', provider: 'nvidia', tags: ['coding'], context: 32768, priceIn: 0.30, priceOut: 0.60 },
|
|
53
62
|
{ id: 'mistralai/mixtral-8x22b-v0.1', name: 'Mixtral 8x22B', provider: 'nvidia', tags: [], context: 65536, priceIn: 0.60, priceOut: 0.60 },
|
|
54
63
|
{ id: 'nv-mistralai/mistral-nemo-12b-instruct', name: 'Mistral NeMo 12B', provider: 'nvidia', tags: ['fast'], context: 128000, priceIn: 0.05, priceOut: 0.05 },
|
|
@@ -58,26 +67,38 @@ const provider = {
|
|
|
58
67
|
{ id: 'microsoft/phi-3-vision-128k-instruct', name: 'Phi 3 Vision 128K', provider: 'nvidia', tags: ['vision'], context: 128000, priceIn: 0.05, priceOut: 0.05 },
|
|
59
68
|
|
|
60
69
|
// ── Google ──
|
|
61
|
-
{ id: 'google/gemma-
|
|
62
|
-
{ id: 'google/gemma-3-12b-it', name: 'Gemma 3 12B IT', provider: 'nvidia', tags: ['general'], context:
|
|
63
|
-
{ id: 'google/gemma-
|
|
70
|
+
{ id: 'google/gemma-4-31b-it', name: 'Gemma 4 31B IT', provider: 'nvidia', tags: ['general', 'reasoning'], context: 256000, priceIn: 0.20, priceOut: 0.80 },
|
|
71
|
+
{ id: 'google/gemma-3-12b-it', name: 'Gemma 3 12B IT', provider: 'nvidia', tags: ['general'], context: 131072, priceIn: 0.10, priceOut: 0.10 },
|
|
72
|
+
{ id: 'google/gemma-3-4b-it', name: 'Gemma 3 4B IT', provider: 'nvidia', tags: ['fast'], context: 131072, priceIn: 0.03, priceOut: 0.03 },
|
|
73
|
+
{ id: 'google/diffusiongemma-26b-a4b-it', name: 'DiffusionGemma 26B', provider: 'nvidia', tags: ['reasoning'], context: 250000, priceIn: 0.20, priceOut: 0.80 },
|
|
64
74
|
{ id: 'google/codegemma-1.1-7b', name: 'CodeGemma 1.1 7B', provider: 'nvidia', tags: ['coding', 'fast'], context: 16384, priceIn: 0.05, priceOut: 0.05 },
|
|
75
|
+
{ id: 'google/codegemma-7b', name: 'CodeGemma 7B', provider: 'nvidia', tags: ['coding'], context: 16384, priceIn: 0.05, priceOut: 0.05 },
|
|
65
76
|
|
|
66
77
|
// ── OpenAI ──
|
|
67
|
-
{ id: 'openai/gpt-oss-
|
|
68
|
-
|
|
78
|
+
{ id: 'openai/gpt-oss-20b', name: 'GPT-OSS 20B', provider: 'nvidia', tags: ['openai', 'reasoning', 'fast'], context: 131072, priceIn: 0.10, priceOut: 0.30 },
|
|
79
|
+
|
|
80
|
+
// ── Z.ai / Moonshot ──
|
|
81
|
+
{ id: 'z-ai/glm-5.3', name: 'GLM-5.3', provider: 'nvidia', tags: ['reasoning'], context: 1000000, priceIn: 0.30, priceOut: 1.20 },
|
|
82
|
+
{ id: 'z-ai/glm-5.3-flash', name: 'GLM-5.3 Flash', provider: 'nvidia', tags: ['fast', 'reasoning'], context: 1000000, priceIn: 0.05, priceOut: 0.20 },
|
|
83
|
+
{ id: 'moonshotai/kimi-k2.6', name: 'Kimi K2.6', provider: 'nvidia', tags: ['reasoning'], context: 262144, priceIn: 0.20, priceOut: 0.80 },
|
|
69
84
|
|
|
70
85
|
// ── Other ──
|
|
71
|
-
{ id: '
|
|
72
|
-
{ id: '
|
|
73
|
-
{ id: '
|
|
74
|
-
{ id: '
|
|
75
|
-
{ id: '
|
|
86
|
+
{ id: 'poolside/laguna-xs-2.1', name: 'Laguna XS 2.1', provider: 'nvidia', tags: ['free', 'coding', 'reasoning'], context: 262144, priceIn: 0, priceOut: 0 },
|
|
87
|
+
{ id: 'stepfun-ai/step-5-preview', name: 'Step 5 Preview', provider: 'nvidia', tags: ['reasoning'], context: 256000, priceIn: 0.30, priceOut: 1.20 },
|
|
88
|
+
{ id: 'writer/palmyra-creative-122b', name: 'Palmyra Creative 122B', provider: 'nvidia', tags: ['creative'], context: 128000, priceIn: 0.90, priceOut: 0.90 },
|
|
89
|
+
{ id: 'writer/palmyra-fin-70b-32k', name: 'Palmyra Fin 70B', provider: 'nvidia', tags: ['finance'], context: 32768, priceIn: 0.90, priceOut: 0.90 },
|
|
90
|
+
{ id: 'writer/palmyra-med-70b', name: 'Palmyra Med 70B', provider: 'nvidia', tags: ['medical'], context: 128000, priceIn: 0.90, priceOut: 0.90 },
|
|
91
|
+
{ id: 'writer/palmyra-med-70b-32k', name: 'Palmyra Med 70B 32K', provider: 'nvidia', tags: ['medical'], context: 32768, priceIn: 0.90, priceOut: 0.90 },
|
|
76
92
|
{ id: '01-ai/yi-large', name: 'Yi Large', provider: 'nvidia', tags: [], context: 32768, priceIn: 0.30, priceOut: 0.90 },
|
|
77
93
|
{ id: 'ai21labs/jamba-1.5-large-instruct', name: 'Jamba 1.5 Large', provider: 'nvidia', tags: [], context: 256000, priceIn: 0.20, priceOut: 0.80 },
|
|
94
|
+
{ id: 'aisingapore/sea-lion-7b-instruct', name: 'Sea-Lion 7B Instruct', provider: 'nvidia', tags: ['fast'], context: 8192, priceIn: 0.05, priceOut: 0.05 },
|
|
78
95
|
{ id: 'databricks/dbrx-instruct', name: 'DBRX Instruct', provider: 'nvidia', tags: [], context: 32768, priceIn: 0.60, priceOut: 0.60 },
|
|
79
96
|
{ id: 'ibm/granite-3.0-8b-instruct', name: 'Granite 3.0 8B', provider: 'nvidia', tags: ['fast'], context: 32768, priceIn: 0.05, priceOut: 0.05 },
|
|
97
|
+
{ id: 'ibm/granite-3.0-3b-a800m-instruct', name: 'Granite 3.0 3B MoE', provider: 'nvidia', tags: ['fast'], context: 32768, priceIn: 0.03, priceOut: 0.03 },
|
|
80
98
|
{ id: 'ibm/granite-34b-code-instruct', name: 'Granite 34B Code', provider: 'nvidia', tags: ['coding'], context: 16384, priceIn: 0.20, priceOut: 0.20 },
|
|
99
|
+
{ id: 'ibm/granite-8b-code-instruct', name: 'Granite 8B Code', provider: 'nvidia', tags: ['coding', 'fast'], context: 16384, priceIn: 0.10, priceOut: 0.10 },
|
|
100
|
+
{ id: 'nvidia/riva-translate-4b-instruct', name: 'Riva Translate 4B', provider: 'nvidia', tags: ['fast', 'translation'], context: 32768, priceIn: 0.05, priceOut: 0.05 },
|
|
101
|
+
{ id: 'nvidia/riva-translate-4b-instruct-v2', name: 'Riva Translate 4B v2', provider: 'nvidia', tags: ['fast', 'translation'], context: 32768, priceIn: 0.05, priceOut: 0.05 },
|
|
81
102
|
{ id: 'zyphra/zamba2-7b-instruct', name: 'Zamba2 7B', provider: 'nvidia', tags: ['fast'], context: 32768, priceIn: 0.05, priceOut: 0.05 },
|
|
82
103
|
],
|
|
83
104
|
};
|