codemaxxing 0.4.13 → 0.4.15
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/README.md +5 -0
- package/dist/index.js +52 -4
- package/dist/utils/models.d.ts +1 -1
- package/dist/utils/models.js +6 -4
- package/dist/utils/ollama.js +2 -1
- package/package.json +1 -1
- package/src/index.tsx +50 -4
- package/src/utils/models.ts +7 -6
- package/src/utils/ollama.ts +2 -1
package/README.md
CHANGED
|
@@ -46,6 +46,11 @@ curl -fsSL -o $env:TEMP\install-codemaxxing.bat https://raw.githubusercontent.co
|
|
|
46
46
|
npm update -g codemaxxing
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
If that doesn't get the latest version:
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g codemaxxing@latest
|
|
52
|
+
```
|
|
53
|
+
|
|
49
54
|
## Quick Start
|
|
50
55
|
|
|
51
56
|
### 1. Start Your LLM
|
package/dist/index.js
CHANGED
|
@@ -175,6 +175,35 @@ function App() {
|
|
|
175
175
|
pasteEvents.on("paste", handler);
|
|
176
176
|
return () => { pasteEvents.off("paste", handler); };
|
|
177
177
|
}, []);
|
|
178
|
+
// Refresh the connection banner to reflect current provider status
|
|
179
|
+
const refreshConnectionBanner = useCallback(async () => {
|
|
180
|
+
const info = [];
|
|
181
|
+
const cliArgs = parseCLIArgs();
|
|
182
|
+
const rawConfig = loadConfig();
|
|
183
|
+
const config = applyOverrides(rawConfig, cliArgs);
|
|
184
|
+
const provider = config.provider;
|
|
185
|
+
if (provider.model === "auto" || (provider.baseUrl === "http://localhost:1234/v1" && !cliArgs.baseUrl)) {
|
|
186
|
+
const detected = await detectLocalProvider();
|
|
187
|
+
if (detected) {
|
|
188
|
+
info.push(`✔ Connected to ${detected.baseUrl} → ${detected.model}`);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const ollamaUp = await isOllamaRunning();
|
|
192
|
+
info.push(ollamaUp ? "Ollama running (no model loaded)" : "✗ No local LLM server found");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
info.push(`Provider: ${provider.baseUrl}`);
|
|
197
|
+
info.push(`Model: ${provider.model}`);
|
|
198
|
+
}
|
|
199
|
+
const cwd = process.cwd();
|
|
200
|
+
if (isGitRepo(cwd)) {
|
|
201
|
+
const branch = getBranch(cwd);
|
|
202
|
+
const status = getStatus(cwd);
|
|
203
|
+
info.push(`Git: ${branch} (${status})`);
|
|
204
|
+
}
|
|
205
|
+
setConnectionInfo(info);
|
|
206
|
+
}, []);
|
|
178
207
|
// Connect/reconnect to LLM provider
|
|
179
208
|
const connectToProvider = useCallback(async (isRetry = false) => {
|
|
180
209
|
const cliArgs = parseCLIArgs();
|
|
@@ -664,6 +693,7 @@ function App() {
|
|
|
664
693
|
await new Promise(r => setTimeout(r, 1000));
|
|
665
694
|
if (await isOllamaRunning()) {
|
|
666
695
|
addMsg("info", "Ollama is running.");
|
|
696
|
+
await refreshConnectionBanner();
|
|
667
697
|
return;
|
|
668
698
|
}
|
|
669
699
|
}
|
|
@@ -679,6 +709,8 @@ function App() {
|
|
|
679
709
|
addMsg("info", "Stopping Ollama...");
|
|
680
710
|
const result = await stopOllama();
|
|
681
711
|
addMsg(result.ok ? "info" : "error", result.ok ? `\u2705 ${result.message}` : `\u274C ${result.message}`);
|
|
712
|
+
if (result.ok)
|
|
713
|
+
await refreshConnectionBanner();
|
|
682
714
|
return;
|
|
683
715
|
}
|
|
684
716
|
if (trimmed === "/ollama pull") {
|
|
@@ -730,7 +762,23 @@ function App() {
|
|
|
730
762
|
return;
|
|
731
763
|
}
|
|
732
764
|
if (trimmed === "/ollama delete") {
|
|
733
|
-
//
|
|
765
|
+
// Ensure Ollama is running so we can list models
|
|
766
|
+
let running = await isOllamaRunning();
|
|
767
|
+
if (!running) {
|
|
768
|
+
addMsg("info", "Starting Ollama to list models...");
|
|
769
|
+
startOllama();
|
|
770
|
+
for (let i = 0; i < 10; i++) {
|
|
771
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
772
|
+
if (await isOllamaRunning()) {
|
|
773
|
+
running = true;
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (!running) {
|
|
778
|
+
addMsg("error", "Could not start Ollama. Start it manually first.");
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
734
782
|
const models = await listInstalledModelsDetailed();
|
|
735
783
|
if (models.length === 0) {
|
|
736
784
|
addMsg("info", "No models installed.");
|
|
@@ -1021,7 +1069,7 @@ function App() {
|
|
|
1021
1069
|
}
|
|
1022
1070
|
setLoading(false);
|
|
1023
1071
|
setStreaming(false);
|
|
1024
|
-
}, [agent, exit]);
|
|
1072
|
+
}, [agent, exit, refreshConnectionBanner]);
|
|
1025
1073
|
useInput((inputChar, key) => {
|
|
1026
1074
|
// Handle slash command navigation
|
|
1027
1075
|
if (showSuggestionsRef.current) {
|
|
@@ -1351,7 +1399,7 @@ function App() {
|
|
|
1351
1399
|
const pullModels = [
|
|
1352
1400
|
{ id: "qwen2.5-coder:7b", name: "Qwen 2.5 Coder 7B", size: "5 GB", desc: "Best balance of speed & quality" },
|
|
1353
1401
|
{ id: "qwen2.5-coder:14b", name: "Qwen 2.5 Coder 14B", size: "9 GB", desc: "Higher quality, needs 16GB+ RAM" },
|
|
1354
|
-
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "
|
|
1402
|
+
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "\u26A0\uFE0F Basic \u2014 may struggle with tool calls" },
|
|
1355
1403
|
{ id: "qwen2.5-coder:32b", name: "Qwen 2.5 Coder 32B", size: "20 GB", desc: "Premium quality, needs 48GB+" },
|
|
1356
1404
|
{ id: "deepseek-coder-v2:16b", name: "DeepSeek Coder V2", size: "9 GB", desc: "Strong alternative" },
|
|
1357
1405
|
{ id: "codellama:7b", name: "CodeLlama 7B", size: "4 GB", desc: "Meta's coding model" },
|
|
@@ -1915,7 +1963,7 @@ function App() {
|
|
|
1915
1963
|
})(), themePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Choose a theme:" }), listThemes().map((key, i) => (_jsxs(Text, { children: [i === themePickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === themePickerIndex ? theme.colors.suggestion : theme.colors.primary, bold: true, children: key }), _jsxs(Text, { color: theme.colors.muted, children: [" — ", THEMES[key].description] }), key === theme.name.toLowerCase() ? _jsx(Text, { color: theme.colors.muted, children: " (current)" }) : null] }, key))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), sessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Resume a session:" }), sessionPicker.map((s, i) => (_jsxs(Text, { children: [i === sessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === sessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.error, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.error, children: "Delete a session:" }), deleteSessionPicker.map((s, i) => (_jsxs(Text, { children: [i === deleteSessionPickerIndex ? _jsx(Text, { color: theme.colors.suggestion, bold: true, children: "▸ " }) : _jsx(Text, { children: " " }), _jsx(Text, { color: i === deleteSessionPickerIndex ? theme.colors.suggestion : theme.colors.muted, children: s.display })] }, s.id))), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter select · Esc cancel" })] })), deleteSessionConfirm && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.warning, paddingX: 1, marginBottom: 0, children: [_jsxs(Text, { bold: true, color: theme.colors.warning, children: ["Delete session ", deleteSessionConfirm.id, "?"] }), _jsxs(Text, { color: theme.colors.muted, children: [" ", deleteSessionConfirm.display] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.colors.error, bold: true, children: " [y]" }), _jsx(Text, { children: "es " }), _jsx(Text, { color: theme.colors.success, bold: true, children: "[n]" }), _jsx(Text, { children: "o" })] })] })), ollamaDeletePicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Delete which model?" }), _jsx(Text, { children: "" }), ollamaDeletePicker.models.map((m, i) => (_jsxs(Text, { children: [" ", i === ollamaDeletePickerIndex ? _jsx(Text, { color: theme.colors.primary, bold: true, children: "▸ " }) : " ", _jsx(Text, { color: i === ollamaDeletePickerIndex ? theme.colors.primary : undefined, children: m.name }), _jsxs(Text, { color: theme.colors.muted, children: [" (", (m.size / (1024 * 1024 * 1024)).toFixed(1), " GB)"] })] }, m.name))), _jsx(Text, { children: "" }), _jsx(Text, { dimColor: true, children: " ↑↓ navigate · Enter to delete · Esc cancel" })] })), ollamaPullPicker && (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: theme.colors.border, paddingX: 1, marginBottom: 0, children: [_jsx(Text, { bold: true, color: theme.colors.secondary, children: "Download which model?" }), _jsx(Text, { children: "" }), [
|
|
1916
1964
|
{ id: "qwen2.5-coder:7b", name: "Qwen 2.5 Coder 7B", size: "5 GB", desc: "Best balance of speed & quality" },
|
|
1917
1965
|
{ id: "qwen2.5-coder:14b", name: "Qwen 2.5 Coder 14B", size: "9 GB", desc: "Higher quality, needs 16GB+ RAM" },
|
|
1918
|
-
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "
|
|
1966
|
+
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "\u26A0\uFE0F Basic \u2014 may struggle with tool calls" },
|
|
1919
1967
|
{ id: "qwen2.5-coder:32b", name: "Qwen 2.5 Coder 32B", size: "20 GB", desc: "Premium, needs 48GB+" },
|
|
1920
1968
|
{ id: "deepseek-coder-v2:16b", name: "DeepSeek Coder V2", size: "9 GB", desc: "Strong alternative" },
|
|
1921
1969
|
{ id: "codellama:7b", name: "CodeLlama 7B", size: "4 GB", desc: "Meta's coding model" },
|
package/dist/utils/models.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface RecommendedModel {
|
|
|
7
7
|
vramOptimal: number;
|
|
8
8
|
description: string;
|
|
9
9
|
speed: string;
|
|
10
|
-
quality: "good" | "great" | "best";
|
|
10
|
+
quality: "limited" | "good" | "great" | "best";
|
|
11
11
|
}
|
|
12
12
|
export type ModelFit = "perfect" | "good" | "tight" | "skip";
|
|
13
13
|
export interface ScoredModel extends RecommendedModel {
|
package/dist/utils/models.js
CHANGED
|
@@ -6,9 +6,9 @@ const MODELS = [
|
|
|
6
6
|
size: 2,
|
|
7
7
|
ramRequired: 8,
|
|
8
8
|
vramOptimal: 4,
|
|
9
|
-
description: "
|
|
9
|
+
description: "\u26A0\uFE0F May not support tool calling well",
|
|
10
10
|
speed: "~60 tok/s on M1",
|
|
11
|
-
quality: "
|
|
11
|
+
quality: "limited",
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
name: "Qwen 2.5 Coder 7B",
|
|
@@ -84,7 +84,7 @@ function scoreModel(model, ramGB, vramGB) {
|
|
|
84
84
|
return "tight";
|
|
85
85
|
return "skip";
|
|
86
86
|
}
|
|
87
|
-
const qualityOrder = { best: 3, great: 2, good: 1 };
|
|
87
|
+
const qualityOrder = { best: 3, great: 2, good: 1, limited: 0 };
|
|
88
88
|
const fitOrder = { perfect: 4, good: 3, tight: 2, skip: 1 };
|
|
89
89
|
export function getRecommendations(hardware) {
|
|
90
90
|
const ramGB = hardware.ram / (1024 * 1024 * 1024);
|
|
@@ -136,7 +136,9 @@ function mapLlmfitQuality(params_b) {
|
|
|
136
136
|
return "best";
|
|
137
137
|
if (params_b >= 7)
|
|
138
138
|
return "great";
|
|
139
|
-
|
|
139
|
+
if (params_b >= 5)
|
|
140
|
+
return "good";
|
|
141
|
+
return "limited";
|
|
140
142
|
}
|
|
141
143
|
/** Get recommendations using llmfit if available, otherwise fall back to hardcoded list */
|
|
142
144
|
export function getRecommendationsWithLlmfit(hardware) {
|
package/dist/utils/ollama.js
CHANGED
|
@@ -296,7 +296,8 @@ export async function stopOllama() {
|
|
|
296
296
|
/** Delete a model from disk */
|
|
297
297
|
export function deleteModel(modelId) {
|
|
298
298
|
try {
|
|
299
|
-
|
|
299
|
+
const bin = findOllamaBinary();
|
|
300
|
+
execSync(`"${bin}" rm ${modelId}`, { stdio: ["pipe", "pipe", "pipe"], timeout: 30000 });
|
|
300
301
|
return { ok: true, message: `Deleted ${modelId}` };
|
|
301
302
|
}
|
|
302
303
|
catch (err) {
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -215,6 +215,37 @@ function App() {
|
|
|
215
215
|
return () => { pasteEvents.off("paste", handler); };
|
|
216
216
|
}, []);
|
|
217
217
|
|
|
218
|
+
// Refresh the connection banner to reflect current provider status
|
|
219
|
+
const refreshConnectionBanner = useCallback(async () => {
|
|
220
|
+
const info: string[] = [];
|
|
221
|
+
const cliArgs = parseCLIArgs();
|
|
222
|
+
const rawConfig = loadConfig();
|
|
223
|
+
const config = applyOverrides(rawConfig, cliArgs);
|
|
224
|
+
const provider = config.provider;
|
|
225
|
+
|
|
226
|
+
if (provider.model === "auto" || (provider.baseUrl === "http://localhost:1234/v1" && !cliArgs.baseUrl)) {
|
|
227
|
+
const detected = await detectLocalProvider();
|
|
228
|
+
if (detected) {
|
|
229
|
+
info.push(`✔ Connected to ${detected.baseUrl} → ${detected.model}`);
|
|
230
|
+
} else {
|
|
231
|
+
const ollamaUp = await isOllamaRunning();
|
|
232
|
+
info.push(ollamaUp ? "Ollama running (no model loaded)" : "✗ No local LLM server found");
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
info.push(`Provider: ${provider.baseUrl}`);
|
|
236
|
+
info.push(`Model: ${provider.model}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const cwd = process.cwd();
|
|
240
|
+
if (isGitRepo(cwd)) {
|
|
241
|
+
const branch = getBranch(cwd);
|
|
242
|
+
const status = getStatus(cwd);
|
|
243
|
+
info.push(`Git: ${branch} (${status})`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
setConnectionInfo(info);
|
|
247
|
+
}, []);
|
|
248
|
+
|
|
218
249
|
// Connect/reconnect to LLM provider
|
|
219
250
|
const connectToProvider = useCallback(async (isRetry = false) => {
|
|
220
251
|
const cliArgs = parseCLIArgs();
|
|
@@ -708,6 +739,7 @@ function App() {
|
|
|
708
739
|
await new Promise(r => setTimeout(r, 1000));
|
|
709
740
|
if (await isOllamaRunning()) {
|
|
710
741
|
addMsg("info", "Ollama is running.");
|
|
742
|
+
await refreshConnectionBanner();
|
|
711
743
|
return;
|
|
712
744
|
}
|
|
713
745
|
}
|
|
@@ -723,6 +755,7 @@ function App() {
|
|
|
723
755
|
addMsg("info", "Stopping Ollama...");
|
|
724
756
|
const result = await stopOllama();
|
|
725
757
|
addMsg(result.ok ? "info" : "error", result.ok ? `\u2705 ${result.message}` : `\u274C ${result.message}`);
|
|
758
|
+
if (result.ok) await refreshConnectionBanner();
|
|
726
759
|
return;
|
|
727
760
|
}
|
|
728
761
|
if (trimmed === "/ollama pull") {
|
|
@@ -770,7 +803,20 @@ function App() {
|
|
|
770
803
|
return;
|
|
771
804
|
}
|
|
772
805
|
if (trimmed === "/ollama delete") {
|
|
773
|
-
//
|
|
806
|
+
// Ensure Ollama is running so we can list models
|
|
807
|
+
let running = await isOllamaRunning();
|
|
808
|
+
if (!running) {
|
|
809
|
+
addMsg("info", "Starting Ollama to list models...");
|
|
810
|
+
startOllama();
|
|
811
|
+
for (let i = 0; i < 10; i++) {
|
|
812
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
813
|
+
if (await isOllamaRunning()) { running = true; break; }
|
|
814
|
+
}
|
|
815
|
+
if (!running) {
|
|
816
|
+
addMsg("error", "Could not start Ollama. Start it manually first.");
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
774
820
|
const models = await listInstalledModelsDetailed();
|
|
775
821
|
if (models.length === 0) {
|
|
776
822
|
addMsg("info", "No models installed.");
|
|
@@ -1058,7 +1104,7 @@ function App() {
|
|
|
1058
1104
|
|
|
1059
1105
|
setLoading(false);
|
|
1060
1106
|
setStreaming(false);
|
|
1061
|
-
}, [agent, exit]);
|
|
1107
|
+
}, [agent, exit, refreshConnectionBanner]);
|
|
1062
1108
|
|
|
1063
1109
|
useInput((inputChar, key) => {
|
|
1064
1110
|
// Handle slash command navigation
|
|
@@ -1374,7 +1420,7 @@ function App() {
|
|
|
1374
1420
|
const pullModels = [
|
|
1375
1421
|
{ id: "qwen2.5-coder:7b", name: "Qwen 2.5 Coder 7B", size: "5 GB", desc: "Best balance of speed & quality" },
|
|
1376
1422
|
{ id: "qwen2.5-coder:14b", name: "Qwen 2.5 Coder 14B", size: "9 GB", desc: "Higher quality, needs 16GB+ RAM" },
|
|
1377
|
-
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "
|
|
1423
|
+
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "\u26A0\uFE0F Basic \u2014 may struggle with tool calls" },
|
|
1378
1424
|
{ id: "qwen2.5-coder:32b", name: "Qwen 2.5 Coder 32B", size: "20 GB", desc: "Premium quality, needs 48GB+" },
|
|
1379
1425
|
{ id: "deepseek-coder-v2:16b", name: "DeepSeek Coder V2", size: "9 GB", desc: "Strong alternative" },
|
|
1380
1426
|
{ id: "codellama:7b", name: "CodeLlama 7B", size: "4 GB", desc: "Meta's coding model" },
|
|
@@ -2191,7 +2237,7 @@ function App() {
|
|
|
2191
2237
|
{[
|
|
2192
2238
|
{ id: "qwen2.5-coder:7b", name: "Qwen 2.5 Coder 7B", size: "5 GB", desc: "Best balance of speed & quality" },
|
|
2193
2239
|
{ id: "qwen2.5-coder:14b", name: "Qwen 2.5 Coder 14B", size: "9 GB", desc: "Higher quality, needs 16GB+ RAM" },
|
|
2194
|
-
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "
|
|
2240
|
+
{ id: "qwen2.5-coder:3b", name: "Qwen 2.5 Coder 3B", size: "2 GB", desc: "\u26A0\uFE0F Basic \u2014 may struggle with tool calls" },
|
|
2195
2241
|
{ id: "qwen2.5-coder:32b", name: "Qwen 2.5 Coder 32B", size: "20 GB", desc: "Premium, needs 48GB+" },
|
|
2196
2242
|
{ id: "deepseek-coder-v2:16b", name: "DeepSeek Coder V2", size: "9 GB", desc: "Strong alternative" },
|
|
2197
2243
|
{ id: "codellama:7b", name: "CodeLlama 7B", size: "4 GB", desc: "Meta's coding model" },
|
package/src/utils/models.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface RecommendedModel {
|
|
|
9
9
|
vramOptimal: number; // Optimal VRAM in GB (0 = CPU fine)
|
|
10
10
|
description: string; // One-liner
|
|
11
11
|
speed: string; // e.g., "~45 tok/s on M1"
|
|
12
|
-
quality: "good" | "great" | "best";
|
|
12
|
+
quality: "limited" | "good" | "great" | "best";
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export type ModelFit = "perfect" | "good" | "tight" | "skip";
|
|
@@ -25,9 +25,9 @@ const MODELS: RecommendedModel[] = [
|
|
|
25
25
|
size: 2,
|
|
26
26
|
ramRequired: 8,
|
|
27
27
|
vramOptimal: 4,
|
|
28
|
-
description: "
|
|
28
|
+
description: "\u26A0\uFE0F May not support tool calling well",
|
|
29
29
|
speed: "~60 tok/s on M1",
|
|
30
|
-
quality: "
|
|
30
|
+
quality: "limited",
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
name: "Qwen 2.5 Coder 7B",
|
|
@@ -103,7 +103,7 @@ function scoreModel(model: RecommendedModel, ramGB: number, vramGB: number): Mod
|
|
|
103
103
|
return "skip";
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
const qualityOrder: Record<string, number> = { best: 3, great: 2, good: 1 };
|
|
106
|
+
const qualityOrder: Record<string, number> = { best: 3, great: 2, good: 1, limited: 0 };
|
|
107
107
|
const fitOrder: Record<string, number> = { perfect: 4, good: 3, tight: 2, skip: 1 };
|
|
108
108
|
|
|
109
109
|
export function getRecommendations(hardware: HardwareInfo): ScoredModel[] {
|
|
@@ -168,10 +168,11 @@ function mapLlmfitFit(fit: string): ModelFit {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
function mapLlmfitQuality(params_b: number): "good" | "great" | "best" {
|
|
171
|
+
function mapLlmfitQuality(params_b: number): "limited" | "good" | "great" | "best" {
|
|
172
172
|
if (params_b >= 14) return "best";
|
|
173
173
|
if (params_b >= 7) return "great";
|
|
174
|
-
return "good";
|
|
174
|
+
if (params_b >= 5) return "good";
|
|
175
|
+
return "limited";
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
/** Get recommendations using llmfit if available, otherwise fall back to hardcoded list */
|
package/src/utils/ollama.ts
CHANGED
|
@@ -319,7 +319,8 @@ export async function stopOllama(): Promise<{ ok: boolean; message: string }> {
|
|
|
319
319
|
/** Delete a model from disk */
|
|
320
320
|
export function deleteModel(modelId: string): { ok: boolean; message: string } {
|
|
321
321
|
try {
|
|
322
|
-
|
|
322
|
+
const bin = findOllamaBinary();
|
|
323
|
+
execSync(`"${bin}" rm ${modelId}`, { stdio: ["pipe", "pipe", "pipe"], timeout: 30000 });
|
|
323
324
|
return { ok: true, message: `Deleted ${modelId}` };
|
|
324
325
|
} catch (err: any) {
|
|
325
326
|
return { ok: false, message: `Failed to delete ${modelId}: ${err.stderr?.toString().trim() || err.message}` };
|