agen-vektor 0.1.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +212 -0
  3. package/dist/agent/agent.js +90 -0
  4. package/dist/agent/context.js +106 -0
  5. package/dist/agent/loop.js +152 -0
  6. package/dist/agent/memory.js +87 -0
  7. package/dist/agent/planner.js +38 -0
  8. package/dist/agent/prompts.js +41 -0
  9. package/dist/agent/session.js +125 -0
  10. package/dist/cli/index.js +304 -0
  11. package/dist/cli/keyboard.js +283 -0
  12. package/dist/config/config.js +92 -0
  13. package/dist/config/credentials.js +127 -0
  14. package/dist/config/models.js +47 -0
  15. package/dist/providers/anthropic.js +276 -0
  16. package/dist/providers/custom.js +24 -0
  17. package/dist/providers/factory.js +58 -0
  18. package/dist/providers/gemini.js +223 -0
  19. package/dist/providers/ollama.js +195 -0
  20. package/dist/providers/openai-compat.js +296 -0
  21. package/dist/providers/openai.js +17 -0
  22. package/dist/providers/openrouter.js +23 -0
  23. package/dist/providers/provider.js +39 -0
  24. package/dist/security/command-policy.js +99 -0
  25. package/dist/security/permissions.js +66 -0
  26. package/dist/tools/filesystem.js +297 -0
  27. package/dist/tools/git.js +66 -0
  28. package/dist/tools/registry.js +39 -0
  29. package/dist/tools/search.js +184 -0
  30. package/dist/tools/shell.js +108 -0
  31. package/dist/tools/web.js +76 -0
  32. package/dist/tui/app.js +913 -0
  33. package/dist/tui/chat.js +76 -0
  34. package/dist/tui/components.js +85 -0
  35. package/dist/tui/diff.js +105 -0
  36. package/dist/tui/input.js +121 -0
  37. package/dist/tui/statusbar.js +32 -0
  38. package/dist/utils/logger.js +96 -0
  39. package/dist/utils/paths.js +90 -0
  40. package/dist/utils/terminal.js +191 -0
  41. package/package.json +56 -0
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseKey = parseKey;
37
+ exports.enableRawMode = enableRawMode;
38
+ exports.keyStream = keyStream;
39
+ exports.setupReadline = setupReadline;
40
+ /**
41
+ * Keyboard — raw-mode input parsing into semantic key events.
42
+ * Supports ASCII, control keys, arrows, page up/down, home/end,
43
+ * and mouse (SGR + X10) scroll events when the terminal supports it.
44
+ */
45
+ const readline = __importStar(require("node:readline"));
46
+ const SEQ_MAP = {
47
+ '\x1b[A': 'up',
48
+ '\x1b[B': 'down',
49
+ '\x1b[C': 'right',
50
+ '\x1b[D': 'left',
51
+ '\x1b[5~': 'pageup',
52
+ '\x1b[6~': 'pagedown',
53
+ '\x1b[3~': 'delete',
54
+ '\x1b[H': 'home',
55
+ '\x1b[F': 'end',
56
+ '\x1b[1~': 'home',
57
+ '\x1b[4~': 'end',
58
+ '\x1b[7~': 'home',
59
+ '\x1b[8~': 'end',
60
+ '\x1b[Z': 'shift_tab',
61
+ '\x1bOA': 'up',
62
+ '\x1bOB': 'down',
63
+ '\x1bOC': 'right',
64
+ '\x1bOD': 'left',
65
+ };
66
+ function parseKey(data) {
67
+ const events = [];
68
+ let i = 0;
69
+ const s = data.toString('utf8');
70
+ while (i < s.length) {
71
+ const ch = s[i];
72
+ const code = ch.charCodeAt(0);
73
+ // Multi-byte UTF-8 (already decoded in `s`): a BMP char is 1 code unit,
74
+ // an astral char (emoji etc.) is a surrogate pair of 2 code units.
75
+ if (code >= 0x80) {
76
+ const codeUnitLen = code >= 0xd800 && code <= 0xdbff ? 2 : 1;
77
+ const full = s.slice(i, i + codeUnitLen);
78
+ if (full) {
79
+ events.push({ name: 'char', char: full });
80
+ i += codeUnitLen;
81
+ continue;
82
+ }
83
+ }
84
+ // Mouse SGR: ESC [ < b ; x ; y M or m
85
+ if (ch === '\x1b' && s.startsWith('\x1b[<', i)) {
86
+ const end = s.indexOf('M', i + 3);
87
+ const end2 = s.indexOf('m', i + 3);
88
+ const e = end === -1 ? end2 : end;
89
+ if (e !== -1) {
90
+ const parts = s.slice(i + 3, e).split(';').map(Number);
91
+ if (parts.length >= 3) {
92
+ const [b, x, y] = parts;
93
+ const kind = b !== undefined && (b & 64) !== 0 ? 'scroll_up' : b !== undefined && (b & 65) === 65 ? 'scroll_down' : 'click';
94
+ events.push({ name: 'mouse', kind, x, y });
95
+ }
96
+ i = e + 1;
97
+ continue;
98
+ }
99
+ }
100
+ // CSI sequence
101
+ if (ch === '\x1b' && i + 1 < s.length && s[i + 1] === '[') {
102
+ // Find the terminating char
103
+ let j = i + 2;
104
+ while (j < s.length && !/[A-Za-z~]/.test(s[j]))
105
+ j++;
106
+ if (j < s.length) {
107
+ const seq = s.slice(i, j + 1);
108
+ const mapped = SEQ_MAP[seq];
109
+ if (mapped) {
110
+ events.push({ name: mapped });
111
+ }
112
+ else if (seq.startsWith('\x1b[<')) {
113
+ // X10-style mouse
114
+ const m = seq.match(/^<(\d+);(\d+);(\d+)([Mm])$/);
115
+ if (m) {
116
+ const b = Number(m[1]);
117
+ events.push({
118
+ name: 'mouse',
119
+ kind: b === 64 ? 'scroll_up' : b === 65 ? 'scroll_down' : 'click',
120
+ x: Number(m[2]),
121
+ y: Number(m[3]),
122
+ });
123
+ }
124
+ else {
125
+ events.push({ name: 'unknown' });
126
+ }
127
+ }
128
+ else {
129
+ events.push({ name: 'unknown' });
130
+ }
131
+ i = j + 1;
132
+ continue;
133
+ }
134
+ }
135
+ // Alt+arrow: ESC then letter
136
+ if (ch === '\x1b' && i + 2 < s.length && /[a-zA-Z]/.test(s[i + 2] || '')) {
137
+ const seq = s.slice(i, i + 3);
138
+ const mapped = SEQ_MAP[seq];
139
+ events.push(mapped ? { name: mapped } : { name: 'unknown' });
140
+ i += 3;
141
+ continue;
142
+ }
143
+ // Bare ESC
144
+ if (ch === '\x1b') {
145
+ // If it's the last char, treat as escape (or as alt+char prefix)
146
+ if (i === s.length - 1) {
147
+ events.push({ name: 'escape' });
148
+ i++;
149
+ continue;
150
+ }
151
+ const next = s[i + 1];
152
+ if (/[\x20-\x7e]/.test(next)) {
153
+ // Alt+char: treat as escape then char (most apps treat as escape)
154
+ events.push({ name: 'escape' });
155
+ i += 2;
156
+ continue;
157
+ }
158
+ events.push({ name: 'escape' });
159
+ i++;
160
+ continue;
161
+ }
162
+ // Control characters
163
+ if (code === 13 || code === 10) {
164
+ events.push({ name: 'enter' });
165
+ i++;
166
+ continue;
167
+ }
168
+ if (code === 9) {
169
+ events.push({ name: 'tab' });
170
+ i++;
171
+ continue;
172
+ }
173
+ if (code === 127 || code === 8) {
174
+ events.push({ name: 'backspace' });
175
+ i++;
176
+ continue;
177
+ }
178
+ if (code === 27) {
179
+ events.push({ name: 'escape' });
180
+ i++;
181
+ continue;
182
+ }
183
+ if (code === 3) {
184
+ events.push({ name: 'ctrl_c' });
185
+ i++;
186
+ continue;
187
+ }
188
+ if (code === 4) {
189
+ events.push({ name: 'ctrl_d' });
190
+ i++;
191
+ continue;
192
+ }
193
+ if (code === 12) {
194
+ events.push({ name: 'ctrl_l' });
195
+ i++;
196
+ continue;
197
+ }
198
+ if (code === 21) {
199
+ events.push({ name: 'ctrl_u' });
200
+ i++;
201
+ continue;
202
+ }
203
+ if (code === 23) {
204
+ events.push({ name: 'ctrl_w' });
205
+ i++;
206
+ continue;
207
+ }
208
+ if (code === 1) {
209
+ events.push({ name: 'ctrl_a' });
210
+ i++;
211
+ continue;
212
+ }
213
+ if (code === 5) {
214
+ events.push({ name: 'ctrl_e' });
215
+ i++;
216
+ continue;
217
+ }
218
+ if (code === 11) {
219
+ events.push({ name: 'ctrl_k' });
220
+ i++;
221
+ continue;
222
+ }
223
+ if (code === 18) {
224
+ events.push({ name: 'ctrl_r' });
225
+ i++;
226
+ continue;
227
+ }
228
+ if (code === 14) {
229
+ events.push({ name: 'ctrl_n' });
230
+ i++;
231
+ continue;
232
+ }
233
+ if (code === 16) {
234
+ events.push({ name: 'ctrl_p' });
235
+ i++;
236
+ continue;
237
+ }
238
+ if (code === 7) {
239
+ events.push({ name: 'ctrl_g' });
240
+ i++;
241
+ continue;
242
+ }
243
+ // Printable
244
+ if (code >= 32 && code <= 126) {
245
+ events.push({ name: 'char', char: ch });
246
+ i++;
247
+ continue;
248
+ }
249
+ events.push({ name: 'unknown' });
250
+ i++;
251
+ }
252
+ return events;
253
+ }
254
+ /**
255
+ * Enter raw mode. Returns a cleanup function.
256
+ * Works with process.stdin on Linux, macOS, and Termux.
257
+ */
258
+ function enableRawMode() {
259
+ const wasRaw = process.stdin.isRaw;
260
+ process.stdin.setRawMode(true);
261
+ process.stdin.resume();
262
+ process.stdin.setEncoding('utf8');
263
+ return () => {
264
+ try {
265
+ process.stdin.setRawMode(wasRaw);
266
+ }
267
+ catch {
268
+ /* ignore */
269
+ }
270
+ if (process.stdin.isTTY)
271
+ process.stdin.pause();
272
+ };
273
+ }
274
+ /** Create a key stream (async iterable of KeyEvent). */
275
+ function keyStream(onKey) {
276
+ process.stdin.on('data', (data) => {
277
+ for (const ev of parseKey(data))
278
+ onKey(ev);
279
+ });
280
+ }
281
+ function setupReadline(stream) {
282
+ return readline.createInterface({ input: stream, terminal: false });
283
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DEFAULT_CONFIG = void 0;
37
+ exports.loadConfig = loadConfig;
38
+ exports.saveConfig = saveConfig;
39
+ exports.effectiveConfig = effectiveConfig;
40
+ /**
41
+ * VECTOR configuration — stored in ~/.vector/config.json
42
+ *
43
+ * Config is deliberately minimal and JSON-based. All secrets live in
44
+ * credentials.json (0600) or environment variables, never in config.json.
45
+ */
46
+ const fs = __importStar(require("node:fs"));
47
+ const paths_1 = require("../utils/paths");
48
+ const logger_1 = require("../utils/logger");
49
+ exports.DEFAULT_CONFIG = {
50
+ provider: 'openrouter',
51
+ model: 'deepseek/deepseek-chat',
52
+ protocol: 'openai',
53
+ permissionMode: 'ask',
54
+ maxIterations: 25,
55
+ maxRetries: 3,
56
+ requestTimeoutMs: 120_000,
57
+ extraModels: {},
58
+ compactionThreshold: 80_000,
59
+ };
60
+ function loadConfig() {
61
+ (0, paths_1.ensureDirs)();
62
+ const p = (0, paths_1.getConfigPath)();
63
+ try {
64
+ if (fs.existsSync(p)) {
65
+ const raw = fs.readFileSync(p, 'utf8');
66
+ const parsed = JSON.parse(raw);
67
+ return { ...exports.DEFAULT_CONFIG, ...parsed };
68
+ }
69
+ }
70
+ catch (err) {
71
+ logger_1.logger.warn(`config load failed: ${err.message}`);
72
+ }
73
+ return { ...exports.DEFAULT_CONFIG };
74
+ }
75
+ function saveConfig(config) {
76
+ (0, paths_1.ensureDirs)();
77
+ fs.writeFileSync((0, paths_1.getConfigPath)(), JSON.stringify(config, null, 2) + '\n');
78
+ }
79
+ /** Effective config, applying environment variable overrides. */
80
+ function effectiveConfig(base) {
81
+ const cfg = base || loadConfig();
82
+ const out = { ...cfg };
83
+ if (process.env.VECTOR_PROVIDER)
84
+ out.provider = process.env.VECTOR_PROVIDER;
85
+ if (process.env.VECTOR_MODEL)
86
+ out.model = process.env.VECTOR_MODEL;
87
+ if (process.env.VECTOR_API_URL)
88
+ out.apiUrl = process.env.VECTOR_API_URL;
89
+ if (process.env.VECTOR_YOLO === '1')
90
+ out.permissionMode = 'yolo';
91
+ return out;
92
+ }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ENV_KEY_MAP = void 0;
37
+ exports.getApiKey = getApiKey;
38
+ exports.setApiKey = setApiKey;
39
+ exports.hasApiKey = hasApiKey;
40
+ exports.redact = redact;
41
+ /**
42
+ * Credential management.
43
+ *
44
+ * - API keys are read from environment variables first (VECTOR_API_KEY,
45
+ * OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY).
46
+ * - As a convenience fallback, keys may be stored in ~/.vector/credentials.json
47
+ * with restrictive file permissions (0600). Keys are NEVER printed to the
48
+ * terminal, logs, diffs, or session history.
49
+ */
50
+ const fs = __importStar(require("node:fs"));
51
+ const paths_1 = require("../utils/paths");
52
+ exports.ENV_KEY_MAP = {
53
+ openai: 'OPENAI_API_KEY',
54
+ anthropic: 'ANTHROPIC_API_KEY',
55
+ gemini: 'GEMINI_API_KEY',
56
+ openrouter: 'OPENROUTER_API_KEY',
57
+ custom: 'VECTOR_API_KEY',
58
+ };
59
+ function readFile() {
60
+ const p = (0, paths_1.getCredentialsPath)();
61
+ try {
62
+ if (fs.existsSync(p)) {
63
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
64
+ }
65
+ }
66
+ catch {
67
+ /* ignore */
68
+ }
69
+ return {};
70
+ }
71
+ function writeFile(map) {
72
+ (0, paths_1.ensureDirs)();
73
+ const p = (0, paths_1.getCredentialsPath)();
74
+ fs.writeFileSync(p, JSON.stringify(map, null, 2) + '\n', { mode: 0o600 });
75
+ try {
76
+ fs.chmodSync(p, 0o600);
77
+ }
78
+ catch {
79
+ /* some filesystems (e.g. some Termux setups) ignore chmod */
80
+ }
81
+ }
82
+ /**
83
+ * Resolve an API key for a provider.
84
+ * Order: env var > credentials.json. Returns null when unset.
85
+ */
86
+ function getApiKey(providerId) {
87
+ // Explicit per-provider env first
88
+ const envKey = exports.ENV_KEY_MAP[providerId];
89
+ if (envKey) {
90
+ const v = process.env[envKey];
91
+ if (v && v.trim() !== '')
92
+ return v;
93
+ }
94
+ // Generic fallback
95
+ if (process.env.VECTOR_API_KEY && providerId !== 'custom') {
96
+ // VECTOR_API_KEY should not override the dedicated provider vars
97
+ if (!exports.ENV_KEY_MAP[providerId] || !process.env[exports.ENV_KEY_MAP[providerId]]) {
98
+ const v = process.env.VECTOR_API_KEY;
99
+ if (v && v.trim() !== '')
100
+ return v;
101
+ }
102
+ }
103
+ const map = readFile();
104
+ return map[providerId] || null;
105
+ }
106
+ /** Set (or remove) a stored key for a provider. */
107
+ function setApiKey(providerId, key) {
108
+ const map = readFile();
109
+ if (key === null || key === '') {
110
+ delete map[providerId];
111
+ }
112
+ else {
113
+ map[providerId] = key;
114
+ }
115
+ writeFile(map);
116
+ }
117
+ function hasApiKey(providerId) {
118
+ return getApiKey(providerId) !== null;
119
+ }
120
+ /** Sanitize a string so it never leaks secrets into logs. */
121
+ function redact(text) {
122
+ // Replace any likely bearer token / API key patterns
123
+ return text
124
+ .replace(/(sk-[A-Za-z0-9_-]{8,})/g, 'sk-***REDACTED***')
125
+ .replace(/(Bearer\s+)[A-Za-z0-9._-]{12,}/gi, '$1***REDACTED***')
126
+ .replace(/(api[_-]?key["']?\s*[:=]\s*["']?)[^"'\s,;]+/gi, '$1***REDACTED***');
127
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Model catalog + known model lists per provider.
4
+ * Users can add custom models via `vector /model` or editing models.json.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.KNOWN_MODELS = void 0;
8
+ exports.modelsForProvider = modelsForProvider;
9
+ exports.KNOWN_MODELS = {
10
+ openai: [
11
+ { id: 'gpt-4o', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
12
+ { id: 'gpt-4o-mini', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
13
+ { id: 'gpt-4-turbo', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
14
+ { id: 'o3-mini', contextWindow: 200000, supportsTools: true, supportsStreaming: true },
15
+ { id: 'gpt-4.1', contextWindow: 1047576, supportsTools: true, supportsStreaming: true },
16
+ ],
17
+ anthropic: [
18
+ { id: 'claude-sonnet-4-20250514', label: 'Claude Sonnet 4', contextWindow: 200000, supportsTools: true, supportsStreaming: true },
19
+ { id: 'claude-opus-4-20250514', label: 'Claude Opus 4', contextWindow: 200000, supportsTools: true, supportsStreaming: true },
20
+ { id: 'claude-3-5-haiku-20241022', label: 'Claude 3.5 Haiku', contextWindow: 200000, supportsTools: true, supportsStreaming: true },
21
+ ],
22
+ gemini: [
23
+ { id: 'gemini-2.5-pro', contextWindow: 1048576, supportsTools: true, supportsStreaming: true },
24
+ { id: 'gemini-2.5-flash', contextWindow: 1048576, supportsTools: true, supportsStreaming: true },
25
+ { id: 'gemini-2.0-flash', contextWindow: 1048576, supportsTools: true, supportsStreaming: true },
26
+ ],
27
+ openrouter: [
28
+ { id: 'deepseek/deepseek-chat', label: 'DeepSeek V3', contextWindow: 64000, supportsTools: true, supportsStreaming: true },
29
+ { id: 'deepseek/deepseek-reasoner', label: 'DeepSeek R1', contextWindow: 64000, supportsTools: false, supportsStreaming: true },
30
+ { id: 'anthropic/claude-sonnet-4', contextWindow: 200000, supportsTools: true, supportsStreaming: true },
31
+ { id: 'openai/gpt-4o', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
32
+ { id: 'google/gemini-2.5-pro', contextWindow: 1048576, supportsTools: true, supportsStreaming: true },
33
+ ],
34
+ ollama: [
35
+ { id: 'llama3.1', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
36
+ { id: 'llama3.2', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
37
+ { id: 'qwen2.5-coder', contextWindow: 32768, supportsTools: true, supportsStreaming: true },
38
+ { id: 'deepseek-coder-v2', contextWindow: 128000, supportsTools: true, supportsStreaming: true },
39
+ { id: 'mistral', contextWindow: 32768, supportsTools: true, supportsStreaming: true },
40
+ ],
41
+ };
42
+ /** Get a model list for a provider, falling back to a generic entry. */
43
+ function modelsForProvider(providerId) {
44
+ return exports.KNOWN_MODELS[providerId] || [
45
+ { id: 'default', supportsTools: true, supportsStreaming: true },
46
+ ];
47
+ }