File size: 2,655 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { apiFetch, isServerUp } from "../api.mjs";
import { emit } from "../output.mjs";
import { modelListSchema } from "../schemas/output-schemas.mjs";
import { t } from "../i18n.mjs";

export function registerModels(program) {
  program
    .command("models [provider]")
    .description(t("models.description"))
    .option("--search <query>", t("models.search"))
    .option("--json", "Output as JSON")
    .action(async (provider, opts, cmd) => {
      const globalOpts = cmd.optsWithGlobals();
      const exitCode = await runModelsCommand(provider, { ...opts, output: globalOpts.output });
      if (exitCode !== 0) process.exit(exitCode);
    });
}

export async function runModelsCommand(provider, opts = {}) {
  const serverUp = await isServerUp();
  if (!serverUp) {
    console.error(t("models.noServer"));
    return 1;
  }

  let models = [];

  try {
    const res = await apiFetch("/api/models", { retry: false, timeout: 5000, acceptNotOk: true });
    if (res.ok) {
      const data = await res.json();
      models = Array.isArray(data) ? data : data.models || [];
    }
  } catch {}

  if (models.length === 0) {
    try {
      const res = await apiFetch("/api/v1/models", {
        retry: false,
        timeout: 5000,
        acceptNotOk: true,
      });
      if (res.ok) {
        const data = await res.json();
        models = Array.isArray(data) ? data : data.data || [];
      }
    } catch {}
  }

  if (provider) {
    const filter = provider.toLowerCase();
    models = models.filter(
      (m) =>
        (m.provider && m.provider.toLowerCase().includes(filter)) ||
        (m.id && m.id.toLowerCase().startsWith(filter)) ||
        (m.name && m.name.toLowerCase().includes(filter))
    );
  }

  if (opts.search) {
    const search = opts.search.toLowerCase();
    models = models.filter(
      (m) =>
        (m.id && m.id.toLowerCase().includes(search)) ||
        (m.name && m.name.toLowerCase().includes(search)) ||
        (m.provider && m.provider.toLowerCase().includes(search)) ||
        (m.description && m.description.toLowerCase().includes(search))
    );
  }

  if (models.length === 0) {
    console.log(t("models.noModels"));
    return 0;
  }

  const normalized = models.map((m) => ({
    id: m.id || m.name || "unknown",
    provider: m.provider || "unknown",
    contextWindow: String(m.context_length || m.max_tokens || m.contextWindow || "-"),
  }));

  const display = normalized.slice(0, 50);
  emit(display, opts, modelListSchema);

  if (models.length > 50) {
    console.log(
      `\x1b[2m  ... and ${models.length - 50} more. Use --output json for full list.\x1b[0m`
    );
  }

  return 0;
}