fix(setup): filter non-chat models and display in multi-column layout

Filter out speech/embed/image/video/audio/tts/asr/ocr/rerank models
from the /models listing. Display remaining models in a responsive
multi-column grid that adapts to terminal width.
This commit is contained in:
2026-05-12 22:09:13 +08:00
parent a92deeaf3f
commit f5612ef1b5
@@ -208,7 +208,12 @@ async function fetchAvailableModels(
if (!Array.isArray(body.data)) { if (!Array.isArray(body.data)) {
return []; return [];
} }
return body.data.map((m) => m.id).sort(); const NON_CHAT_RE =
/speech|embed|image|video|audio|ocr|rerank|tts|asr|paraformer|sambert|cosyvoice|wordart|wanx|wan2|flux|stable-diffusion|z-image|s2s|livetranslate|realtime|gui-/i;
return body.data
.map((m) => m.id)
.filter((id) => !NON_CHAT_RE.test(id))
.sort();
} catch { } catch {
return []; return [];
} }
@@ -247,13 +252,14 @@ async function collectInteractiveSetup(): Promise<Result<SetupCliArgs, string>>
const models = await fetchAvailableModels(baseUrl, apiKey); const models = await fetchAvailableModels(baseUrl, apiKey);
let modelPrompt: string; let modelPrompt: string;
if (models.length > 0) { if (models.length > 0) {
const display = models.slice(0, 20); printCliLine(`Available models (${models.length}):`);
printCliLine(`Available models (${models.length} total):`); const cols = process.stdout.columns || 80;
for (const m of display) { const maxLen = Math.max(...models.map((m) => m.length));
printCliLine(` ${m}`); const colWidth = maxLen + 4;
} const numCols = Math.max(1, Math.floor(cols / colWidth));
if (models.length > 20) { for (let i = 0; i < models.length; i += numCols) {
printCliLine(` ... and ${models.length - 20} more`); const row = models.slice(i, i + numCols);
printCliLine(" " + row.map((m) => m.padEnd(colWidth)).join(""));
} }
modelPrompt = `\nDefault model — format: ${provider}/<model-name>: `; modelPrompt = `\nDefault model — format: ${provider}/<model-name>: `;
} else { } else {