agent-termo 1.0.1 → 1.0.2

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 (65) hide show
  1. package/README.md +27 -2
  2. package/dist/agents/index.d.ts +5 -0
  3. package/dist/agents/index.d.ts.map +1 -0
  4. package/dist/agents/index.js +86 -0
  5. package/dist/agents/index.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +97 -168
  9. package/dist/cli.js.map +4 -4
  10. package/dist/diff/index.d.ts +9 -0
  11. package/dist/diff/index.d.ts.map +1 -0
  12. package/dist/diff/index.js +213 -0
  13. package/dist/diff/index.js.map +1 -0
  14. package/dist/llm/client.d.ts +39 -0
  15. package/dist/llm/client.d.ts.map +1 -0
  16. package/dist/llm/client.js +188 -0
  17. package/dist/llm/client.js.map +1 -0
  18. package/dist/llm/models.d.ts +19 -0
  19. package/dist/llm/models.d.ts.map +1 -0
  20. package/dist/llm/models.js +45 -0
  21. package/dist/llm/models.js.map +1 -0
  22. package/dist/llm/tools.d.ts +3 -0
  23. package/dist/llm/tools.d.ts.map +1 -0
  24. package/dist/llm/tools.js +204 -0
  25. package/dist/llm/tools.js.map +1 -0
  26. package/dist/main.d.ts +2 -0
  27. package/dist/main.d.ts.map +1 -0
  28. package/dist/main.js +91 -140
  29. package/dist/main.js.map +4 -4
  30. package/dist/memory/index.d.ts +10 -0
  31. package/dist/memory/index.d.ts.map +1 -0
  32. package/dist/memory/index.js +117 -0
  33. package/dist/memory/index.js.map +1 -0
  34. package/dist/tools/index.d.ts +5 -0
  35. package/dist/tools/index.d.ts.map +1 -0
  36. package/dist/tools/index.js +334 -0
  37. package/dist/tools/index.js.map +1 -0
  38. package/dist/types/index.d.ts +119 -0
  39. package/dist/types/index.d.ts.map +1 -0
  40. package/dist/types/index.js +5 -0
  41. package/dist/types/index.js.map +1 -0
  42. package/dist/ui/index.d.ts +47 -0
  43. package/dist/ui/index.d.ts.map +1 -0
  44. package/dist/ui/index.js +321 -0
  45. package/dist/ui/index.js.map +1 -0
  46. package/dist/ui/screen.d.ts +59 -0
  47. package/dist/ui/screen.d.ts.map +1 -0
  48. package/dist/ui/screen.js +629 -0
  49. package/dist/ui/screen.js.map +1 -0
  50. package/dist/utils/ansi.d.ts +62 -0
  51. package/dist/utils/ansi.d.ts.map +1 -0
  52. package/dist/utils/ansi.js +116 -0
  53. package/dist/utils/ansi.js.map +1 -0
  54. package/dist/utils/config.d.ts +9 -0
  55. package/dist/utils/config.d.ts.map +1 -0
  56. package/dist/utils/config.js +120 -0
  57. package/dist/utils/config.js.map +1 -0
  58. package/package.json +1 -1
  59. package/src/cli.ts +1 -1
  60. package/src/llm/client.ts +24 -0
  61. package/src/llm/models.ts +55 -0
  62. package/src/main.ts +201 -75
  63. package/src/ui/index.ts +256 -389
  64. package/src/ui/screen.ts +698 -0
  65. package/src/utils/config.ts +37 -20
@@ -0,0 +1,62 @@
1
+ export declare const COLORS: {
2
+ primary: string;
3
+ primaryBg: string;
4
+ success: string;
5
+ warning: string;
6
+ error: string;
7
+ info: string;
8
+ background: string;
9
+ surface: string;
10
+ elevated: string;
11
+ border: string;
12
+ borderLight: string;
13
+ text: string;
14
+ textSecondary: string;
15
+ muted: string;
16
+ dim: string;
17
+ manager: string;
18
+ architect: string;
19
+ expert: string;
20
+ security: string;
21
+ codeKeyword: string;
22
+ codeString: string;
23
+ codeComment: string;
24
+ codeFunction: string;
25
+ codeType: string;
26
+ userMsg: string;
27
+ aiMsg: string;
28
+ accent: string;
29
+ reset: string;
30
+ bright: string;
31
+ dim_text: string;
32
+ italic: string;
33
+ underline: string;
34
+ };
35
+ export declare const BG: {
36
+ surface: string;
37
+ elevated: string;
38
+ primaryBg: string;
39
+ };
40
+ export declare const FMT: {
41
+ bold: string;
42
+ dim: string;
43
+ ita: string;
44
+ ul: string;
45
+ reset: string;
46
+ };
47
+ export declare function color(colorCode: string, text: string): string;
48
+ export declare function bg(colorCode: string, text: string): string;
49
+ export declare function bold(text: string): string;
50
+ export declare function dim(text: string): string;
51
+ export declare function spinnerFrame(): string;
52
+ export declare function resetSpinner(): void;
53
+ export declare function hbar(length: number, char?: string): string;
54
+ export declare function clamp(text: string, maxLength: number): string;
55
+ export declare function progressBar(percent: number, width?: number): string;
56
+ export declare function agentColor(agentName: string): string;
57
+ export declare const clearLine = "\u001B[2K\r";
58
+ export declare const clearScreen = "\u001B[2J";
59
+ export declare const cursorHome = "\u001B[H";
60
+ export declare const hideCursor = "\u001B[?25l";
61
+ export declare const showCursor = "\u001B[?25h";
62
+ //# sourceMappingURL=ansi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../../src/utils/ansi.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDlB,CAAC;AAEF,eAAO,MAAM,EAAE;;;;CAId,CAAC;AAEF,eAAO,MAAM,GAAG;;;;;;CAMf,CAAC;AAGF,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExC;AAMD,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAGD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7D;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAI/D;AAGD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMpD;AAGD,eAAO,MAAM,SAAS,gBAAc,CAAC;AACrC,eAAO,MAAM,WAAW,cAAY,CAAC;AACrC,eAAO,MAAM,UAAU,aAAW,CAAC;AACnC,eAAO,MAAM,UAAU,gBAAc,CAAC;AACtC,eAAO,MAAM,UAAU,gBAAc,CAAC"}
@@ -0,0 +1,116 @@
1
+ // =============================================================================
2
+ // ANSI Color Utilities
3
+ // =============================================================================
4
+ // Design System colors (ANSI 256-color codes for cross-platform terminal)
5
+ export const COLORS = {
6
+ // Primary: #A855F7 → ANSI 135
7
+ primary: '\x1b[38;5;135m',
8
+ primaryBg: '\x1b[48;5;57m',
9
+ // Semantic
10
+ success: '\x1b[38;5;82m', // green-500
11
+ warning: '\x1b[38;5;214m', // amber-500
12
+ error: '\x1b[38;5;203m', // red-500
13
+ info: '\x1b[38;5;75m', // blue-500
14
+ // Dark theme neutrals
15
+ background: '\x1b[48;5;17m', // slate-900
16
+ surface: '\x1b[48;5;30m', // slate-800
17
+ elevated: '\x1b[48;5;31m', // slate-700
18
+ border: '\x1b[38;5;240m', // #646B7B
19
+ borderLight: '\x1b[38;5;241m', // #7C8796
20
+ // Text
21
+ text: '\x1b[38;5;255m', // slate-50
22
+ textSecondary: '\x1b[38;5;188m', // slate-300
23
+ muted: '\x1b[38;5;250m', // slate-400
24
+ dim: '\x1b[38;5;244m', // slate-400
25
+ // Agent badge colors
26
+ manager: '\x1b[38;5;135m', // purple
27
+ architect: '\x1b[38;5;75m', // blue
28
+ expert: '\x1b[38;5;82m', // green
29
+ security: '\x1b[38;5;214m', // amber
30
+ // Code syntax
31
+ codeKeyword: '\x1b[38;5;219m', // pink-400
32
+ codeString: '\x1b[38;5;114m', // green-400
33
+ codeComment: '\x1b[38;5;245m', // gray-400
34
+ codeFunction: '\x1b[38;5;75m', // blue-400
35
+ codeType: '\x1b[38;5;171m', // emerald-400
36
+ // Roles
37
+ userMsg: '\x1b[38;5;82m', // green for user
38
+ aiMsg: '\x1b[38;5;135m', // purple for AI
39
+ // Decorators
40
+ accent: '\x1b[38;5;75m', // blue accent
41
+ // Reset
42
+ reset: '\x1b[0m',
43
+ bright: '\x1b[1m',
44
+ dim_text: '\x1b[2m',
45
+ italic: '\x1b[3m',
46
+ underline: '\x1b[4m',
47
+ };
48
+ export const BG = {
49
+ surface: '\x1b[48;5;30m',
50
+ elevated: '\x1b[48;5;31m',
51
+ primaryBg: '\x1b[48;5;57m',
52
+ };
53
+ export const FMT = {
54
+ bold: '\x1b[1m',
55
+ dim: '\x1b[2m',
56
+ ita: '\x1b[3m',
57
+ ul: '\x1b[4m',
58
+ reset: '\x1b[0m',
59
+ };
60
+ // Escape helpers
61
+ export function color(colorCode, text) {
62
+ return `${colorCode}${text}${COLORS.reset}`;
63
+ }
64
+ export function bg(colorCode, text) {
65
+ return `${colorCode}${text}${COLORS.reset}`;
66
+ }
67
+ export function bold(text) {
68
+ return `${FMT.bold}${text}${FMT.reset}`;
69
+ }
70
+ export function dim(text) {
71
+ return `${FMT.dim}${text}${FMT.reset}`;
72
+ }
73
+ // Spinner frames (80ms per frame, 12 chars cycle)
74
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
75
+ let spinnerIndex = 0;
76
+ export function spinnerFrame() {
77
+ const frame = SPINNER_FRAMES[spinnerIndex % SPINNER_FRAMES.length];
78
+ spinnerIndex++;
79
+ return frame ?? ' ';
80
+ }
81
+ export function resetSpinner() {
82
+ spinnerIndex = 0;
83
+ }
84
+ // Box drawing helpers
85
+ export function hbar(length, char = '─') {
86
+ return char.repeat(length);
87
+ }
88
+ export function clamp(text, maxLength) {
89
+ if (text.length <= maxLength)
90
+ return text;
91
+ return text.slice(0, maxLength - 3) + '...';
92
+ }
93
+ // Progress bar
94
+ export function progressBar(percent, width = 30) {
95
+ const filled = Math.round((percent / 100) * width);
96
+ const empty = width - filled;
97
+ return `[${COLORS.success}${'█'.repeat(filled)}${'░'.repeat(empty)}${COLORS.reset}]`;
98
+ }
99
+ // Agent badge color
100
+ export function agentColor(agentName) {
101
+ const lower = agentName.toLowerCase();
102
+ if (lower.includes('project-manager'))
103
+ return COLORS.manager;
104
+ if (lower.includes('architecture') || lower.includes('stack'))
105
+ return COLORS.architect;
106
+ if (lower.includes('security') || lower.includes('deploy'))
107
+ return COLORS.security;
108
+ return COLORS.expert;
109
+ }
110
+ // Clear line (ANSI)
111
+ export const clearLine = '\x1b[2K\r';
112
+ export const clearScreen = '\x1b[2J';
113
+ export const cursorHome = '\x1b[H';
114
+ export const hideCursor = '\x1b[?25l';
115
+ export const showCursor = '\x1b[?25h';
116
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../src/utils/ansi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { AppConfig } from '../types/index.js';
2
+ declare const PROJECT_ROOT: string;
3
+ export { PROJECT_ROOT };
4
+ export declare function getAgentTermoDir(): string;
5
+ export declare function saveNimApiKey(apiKey: string): void;
6
+ export declare function saveNimModel(model: string): void;
7
+ export declare function getConfig(projectRoot: string): AppConfig;
8
+ export declare function resolveProjectRoot(cwd?: string): string;
9
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAiCnD,QAAA,MAAM,YAAY,QAAmB,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAmDD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEhD;AAKD,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAgBxD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,120 @@
1
+ // =============================================================================
2
+ // Config Management
3
+ // =============================================================================
4
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
5
+ import { resolve, dirname } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ // Find project root reliably (works even when cwd != project dir)
8
+ function getProjectRoot() {
9
+ // Try import.meta.url first (ESM)
10
+ try {
11
+ const thisFile = fileURLToPath(import.meta.url);
12
+ return dirname(dirname(thisFile)); // src/utils/ → src/ → project root
13
+ }
14
+ catch {
15
+ // Fall back to process.cwd()
16
+ return process.cwd();
17
+ }
18
+ }
19
+ // Load .env files at startup
20
+ function loadEnvFile(envPath) {
21
+ try {
22
+ const content = readFileSync(envPath, 'utf-8');
23
+ for (const line of content.split('\n')) {
24
+ const trimmed = line.trim();
25
+ if (!trimmed || trimmed.startsWith('#'))
26
+ continue;
27
+ const eqIdx = trimmed.indexOf('=');
28
+ if (eqIdx === -1 || eqIdx === trimmed.length - 1)
29
+ continue;
30
+ const key = trimmed.slice(0, eqIdx).trim();
31
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
32
+ if (!process.env[key])
33
+ process.env[key] = value;
34
+ }
35
+ }
36
+ catch {
37
+ // file not found — continue silently
38
+ }
39
+ }
40
+ // Load .env from project root and current directory
41
+ const PROJECT_ROOT = getProjectRoot();
42
+ loadEnvFile(resolve(PROJECT_ROOT, '.env'));
43
+ loadEnvFile(resolve('.env')); // also try cwd
44
+ export { PROJECT_ROOT };
45
+ export function getAgentTermoDir() {
46
+ const envDir = process.env.AGENT_TERMO_DIR;
47
+ if (envDir) {
48
+ return resolve(process.env.HOME || process.env.USERPROFILE || '.', envDir);
49
+ }
50
+ return resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');
51
+ }
52
+ function readStoredConfig() {
53
+ try {
54
+ const existing = JSON.parse(readFileSync(resolve(getAgentTermoDir(), 'config.json'), 'utf-8'));
55
+ if (existing && typeof existing === 'object' && !Array.isArray(existing)) {
56
+ return existing;
57
+ }
58
+ }
59
+ catch {
60
+ // No saved user configuration yet.
61
+ }
62
+ return {};
63
+ }
64
+ function updateStoredConfig(patch) {
65
+ const configDir = getAgentTermoDir();
66
+ const configPath = resolve(configDir, 'config.json');
67
+ const storedConfig = { ...readStoredConfig(), ...patch };
68
+ mkdirSync(configDir, { recursive: true, mode: 0o700 });
69
+ writeFileSync(configPath, `${JSON.stringify(storedConfig, null, 2)}\n`, {
70
+ encoding: 'utf-8',
71
+ mode: 0o600,
72
+ });
73
+ // Restrict permissions even when updating an existing file on Unix.
74
+ if (process.platform !== 'win32')
75
+ chmodSync(configPath, 0o600);
76
+ }
77
+ function loadStoredNimApiKey() {
78
+ if (process.env.NIM_API_KEY)
79
+ return;
80
+ const { nimApiKey } = readStoredConfig();
81
+ if (typeof nimApiKey === 'string' && nimApiKey.trim()) {
82
+ process.env.NIM_API_KEY = nimApiKey;
83
+ }
84
+ }
85
+ /**
86
+ * A model picked with /model is saved and wins over NIM_MODEL from .env, so
87
+ * the choice survives restarts. The --model CLI flag still overrides it.
88
+ */
89
+ function loadStoredNimModel() {
90
+ const { nimModel } = readStoredConfig();
91
+ if (typeof nimModel === 'string' && nimModel.trim()) {
92
+ process.env.NIM_MODEL = nimModel;
93
+ }
94
+ }
95
+ export function saveNimApiKey(apiKey) {
96
+ updateStoredConfig({ nimApiKey: apiKey });
97
+ }
98
+ export function saveNimModel(model) {
99
+ updateStoredConfig({ nimModel: model });
100
+ }
101
+ loadStoredNimApiKey();
102
+ loadStoredNimModel();
103
+ export function getConfig(projectRoot) {
104
+ loadEnvFile(resolve(projectRoot, '.env'));
105
+ return {
106
+ nimApiKey: process.env.NIM_API_KEY ?? '',
107
+ nimBaseUrl: process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1',
108
+ nimModel: process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash',
109
+ agentTermoDir: process.env.AGENT_TERMO_DIR ?? '.claude',
110
+ logLevel: process.env.LOG_LEVEL || 'info',
111
+ confirmDestructive: process.env.CONFIRM_DESTRUCTIVE !== 'false',
112
+ allowedCommands: (process.env.ALLOWED_COMMANDS ?? 'git,npm,node,pnpm,yarn,tsx,tsc,npx').split(','),
113
+ llmTimeout: parseInt(process.env.LLM_TIMEOUT ?? '120000', 10),
114
+ bashTimeout: parseInt(process.env.BASH_TIMEOUT ?? '300000', 10),
115
+ };
116
+ }
117
+ export function resolveProjectRoot(cwd) {
118
+ return cwd || PROJECT_ROOT;
119
+ }
120
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-termo",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Terminal-based AI coding agent that replicates Claude Code experience",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",
package/src/cli.ts CHANGED
@@ -96,7 +96,7 @@ async function startAgent(
96
96
  program
97
97
  .name('agent-termo')
98
98
  .description('Terminal AI coding agent with Nvidia NIM APIs')
99
- .version('1.0.1')
99
+ .version('1.0.2')
100
100
  .argument('[project]', 'Project directory to operate in', process.cwd())
101
101
  .option('-k, --api-key <key>', 'Nvidia NIM API key')
102
102
  .option('-m, --model <model>', 'Model name to use')
package/src/llm/client.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import OpenAI from 'openai';
6
6
  import type { ToolCall, ConversationMessage, ToolDef } from '../types/index.js';
7
+ import { mergeModels, type ModelInfo } from './models.js';
7
8
 
8
9
  type NIMTool = OpenAI.Chat.ChatCompletionTool;
9
10
 
@@ -40,6 +41,29 @@ export class NimClient {
40
41
  return this.model;
41
42
  }
42
43
 
44
+ setModel(model: string): void {
45
+ this.model = model;
46
+ }
47
+
48
+ /**
49
+ * Fetch the models this API key can use. Never throws: on failure the curated
50
+ * list is returned with `live: false` and the reason in `error`.
51
+ */
52
+ async listModels(): Promise<{ models: ModelInfo[]; live: boolean; error?: string }> {
53
+ try {
54
+ const page = await this.client.models.list({ timeout: 10_000 });
55
+ const ids = page.data.map((m) => m.id);
56
+ if (ids.length === 0) throw new Error('empty model list');
57
+ return { models: mergeModels(ids), live: true };
58
+ } catch (err) {
59
+ return {
60
+ models: mergeModels(null),
61
+ live: false,
62
+ error: err instanceof Error ? err.message : String(err),
63
+ };
64
+ }
65
+ }
66
+
43
67
  /**
44
68
  * Streaming chat completion.
45
69
  * Handles Stepfun's quirks: filters "null" reasoning chunks, strips reasoning field.
@@ -0,0 +1,55 @@
1
+ // =============================================================================
2
+ // NVIDIA NIM model catalogue — curated suggestions + live /v1/models merge
3
+ // =============================================================================
4
+
5
+ export interface ModelInfo {
6
+ id: string;
7
+ note?: string;
8
+ }
9
+
10
+ /**
11
+ * Hand-picked chat/coding models worth surfacing first. This list is only a
12
+ * starting point: when the live catalogue is reachable, entries NIM no longer
13
+ * serves are dropped, and everything else NIM returns is still selectable.
14
+ */
15
+ export const CURATED_MODELS: ModelInfo[] = [
16
+ { id: 'stepfun-ai/step-3.7-flash', note: 'default' },
17
+ { id: 'meta/llama-3.1-8b-instruct', note: 'fast, low cost' },
18
+ { id: 'meta/llama-3.1-70b-instruct', note: 'balanced' },
19
+ { id: 'meta/llama-3.3-70b-instruct', note: 'balanced' },
20
+ { id: 'meta/llama-3.1-405b-instruct', note: 'highest quality Llama' },
21
+ { id: 'nvidia/llama-3.1-nemotron-70b-instruct', note: 'NVIDIA tuned' },
22
+ { id: 'qwen/qwen2.5-coder-32b-instruct', note: 'coding' },
23
+ { id: 'deepseek-ai/deepseek-r1', note: 'reasoning' },
24
+ { id: 'moonshotai/kimi-k2-instruct', note: 'agentic / tool use' },
25
+ { id: 'openai/gpt-oss-120b', note: 'open-weight GPT' },
26
+ ];
27
+
28
+ // NIM serves embedding, vision, speech and other non-chat models from the same
29
+ // endpoint. Hide the obvious ones so the picker stays about chat models.
30
+ const NON_CHAT =
31
+ /embed|rerank|retriev|reward|guard|safety|parse|clip|vila|neva|fuyu|kosmos|paligemma|deplot|riva|asr|tts|whisper|diffusion|sdxl|flux|cosmos|segment|bge-|e5-|gliner|pii|streampetr|ocdrnet|bevformer/i;
32
+
33
+ export function isChatModel(id: string): boolean {
34
+ return !NON_CHAT.test(id);
35
+ }
36
+
37
+ /**
38
+ * Build the picker list.
39
+ * - live === null: the catalogue could not be fetched, so offer the curated list.
40
+ * - otherwise: curated entries that NIM serves first, then the rest of the live
41
+ * chat models alphabetically.
42
+ */
43
+ export function mergeModels(live: string[] | null): ModelInfo[] {
44
+ if (!live) return [...CURATED_MODELS];
45
+
46
+ const liveSet = new Set(live);
47
+ const curated = CURATED_MODELS.filter((m) => liveSet.has(m.id));
48
+ const curatedIds = new Set(curated.map((m) => m.id));
49
+ const rest = live
50
+ .filter((id) => !curatedIds.has(id) && isChatModel(id))
51
+ .sort((a, b) => a.localeCompare(b))
52
+ .map((id): ModelInfo => ({ id }));
53
+
54
+ return [...curated, ...rest];
55
+ }