pi-llama-cpp 0.13.0 → 0.15.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 (77) hide show
  1. package/README.md +19 -18
  2. package/package.json +3 -3
  3. package/src/api/client.ts +25 -0
  4. package/src/constants.ts +2 -2
  5. package/src/enums/status.ts +0 -1
  6. package/src/index.ts +2 -1
  7. package/src/interfaces/endpoints/models.ts +1 -1
  8. package/src/interfaces/settings.ts +7 -1
  9. package/src/interfaces/sortBy.ts +4 -0
  10. package/src/managers/command/models.ts +254 -0
  11. package/src/managers/command.ts +34 -461
  12. package/src/managers/events.ts +2 -2
  13. package/src/managers/server.ts +34 -18
  14. package/src/managers/settings.ts +26 -90
  15. package/src/models/baseModel.ts +27 -10
  16. package/src/models/legacyModel.ts +2 -2
  17. package/src/models/routerModel.ts +2 -2
  18. package/src/models/singleModel.ts +1 -1
  19. package/src/server.ts +17 -38
  20. package/src/sse/client.ts +113 -59
  21. package/src/sse/fetch.ts +43 -0
  22. package/src/sse/manager.ts +9 -27
  23. package/src/sse/types.ts +0 -4
  24. package/src/ui/dialog/base.ts +118 -0
  25. package/src/ui/dialog/confirm.ts +45 -0
  26. package/src/ui/dialog/factory.ts +111 -0
  27. package/src/ui/dialog/input.ts +63 -0
  28. package/src/ui/dialog/options.ts +23 -0
  29. package/src/ui/editors/editorOptions.ts +50 -0
  30. package/src/ui/editors/itemBuilder.ts +43 -0
  31. package/src/ui/editors/listEditor.ts +300 -0
  32. package/src/ui/editors/override/entry.ts +24 -0
  33. package/src/ui/editors/override/entryEditor.ts +248 -0
  34. package/src/ui/editors/override/fields/base.ts +53 -0
  35. package/src/ui/editors/override/fields/capabilities.ts +36 -0
  36. package/src/ui/editors/override/fields/cost.ts +64 -0
  37. package/src/ui/editors/override/fields/index.ts +68 -0
  38. package/src/ui/editors/override/fields/numeric.ts +55 -0
  39. package/src/ui/editors/override/fields/pattern.ts +24 -0
  40. package/src/ui/editors/override/fields/reasoning.ts +33 -0
  41. package/src/ui/editors/override/itemBuilder.ts +39 -0
  42. package/src/ui/editors/override/overrideList.ts +127 -0
  43. package/src/ui/editors/server/builder.ts +60 -0
  44. package/src/ui/editors/server/fields.ts +84 -0
  45. package/src/ui/editors/server/itemBuilder.ts +64 -0
  46. package/src/ui/editors/server/serverEditor.ts +197 -0
  47. package/src/ui/editors/server/utils.ts +95 -0
  48. package/src/ui/editors/server/wizard.ts +110 -0
  49. package/src/ui/editors/settingField.ts +37 -0
  50. package/src/ui/editors/settingsListFactory.ts +33 -0
  51. package/src/ui/settings/index.ts +248 -0
  52. package/src/ui/strings.ts +25 -4
  53. package/src/utils/health.ts +2 -1
  54. package/src/utils/serverIds.ts +21 -0
  55. package/src/utils/settingsStore.ts +1 -1
  56. package/src/utils/urlResolver.ts +129 -0
  57. package/src/utils/urls.ts +33 -13
  58. package/tests/{commandManager.test.ts → command/commandManager.test.ts} +88 -12
  59. package/tests/{events.test.ts → events/events.test.ts} +6 -6
  60. package/tests/mocks.ts +2 -0
  61. package/tests/models/legacyModel.test.ts +103 -0
  62. package/tests/{routerModel.test.ts → models/routerModel.test.ts} +71 -72
  63. package/tests/{singleModel.test.ts → models/singleModel.test.ts} +17 -17
  64. package/tests/{health.test.ts → server/health.test.ts} +2 -2
  65. package/tests/{server.test.ts → server/server.test.ts} +5 -17
  66. package/tests/{serverManager.test.ts → server/serverManager.test.ts} +4 -4
  67. package/tests/{settings.test.ts → settings/settings.test.ts} +184 -141
  68. package/tests/{settingsStore.test.ts → settings/settingsStore.test.ts} +1 -1
  69. package/tests/{sseManager.test.ts → sse/sseManager.test.ts} +8 -26
  70. package/tests/{dialog.test.ts → ui/dialog.test.ts} +56 -4
  71. package/tests/{overrides.test.ts → ui/overrides.test.ts} +101 -111
  72. package/src/ui/dialog.ts +0 -290
  73. package/src/ui/overrideEntryEditor.ts +0 -119
  74. package/src/ui/overrideSettingsList.ts +0 -710
  75. package/src/ui/serverListEditor.ts +0 -59
  76. package/src/ui/serverSettingsList.ts +0 -513
  77. package/tests/legacyModel.test.ts +0 -97
@@ -1,10 +1,10 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
- import { THINKING_BUDGETS } from "../src/constants";
3
- import { Status } from "../src/enums/status";
4
- import { EventManager } from "../src/managers/events";
5
- import { ServerManager } from "../src/managers/server";
6
- import type { Server } from "../src/server";
7
- import { createMockModel, createMockServer, makeSettingsStub } from "./mocks";
2
+ import { THINKING_BUDGETS } from "../../src/constants";
3
+ import { Status } from "../../src/enums/status";
4
+ import { EventManager } from "../../src/managers/events";
5
+ import { ServerManager } from "../../src/managers/server";
6
+ import type { Server } from "../../src/server";
7
+ import { createMockModel, createMockServer, makeSettingsStub } from "../mocks";
8
8
 
9
9
  /**
10
10
  * Injected settings stub (EventManager and — in the live-list test — the
package/tests/mocks.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  POLLING_TIMEOUT,
8
8
  REACT_TO_MODEL_SELECT,
9
9
  SERVER_TIMEOUT,
10
+ SHOW_SERVER_URLS,
10
11
  SORT_BY,
11
12
  THINKING_BUDGETS,
12
13
  } from "../src/constants";
@@ -40,6 +41,7 @@ export const makeSettingsStub = (
40
41
  })),
41
42
  resolveServers: vi.fn(async () => []),
42
43
  resolveSortBy: vi.fn(async () => SORT_BY),
44
+ resolveShowServerUrls: vi.fn(async () => SHOW_SERVER_URLS),
43
45
  resolveApiKey: vi.fn(() => API_KEY_PLACEHOLDER),
44
46
  resolveReactToModelSelect: vi.fn(async () => REACT_TO_MODEL_SELECT),
45
47
  resolveAutoloadOnMessage: vi.fn(async () => AUTOLOAD_ON_MESSAGE),
@@ -0,0 +1,103 @@
1
+ import { beforeEach, describe, expect, it } from "vitest";
2
+ import { FALLBACK_CTX } from "../../src/constants";
3
+ import { Mode } from "../../src/enums/mode";
4
+ import { DataProperty } from "../../src/interfaces/endpoints/models";
5
+ import { LegacyModel } from "../../src/models/legacyModel";
6
+ import { createMockServer, mockRpc } from "../mocks";
7
+
8
+ beforeEach(() => {
9
+ mockRpc.mockReset();
10
+ });
11
+
12
+ const createModel = (extra: Partial<DataProperty> = {}): LegacyModel =>
13
+ new LegacyModel(
14
+ {
15
+ id: "test",
16
+ tags: [],
17
+ object: "model",
18
+ owned_by: "test",
19
+ created: Date.now(),
20
+ ...extra,
21
+ },
22
+ createMockServer(),
23
+ );
24
+
25
+ describe("LegacyModel mode", () => {
26
+ it("should always return LEGACY mode", () => {
27
+ const model = createModel();
28
+ expect(model.mode).toBe(Mode.LEGACY);
29
+ });
30
+ });
31
+
32
+ describe("LegacyModel capabilities (via toProviderConfig)", () => {
33
+ it("should detect image capability when multimodal is in capabilities", async () => {
34
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: true } });
35
+ mockRpc.mockResolvedValue({ n_ctx: 4096, data: [{ max_model_len: 8192 }] });
36
+
37
+ const model = createModel();
38
+ const { input } = await model.toProviderConfig();
39
+
40
+ expect(input).toEqual(["text", "image"]);
41
+ });
42
+
43
+ it("should detect text-only capability when multimodal is not in capabilities", async () => {
44
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: false } });
45
+ mockRpc.mockResolvedValue({ n_ctx: 4096, data: [{ max_model_len: 8192 }] });
46
+
47
+ const model = createModel();
48
+ const { input } = await model.toProviderConfig();
49
+
50
+ expect(input).toEqual(["text"]);
51
+ });
52
+
53
+ it("should fall back to text-only when auth fails", async () => {
54
+ mockRpc.mockRejectedValueOnce(new Error("401 Unauthorized")); // /props
55
+ mockRpc.mockRejectedValueOnce(new Error("401 Unauthorized")); // /v1/models in BaseModel's catch
56
+ mockRpc.mockResolvedValue({
57
+ n_ctx: 4096,
58
+ data: [{ max_model_len: 8192 }],
59
+ models: [{ capabilities: ["text"] }],
60
+ });
61
+
62
+ const model = createModel();
63
+ const { input } = await model.toProviderConfig();
64
+
65
+ expect(input).toEqual(["text"]);
66
+ });
67
+ });
68
+
69
+ describe("LegacyModel context size (via toProviderConfig)", () => {
70
+ it("should use max_model_len when it is non-zero", async () => {
71
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: false } }); // capabilities: /props
72
+ mockRpc.mockResolvedValueOnce({ n_ctx: 4096 }); // /props
73
+ mockRpc.mockResolvedValueOnce({ data: [{ max_model_len: 8192 }] }); // /v1/models
74
+
75
+ const model = createModel();
76
+ const { contextWindow } = await model.toProviderConfig();
77
+
78
+ expect(contextWindow).toBe(8192);
79
+ expect(mockRpc).toHaveBeenCalledWith("/v1/models");
80
+ });
81
+
82
+ it("should fall back to n_ctx when max_model_len is 0", async () => {
83
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: false } }); // capabilities: /props
84
+ mockRpc.mockResolvedValueOnce({ n_ctx: 4096 }); // /props
85
+ mockRpc.mockResolvedValueOnce({ data: [{ max_model_len: 0 }] }); // /v1/models
86
+
87
+ const model = createModel();
88
+ const { contextWindow } = await model.toProviderConfig();
89
+
90
+ expect(contextWindow).toBe(4096);
91
+ });
92
+
93
+ it("should return FALLBACK_CTX when both values are missing/null", async () => {
94
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: false } }); // capabilities: /props
95
+ mockRpc.mockResolvedValueOnce({}); // /props
96
+ mockRpc.mockResolvedValueOnce({ data: [{ max_model_len: null }] }); // /v1/models
97
+
98
+ const model = createModel();
99
+ const { contextWindow } = await model.toProviderConfig();
100
+
101
+ expect(contextWindow).toBe(FALLBACK_CTX);
102
+ });
103
+ });
@@ -1,8 +1,9 @@
1
1
  import { beforeEach, describe, expect, it } from "vitest";
2
- import { Mode } from "../src/enums/mode";
3
- import { DataProperty } from "../src/interfaces/endpoints/models";
4
- import { RouterModel } from "../src/models/routerModel";
5
- import { createMockServer, mockRpc } from "./mocks";
2
+ import { FALLBACK_CTX } from "../../src/constants";
3
+ import { Mode } from "../../src/enums/mode";
4
+ import { DataProperty } from "../../src/interfaces/endpoints/models";
5
+ import { RouterModel } from "../../src/models/routerModel";
6
+ import { createMockServer, mockRpc } from "../mocks";
6
7
 
7
8
  // Helper to create a mock DataProperty
8
9
  const createModel = (overrides: Partial<DataProperty> = {}): DataProperty => ({
@@ -20,12 +21,21 @@ beforeEach(() => {
20
21
  mockRpc.mockClear();
21
22
  });
22
23
 
23
- describe("RouterModel context size extraction", () => {
24
- it("should extract --ctx-size value", () => {
24
+ describe("RouterModel context size (via toProviderConfig)", () => {
25
+ /** Mocks for an unloaded model: capabilities detection fails (text-only),
26
+ * then the status probe fails so context size falls back to CLI args. */
27
+ const mockUnloaded = () => {
28
+ mockRpc.mockRejectedValueOnce(new Error("props not available")); // capabilities: /props
29
+ mockRpc.mockResolvedValueOnce({ data: [] }); // capabilities: /v1/models
30
+ mockRpc.mockRejectedValueOnce(new Error("props not available")); // status: /props
31
+ };
32
+
33
+ it("should extract --ctx-size when unloaded", async () => {
34
+ mockUnloaded();
25
35
  const model = new RouterModel(
26
36
  createModel({
27
37
  status: {
28
- value: "loaded",
38
+ value: "unloaded",
29
39
  args: [
30
40
  "--model",
31
41
  "gguf",
@@ -40,16 +50,17 @@ describe("RouterModel context size extraction", () => {
40
50
  createMockServer(),
41
51
  );
42
52
 
43
- // Access the private method via any
44
- const extractFrom = (model as any).extractFrom.bind(model);
45
- expect(extractFrom("--ctx-size")).toBe(4096);
53
+ const { contextWindow } = await model.toProviderConfig();
54
+
55
+ expect(contextWindow).toBe(4096);
46
56
  });
47
57
 
48
- it("should extract --fit-ctx value when --ctx-size is not present", () => {
58
+ it("should fall back to --fit-ctx when --ctx-size is not present", async () => {
59
+ mockUnloaded();
49
60
  const model = new RouterModel(
50
61
  createModel({
51
62
  status: {
52
- value: "loaded",
63
+ value: "unloaded",
53
64
  args: ["--model", "gguf", "--fit-ctx", "8192"],
54
65
  preset: "default",
55
66
  },
@@ -57,91 +68,87 @@ describe("RouterModel context size extraction", () => {
57
68
  createMockServer(),
58
69
  );
59
70
 
60
- const extractFrom = (model as any).extractFrom.bind(model);
61
- expect(extractFrom("--fit-ctx")).toBe(8192);
71
+ const { contextWindow } = await model.toProviderConfig();
72
+
73
+ expect(contextWindow).toBe(8192);
62
74
  });
63
75
 
64
- it("should return null when argument is not found", () => {
76
+ it("should prefer --ctx-size over --fit-ctx", async () => {
77
+ mockUnloaded();
65
78
  const model = new RouterModel(
66
79
  createModel({
67
80
  status: {
68
- value: "loaded",
69
- args: ["--model", "gguf", "--batch-size", "512"],
81
+ value: "unloaded",
82
+ args: ["--model", "gguf", "--ctx-size", "4096", "--fit-ctx", "8192"],
70
83
  preset: "default",
71
84
  },
72
85
  }),
73
86
  createMockServer(),
74
87
  );
75
88
 
76
- const extractFrom = (model as any).extractFrom.bind(model);
77
- expect(extractFrom("--ctx-size")).toBeNull();
78
- expect(extractFrom("--fit-ctx")).toBeNull();
89
+ const { contextWindow } = await model.toProviderConfig();
90
+
91
+ expect(contextWindow).toBe(4096);
79
92
  });
80
93
 
81
- it("should return null when argument has no following value", () => {
94
+ it("should fall back to FALLBACK_CTX when no size argument is present", async () => {
95
+ mockUnloaded();
82
96
  const model = new RouterModel(
83
97
  createModel({
84
98
  status: {
85
- value: "loaded",
86
- args: ["--model", "gguf", "--ctx-size"],
99
+ value: "unloaded",
100
+ args: ["--model", "gguf", "--batch-size", "512"],
87
101
  preset: "default",
88
102
  },
89
103
  }),
90
104
  createMockServer(),
91
105
  );
92
106
 
93
- const extractFrom = (model as any).extractFrom.bind(model);
94
- expect(extractFrom("--ctx-size")).toBeNull();
107
+ const { contextWindow } = await model.toProviderConfig();
108
+
109
+ expect(contextWindow).toBe(FALLBACK_CTX);
95
110
  });
96
111
 
97
- it("should return null when argument value is not a valid number", () => {
112
+ it("should fall back to FALLBACK_CTX when the argument has no following value", async () => {
113
+ mockUnloaded();
98
114
  const model = new RouterModel(
99
115
  createModel({
100
116
  status: {
101
- value: "loaded",
102
- args: ["--model", "gguf", "--ctx-size", "not-a-number"],
117
+ value: "unloaded",
118
+ args: ["--model", "gguf", "--ctx-size"],
103
119
  preset: "default",
104
120
  },
105
121
  }),
106
122
  createMockServer(),
107
123
  );
108
124
 
109
- const extractFrom = (model as any).extractFrom.bind(model);
110
- expect(extractFrom("--ctx-size")).toBeNull();
111
- });
125
+ const { contextWindow } = await model.toProviderConfig();
112
126
 
113
- it("should prefer --ctx-size over --fit-ctx when loaded", async () => {
114
- // First call: getStatus() -> fetchModelProps
115
- mockRpc.mockResolvedValueOnce({ is_sleeping: false });
116
- // Second call: super.getContextSize() -> fetchModels with meta.n_ctx
117
- mockRpc.mockResolvedValueOnce({
118
- data: [
119
- {
120
- id: "test-model",
121
- meta: { n_ctx: 4096 },
122
- },
123
- ],
124
- });
127
+ expect(contextWindow).toBe(FALLBACK_CTX);
128
+ });
125
129
 
130
+ it("should fall back to FALLBACK_CTX when the argument value is not a valid number", async () => {
131
+ mockUnloaded();
126
132
  const model = new RouterModel(
127
133
  createModel({
128
134
  status: {
129
- value: "loaded",
130
- args: ["--model", "gguf", "--ctx-size", "4096", "--fit-ctx", "8192"],
135
+ value: "unloaded",
136
+ args: ["--model", "gguf", "--ctx-size", "not-a-number"],
131
137
  preset: "default",
132
138
  },
133
139
  }),
134
140
  createMockServer(),
135
141
  );
136
142
 
137
- const ctxSize = await model.getContextSize();
138
- expect(ctxSize).toBe(4096);
143
+ const { contextWindow } = await model.toProviderConfig();
144
+
145
+ expect(contextWindow).toBe(FALLBACK_CTX);
139
146
  });
140
147
 
141
- it("should return n_ctx from meta when loaded without context size args", async () => {
142
- // First call: getStatus() -> fetchModelProps
143
- mockRpc.mockResolvedValueOnce({ is_sleeping: false });
144
- // Second call: super.getContextSize() -> fetchModels with meta.n_ctx
148
+ it("should return n_ctx from meta when loaded", async () => {
149
+ mockRpc.mockResolvedValueOnce({ modalities: { vision: false } }); // capabilities: /props
150
+ mockRpc.mockResolvedValueOnce({ is_sleeping: false }); // status: /props
151
+ // super.getContextSize() -> fetchModels with meta.n_ctx
145
152
  mockRpc.mockResolvedValueOnce({
146
153
  data: [
147
154
  {
@@ -151,30 +158,22 @@ describe("RouterModel context size extraction", () => {
151
158
  ],
152
159
  });
153
160
 
154
- const model = new RouterModel(
155
- createModel({
156
- status: {
157
- value: "loaded",
158
- args: ["--model", "gguf"],
159
- preset: "default",
160
- },
161
- }),
162
- createMockServer(),
163
- );
161
+ const model = new RouterModel(createModel(), createMockServer());
162
+
163
+ const { contextWindow } = await model.toProviderConfig();
164
164
 
165
- const ctxSize = await model.getContextSize();
166
- expect(ctxSize).toBe(4096);
165
+ expect(contextWindow).toBe(4096);
167
166
  });
168
167
  });
169
168
 
170
- describe("RouterModel capabilities detection", () => {
169
+ describe("RouterModel capabilities detection (via toProviderConfig)", () => {
171
170
  it("should detect image capability when modalities.vision is true", async () => {
172
171
  mockRpc.mockResolvedValueOnce({ modalities: { vision: true } });
173
172
 
174
173
  const model = new RouterModel(createModel(), createMockServer());
175
- const capabilities = await model.getCapabilities();
174
+ const { input } = await model.toProviderConfig();
176
175
 
177
- expect(capabilities).toEqual(["text", "image"]);
176
+ expect(input).toEqual(["text", "image"]);
178
177
  expect(mockRpc).toHaveBeenCalledWith(
179
178
  "/props?model=test-model&autoload=false",
180
179
  );
@@ -187,9 +186,9 @@ describe("RouterModel capabilities detection", () => {
187
186
  mockRpc.mockResolvedValueOnce({ data: [] });
188
187
 
189
188
  const model = new RouterModel(createModel(), createMockServer());
190
- const capabilities = await model.getCapabilities();
189
+ const { input } = await model.toProviderConfig();
191
190
 
192
- expect(capabilities).toEqual(["text"]);
191
+ expect(input).toEqual(["text"]);
193
192
  });
194
193
 
195
194
  it("should detect text-only capability when only text in input_modalities", async () => {
@@ -215,9 +214,9 @@ describe("RouterModel capabilities detection", () => {
215
214
  });
216
215
 
217
216
  const model = new RouterModel(createModel(), createMockServer());
218
- const capabilities = await model.getCapabilities();
217
+ const { input } = await model.toProviderConfig();
219
218
 
220
- expect(capabilities).toEqual(["text"]);
219
+ expect(input).toEqual(["text"]);
221
220
  });
222
221
 
223
222
  it("should return text when model not found in /models response", async () => {
@@ -239,9 +238,9 @@ describe("RouterModel capabilities detection", () => {
239
238
  });
240
239
 
241
240
  const model = new RouterModel(createModel(), createMockServer());
242
- const capabilities = await model.getCapabilities();
241
+ const { input } = await model.toProviderConfig();
243
242
 
244
- expect(capabilities).toEqual(["text"]);
243
+ expect(input).toEqual(["text"]);
245
244
  });
246
245
  });
247
246
 
@@ -1,9 +1,9 @@
1
1
  import { beforeEach, describe, expect, it } from "vitest";
2
- import { Mode } from "../src/enums/mode";
3
- import { Status } from "../src/enums/status";
4
- import { DataProperty } from "../src/interfaces/endpoints/models";
5
- import { SingleModel } from "../src/models/singleModel";
6
- import { createMockServer, mockRpc } from "./mocks";
2
+ import { Mode } from "../../src/enums/mode";
3
+ import { Status } from "../../src/enums/status";
4
+ import { DataProperty } from "../../src/interfaces/endpoints/models";
5
+ import { SingleModel } from "../../src/models/singleModel";
6
+ import { createMockServer, mockRpc } from "../mocks";
7
7
 
8
8
  beforeEach(() => {
9
9
  mockRpc.mockReset();
@@ -29,23 +29,23 @@ describe("SingleModel mode", () => {
29
29
  });
30
30
  });
31
31
 
32
- describe("SingleModel capabilities", () => {
32
+ describe("SingleModel capabilities (via toProviderConfig)", () => {
33
33
  it("should detect image capability when multimodal is in capabilities", async () => {
34
34
  mockRpc.mockResolvedValueOnce({ modalities: { vision: true } });
35
35
 
36
36
  const model = createModel();
37
- const capabilities = await model.getCapabilities();
37
+ const { input } = await model.toProviderConfig();
38
38
 
39
- expect(capabilities).toEqual(["text", "image"]);
39
+ expect(input).toEqual(["text", "image"]);
40
40
  });
41
41
 
42
42
  it("should detect text-only capability when multimodal is not in capabilities", async () => {
43
43
  mockRpc.mockResolvedValueOnce({ modalities: { vision: false } });
44
44
 
45
45
  const model = createModel();
46
- const capabilities = await model.getCapabilities();
46
+ const { input } = await model.toProviderConfig();
47
47
 
48
- expect(capabilities).toEqual(["text"]);
48
+ expect(input).toEqual(["text"]);
49
49
  });
50
50
 
51
51
  it("should fall back to the models endpoint when auth fails", async () => {
@@ -59,9 +59,9 @@ describe("SingleModel capabilities", () => {
59
59
  }); // /v1/models retry in SingleModel's catch
60
60
 
61
61
  const model = createModel();
62
- const capabilities = await model.getCapabilities();
62
+ const { input } = await model.toProviderConfig();
63
63
 
64
- expect(capabilities).toEqual(["text", "image"]);
64
+ expect(input).toEqual(["text", "image"]);
65
65
  });
66
66
 
67
67
  it("should fall back to text-only when the models endpoint reports no multimodal", async () => {
@@ -75,9 +75,9 @@ describe("SingleModel capabilities", () => {
75
75
  }); // /v1/models retry in SingleModel's catch
76
76
 
77
77
  const model = createModel();
78
- const capabilities = await model.getCapabilities();
78
+ const { input } = await model.toProviderConfig();
79
79
 
80
- expect(capabilities).toEqual(["text"]);
80
+ expect(input).toEqual(["text"]);
81
81
  });
82
82
  });
83
83
 
@@ -104,16 +104,16 @@ describe("SingleModel getStatus", () => {
104
104
  });
105
105
  });
106
106
 
107
- describe("SingleModel getContextSize", () => {
107
+ describe("SingleModel context size (via toProviderConfig)", () => {
108
108
  it("should return n_ctx from /v1/models endpoint meta", async () => {
109
109
  mockRpc.mockResolvedValue({
110
110
  data: [{ id: "test", meta: { n_ctx: 8192 } }],
111
111
  });
112
112
 
113
113
  const model = createModel();
114
- const ctxSize = await model.getContextSize();
114
+ const { contextWindow } = await model.toProviderConfig();
115
115
 
116
- expect(ctxSize).toBe(8192);
116
+ expect(contextWindow).toBe(8192);
117
117
  expect(mockRpc).toHaveBeenCalledWith("/v1/models");
118
118
  });
119
119
  });
@@ -1,6 +1,6 @@
1
1
  import { afterEach, describe, expect, it, vi } from "vitest";
2
- import { ServerStatus } from "../src/enums/serverStatus";
3
- import { checkServerHealth } from "../src/utils/health";
2
+ import { ServerStatus } from "../../src/enums/serverStatus";
3
+ import { checkServerHealth } from "../../src/utils/health";
4
4
 
5
5
  /**
6
6
  * Stubs `global.fetch` for one test. The probe only reads the parsed body,
@@ -1,9 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
- import { POLLING_TIMEOUT, SERVER_TIMEOUT } from "../src/constants";
3
- import { ServerStatus } from "../src/enums/serverStatus";
4
- import type { LlamaSettingsManager } from "../src/managers/settings";
5
- import { Server } from "../src/server";
6
- import { createMockServer, makeSettingsStub, mockRpc } from "./mocks";
2
+ import { POLLING_TIMEOUT, SERVER_TIMEOUT } from "../../src/constants";
3
+ import { ServerStatus } from "../../src/enums/serverStatus";
4
+ import type { LlamaSettingsManager } from "../../src/managers/settings";
5
+ import { Server } from "../../src/server";
6
+ import { createMockServer, makeSettingsStub, mockRpc } from "../mocks";
7
7
 
8
8
  // Injected into every real Server below; fresh per test so per-case
9
9
  // overrides never leak. The Server constructor resolves the API key eagerly
@@ -107,18 +107,6 @@ describe("Server fetchModelProps", () => {
107
107
  });
108
108
  });
109
109
 
110
- describe("Server fetchServerHealth", () => {
111
- it("should call the /health endpoint", async () => {
112
- mockRpc.mockResolvedValueOnce({ status: "ok" });
113
-
114
- const server = createMockServer();
115
- const result = await server.fetchServerHealth();
116
-
117
- expect(result).toEqual({ status: "ok" });
118
- expect(mockRpc).toHaveBeenCalledWith("/health");
119
- });
120
- });
121
-
122
110
  describe("Server fetchServerProps", () => {
123
111
  it("should call the /props endpoint without model", async () => {
124
112
  mockRpc.mockResolvedValueOnce({
@@ -1,13 +1,13 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
- import { ServerManager } from "../src/managers/server";
3
- import { BaseModel } from "../src/models/baseModel";
4
- import { Server } from "../src/server";
2
+ import { ServerManager } from "../../src/managers/server";
3
+ import { BaseModel } from "../../src/models/baseModel";
4
+ import { Server } from "../../src/server";
5
5
  import {
6
6
  createMockModel,
7
7
  createMockServer,
8
8
  makeSettingsStub,
9
9
  mockRpc,
10
- } from "./mocks";
10
+ } from "../mocks";
11
11
 
12
12
  // Injected settings stub — the single instance passed to ServerManager and
13
13
  // to every real `new Server(...)` construction below (Server's eager