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.
- package/README.md +19 -18
- package/package.json +3 -3
- package/src/api/client.ts +25 -0
- package/src/constants.ts +2 -2
- package/src/enums/status.ts +0 -1
- package/src/index.ts +2 -1
- package/src/interfaces/endpoints/models.ts +1 -1
- package/src/interfaces/settings.ts +7 -1
- package/src/interfaces/sortBy.ts +4 -0
- package/src/managers/command/models.ts +254 -0
- package/src/managers/command.ts +34 -461
- package/src/managers/events.ts +2 -2
- package/src/managers/server.ts +34 -18
- package/src/managers/settings.ts +26 -90
- package/src/models/baseModel.ts +27 -10
- package/src/models/legacyModel.ts +2 -2
- package/src/models/routerModel.ts +2 -2
- package/src/models/singleModel.ts +1 -1
- package/src/server.ts +17 -38
- package/src/sse/client.ts +113 -59
- package/src/sse/fetch.ts +43 -0
- package/src/sse/manager.ts +9 -27
- package/src/sse/types.ts +0 -4
- package/src/ui/dialog/base.ts +118 -0
- package/src/ui/dialog/confirm.ts +45 -0
- package/src/ui/dialog/factory.ts +111 -0
- package/src/ui/dialog/input.ts +63 -0
- package/src/ui/dialog/options.ts +23 -0
- package/src/ui/editors/editorOptions.ts +50 -0
- package/src/ui/editors/itemBuilder.ts +43 -0
- package/src/ui/editors/listEditor.ts +300 -0
- package/src/ui/editors/override/entry.ts +24 -0
- package/src/ui/editors/override/entryEditor.ts +248 -0
- package/src/ui/editors/override/fields/base.ts +53 -0
- package/src/ui/editors/override/fields/capabilities.ts +36 -0
- package/src/ui/editors/override/fields/cost.ts +64 -0
- package/src/ui/editors/override/fields/index.ts +68 -0
- package/src/ui/editors/override/fields/numeric.ts +55 -0
- package/src/ui/editors/override/fields/pattern.ts +24 -0
- package/src/ui/editors/override/fields/reasoning.ts +33 -0
- package/src/ui/editors/override/itemBuilder.ts +39 -0
- package/src/ui/editors/override/overrideList.ts +127 -0
- package/src/ui/editors/server/builder.ts +60 -0
- package/src/ui/editors/server/fields.ts +84 -0
- package/src/ui/editors/server/itemBuilder.ts +64 -0
- package/src/ui/editors/server/serverEditor.ts +197 -0
- package/src/ui/editors/server/utils.ts +95 -0
- package/src/ui/editors/server/wizard.ts +110 -0
- package/src/ui/editors/settingField.ts +37 -0
- package/src/ui/editors/settingsListFactory.ts +33 -0
- package/src/ui/settings/index.ts +248 -0
- package/src/ui/strings.ts +25 -4
- package/src/utils/health.ts +2 -1
- package/src/utils/serverIds.ts +21 -0
- package/src/utils/settingsStore.ts +1 -1
- package/src/utils/urlResolver.ts +129 -0
- package/src/utils/urls.ts +33 -13
- package/tests/{commandManager.test.ts → command/commandManager.test.ts} +88 -12
- package/tests/{events.test.ts → events/events.test.ts} +6 -6
- package/tests/mocks.ts +2 -0
- package/tests/models/legacyModel.test.ts +103 -0
- package/tests/{routerModel.test.ts → models/routerModel.test.ts} +71 -72
- package/tests/{singleModel.test.ts → models/singleModel.test.ts} +17 -17
- package/tests/{health.test.ts → server/health.test.ts} +2 -2
- package/tests/{server.test.ts → server/server.test.ts} +5 -17
- package/tests/{serverManager.test.ts → server/serverManager.test.ts} +4 -4
- package/tests/{settings.test.ts → settings/settings.test.ts} +184 -141
- package/tests/{settingsStore.test.ts → settings/settingsStore.test.ts} +1 -1
- package/tests/{sseManager.test.ts → sse/sseManager.test.ts} +8 -26
- package/tests/{dialog.test.ts → ui/dialog.test.ts} +56 -4
- package/tests/{overrides.test.ts → ui/overrides.test.ts} +101 -111
- package/src/ui/dialog.ts +0 -290
- package/src/ui/overrideEntryEditor.ts +0 -119
- package/src/ui/overrideSettingsList.ts +0 -710
- package/src/ui/serverListEditor.ts +0 -59
- package/src/ui/serverSettingsList.ts +0 -513
- package/tests/legacyModel.test.ts +0 -97
|
@@ -6,12 +6,17 @@ import {
|
|
|
6
6
|
POLLING_TIMEOUT,
|
|
7
7
|
PROVIDER_PREFIX,
|
|
8
8
|
SERVER_TIMEOUT,
|
|
9
|
-
} from "
|
|
10
|
-
import type { ModelOverride } from "
|
|
11
|
-
import {
|
|
12
|
-
|
|
9
|
+
} from "../../src/constants";
|
|
10
|
+
import type { ModelOverride } from "../../src/interfaces/settings";
|
|
11
|
+
import {
|
|
12
|
+
createSettingsManager,
|
|
13
|
+
type LlamaSettingsManager,
|
|
14
|
+
} from "../../src/managers/settings";
|
|
15
|
+
import { Server } from "../../src/server";
|
|
16
|
+
|
|
17
|
+
let manager: LlamaSettingsManager;
|
|
13
18
|
|
|
14
|
-
// Hoisted mock instances
|
|
19
|
+
// Hoisted mock instances
|
|
15
20
|
const mockReadStoredCredential = vi.hoisted(() => vi.fn());
|
|
16
21
|
|
|
17
22
|
const mockSettingsManager = vi.hoisted(() => ({
|
|
@@ -54,7 +59,6 @@ describe("URL resolution fallback chain", () => {
|
|
|
54
59
|
|
|
55
60
|
afterEach(() => {
|
|
56
61
|
delete process.env.LLAMA_SERVER_URL;
|
|
57
|
-
vi.resetModules();
|
|
58
62
|
});
|
|
59
63
|
|
|
60
64
|
beforeEach(() => {
|
|
@@ -63,13 +67,14 @@ describe("URL resolution fallback chain", () => {
|
|
|
63
67
|
// Default: no settings found
|
|
64
68
|
mockGetProjectSettings.mockReturnValue({});
|
|
65
69
|
mockGetGlobalSettings.mockReturnValue({});
|
|
70
|
+
manager = createSettingsManager();
|
|
66
71
|
});
|
|
67
72
|
|
|
68
73
|
it("should return default URL when no config is found", async () => {
|
|
69
74
|
// Ensure env var is not set (and not inherited from environment)
|
|
70
75
|
delete process.env.LLAMA_SERVER_URL;
|
|
71
76
|
|
|
72
|
-
const result = await
|
|
77
|
+
const result = await manager.resolveUrls();
|
|
73
78
|
|
|
74
79
|
expect(result).toEqual([LLAMA_SERVER_URL]);
|
|
75
80
|
});
|
|
@@ -80,7 +85,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
80
85
|
});
|
|
81
86
|
process.env.LLAMA_SERVER_URL = "http://env-url:8080";
|
|
82
87
|
|
|
83
|
-
const result = await
|
|
88
|
+
const result = await manager.resolveUrls();
|
|
84
89
|
|
|
85
90
|
expect(result).toEqual(["http://env-url:8080"]);
|
|
86
91
|
});
|
|
@@ -88,7 +93,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
88
93
|
it("should use env variable when no other config exists", async () => {
|
|
89
94
|
process.env.LLAMA_SERVER_URL = "http://env-url:8080";
|
|
90
95
|
|
|
91
|
-
const result = await
|
|
96
|
+
const result = await manager.resolveUrls();
|
|
92
97
|
|
|
93
98
|
expect(result).toEqual(["http://env-url:8080"]);
|
|
94
99
|
});
|
|
@@ -98,7 +103,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
98
103
|
llamaServerUrl: "http://project:9999",
|
|
99
104
|
});
|
|
100
105
|
|
|
101
|
-
const result = await
|
|
106
|
+
const result = await manager.resolveUrls();
|
|
102
107
|
|
|
103
108
|
expect(result).toEqual(["http://project:9999"]);
|
|
104
109
|
});
|
|
@@ -108,7 +113,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
108
113
|
llamaServerUrl: "http://global:8080",
|
|
109
114
|
});
|
|
110
115
|
|
|
111
|
-
const result = await
|
|
116
|
+
const result = await manager.resolveUrls();
|
|
112
117
|
|
|
113
118
|
expect(result).toEqual(["http://global:8080"]);
|
|
114
119
|
});
|
|
@@ -116,7 +121,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
116
121
|
it("should strip trailing slashes from resolved URL", async () => {
|
|
117
122
|
process.env.LLAMA_SERVER_URL = "http://localhost:8080/";
|
|
118
123
|
|
|
119
|
-
const result = await
|
|
124
|
+
const result = await manager.resolveUrls();
|
|
120
125
|
|
|
121
126
|
expect(result).toEqual(["http://localhost:8080"]);
|
|
122
127
|
});
|
|
@@ -124,8 +129,8 @@ describe("URL resolution fallback chain", () => {
|
|
|
124
129
|
it("should cache the resolved URL on subsequent calls", async () => {
|
|
125
130
|
process.env.LLAMA_SERVER_URL = "http://first:8080";
|
|
126
131
|
|
|
127
|
-
const result1 = await
|
|
128
|
-
const result2 = await
|
|
132
|
+
const result1 = await manager.resolveUrls();
|
|
133
|
+
const result2 = await manager.resolveUrls();
|
|
129
134
|
|
|
130
135
|
expect(result1).toEqual(["http://first:8080"]);
|
|
131
136
|
expect(result2).toEqual(["http://first:8080"]);
|
|
@@ -134,7 +139,7 @@ describe("URL resolution fallback chain", () => {
|
|
|
134
139
|
it("should handle multiple URLs separated by semicolons", async () => {
|
|
135
140
|
process.env.LLAMA_SERVER_URL = "http://first:8080;http://second:9090/";
|
|
136
141
|
|
|
137
|
-
const result = await
|
|
142
|
+
const result = await manager.resolveUrls();
|
|
138
143
|
|
|
139
144
|
expect(result).toEqual(["http://first:8080", "http://second:9090"]);
|
|
140
145
|
});
|
|
@@ -142,13 +147,14 @@ describe("URL resolution fallback chain", () => {
|
|
|
142
147
|
it("should drop env URLs without an http(s) scheme, warn, and fall through", async () => {
|
|
143
148
|
process.env.LLAMA_SERVER_URL = "127.0.0.1:8080";
|
|
144
149
|
|
|
145
|
-
const
|
|
150
|
+
const manager = createSettingsManager();
|
|
151
|
+
const result = await manager.resolveUrls();
|
|
146
152
|
|
|
147
153
|
expect(result).toEqual([LLAMA_SERVER_URL]);
|
|
148
|
-
expect(
|
|
154
|
+
expect(manager.takeWarnings()).toEqual([
|
|
149
155
|
"Ignoring invalid server URL '127.0.0.1:8080' (needs http(s)://)",
|
|
150
156
|
]);
|
|
151
|
-
expect(
|
|
157
|
+
expect(manager.takeWarnings()).toEqual([]); // drained
|
|
152
158
|
});
|
|
153
159
|
|
|
154
160
|
it("should drop server entries without an http(s) scheme and warn", async () => {
|
|
@@ -158,13 +164,14 @@ describe("URL resolution fallback chain", () => {
|
|
|
158
164
|
},
|
|
159
165
|
});
|
|
160
166
|
|
|
161
|
-
const
|
|
167
|
+
const manager = createSettingsManager();
|
|
168
|
+
const result = await manager.resolveUrls();
|
|
162
169
|
|
|
163
170
|
expect(result).toEqual(["http://good:8080"]);
|
|
164
|
-
expect(
|
|
171
|
+
expect(manager.takeWarnings()).toEqual([
|
|
165
172
|
"Ignoring invalid server URL '127.0.0.1:8080' (needs http(s)://)",
|
|
166
173
|
]);
|
|
167
|
-
expect(
|
|
174
|
+
expect(manager.takeWarnings()).toEqual([]); // drained
|
|
168
175
|
});
|
|
169
176
|
});
|
|
170
177
|
|
|
@@ -179,7 +186,6 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
179
186
|
|
|
180
187
|
afterEach(() => {
|
|
181
188
|
delete process.env.LLAMA_SERVER_URL;
|
|
182
|
-
vi.resetModules();
|
|
183
189
|
});
|
|
184
190
|
|
|
185
191
|
beforeEach(() => {
|
|
@@ -187,6 +193,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
187
193
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
188
194
|
mockGetProjectSettings.mockReturnValue({});
|
|
189
195
|
mockGetGlobalSettings.mockReturnValue({});
|
|
196
|
+
manager = createSettingsManager();
|
|
190
197
|
});
|
|
191
198
|
|
|
192
199
|
it("should resolve URLs from llamaSettings.servers in project config", async () => {
|
|
@@ -199,7 +206,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
199
206
|
},
|
|
200
207
|
});
|
|
201
208
|
|
|
202
|
-
const result = await
|
|
209
|
+
const result = await manager.resolveUrls();
|
|
203
210
|
|
|
204
211
|
expect(result).toEqual([
|
|
205
212
|
"http://project-server:8080",
|
|
@@ -219,7 +226,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
219
226
|
},
|
|
220
227
|
});
|
|
221
228
|
|
|
222
|
-
const result = await
|
|
229
|
+
const result = await manager.resolveUrls();
|
|
223
230
|
|
|
224
231
|
expect(result).toEqual(["http://project:8080"]);
|
|
225
232
|
});
|
|
@@ -231,7 +238,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
231
238
|
},
|
|
232
239
|
});
|
|
233
240
|
|
|
234
|
-
const result = await
|
|
241
|
+
const result = await manager.resolveUrls();
|
|
235
242
|
|
|
236
243
|
expect(result).toEqual(["http://global:8080"]);
|
|
237
244
|
});
|
|
@@ -244,7 +251,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
244
251
|
},
|
|
245
252
|
});
|
|
246
253
|
|
|
247
|
-
const result = await
|
|
254
|
+
const result = await manager.resolveUrls();
|
|
248
255
|
|
|
249
256
|
expect(result).toEqual(["http://env:8080"]);
|
|
250
257
|
});
|
|
@@ -256,7 +263,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
256
263
|
},
|
|
257
264
|
});
|
|
258
265
|
|
|
259
|
-
const result = await
|
|
266
|
+
const result = await manager.resolveUrls();
|
|
260
267
|
|
|
261
268
|
expect(result).toEqual(["http://server:9090"]);
|
|
262
269
|
});
|
|
@@ -269,7 +276,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
269
276
|
},
|
|
270
277
|
});
|
|
271
278
|
|
|
272
|
-
const result = await
|
|
279
|
+
const result = await manager.resolveUrls();
|
|
273
280
|
|
|
274
281
|
expect(result).toEqual(["http://server:9090"]);
|
|
275
282
|
});
|
|
@@ -282,7 +289,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
282
289
|
},
|
|
283
290
|
});
|
|
284
291
|
|
|
285
|
-
const result = await
|
|
292
|
+
const result = await manager.resolveUrls();
|
|
286
293
|
|
|
287
294
|
expect(result).toEqual(["http://legacy:8080"]);
|
|
288
295
|
});
|
|
@@ -294,7 +301,7 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
294
301
|
},
|
|
295
302
|
});
|
|
296
303
|
|
|
297
|
-
const result = await
|
|
304
|
+
const result = await manager.resolveUrls();
|
|
298
305
|
|
|
299
306
|
expect(result).toEqual(["http://localhost:8080"]);
|
|
300
307
|
});
|
|
@@ -303,20 +310,19 @@ describe("llamaSettings.servers resolution", () => {
|
|
|
303
310
|
describe("API key resolution", () => {
|
|
304
311
|
const mockGetAgentDir = vi.mocked(getAgentDir);
|
|
305
312
|
|
|
306
|
-
afterEach(() => {
|
|
307
|
-
vi.resetModules();
|
|
308
|
-
});
|
|
313
|
+
afterEach(() => {});
|
|
309
314
|
|
|
310
315
|
beforeEach(() => {
|
|
311
316
|
vi.clearAllMocks();
|
|
312
317
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
313
318
|
mockReadStoredCredential.mockReturnValue(undefined);
|
|
319
|
+
manager = createSettingsManager();
|
|
314
320
|
});
|
|
315
321
|
|
|
316
322
|
it("should return placeholder when credential is not found", () => {
|
|
317
323
|
mockReadStoredCredential.mockReturnValue(undefined);
|
|
318
324
|
|
|
319
|
-
const result =
|
|
325
|
+
const result = manager.resolveApiKey("llama-server=http://127.0.0.1:8080");
|
|
320
326
|
|
|
321
327
|
expect(result).toEqual(API_KEY_PLACEHOLDER);
|
|
322
328
|
});
|
|
@@ -324,7 +330,7 @@ describe("API key resolution", () => {
|
|
|
324
330
|
it("should return placeholder when apiKey is missing from credential", () => {
|
|
325
331
|
mockReadStoredCredential.mockReturnValue({});
|
|
326
332
|
|
|
327
|
-
const result =
|
|
333
|
+
const result = manager.resolveApiKey("llama-server=http://127.0.0.1:8080");
|
|
328
334
|
|
|
329
335
|
expect(result).toEqual(API_KEY_PLACEHOLDER);
|
|
330
336
|
});
|
|
@@ -332,7 +338,7 @@ describe("API key resolution", () => {
|
|
|
332
338
|
it("should return the key when present in credential", () => {
|
|
333
339
|
mockReadStoredCredential.mockReturnValue({ key: "test-api-key" });
|
|
334
340
|
|
|
335
|
-
const result =
|
|
341
|
+
const result = manager.resolveApiKey("llama-server=http://127.0.0.1:8080");
|
|
336
342
|
|
|
337
343
|
expect(result).toEqual("test-api-key");
|
|
338
344
|
});
|
|
@@ -340,7 +346,7 @@ describe("API key resolution", () => {
|
|
|
340
346
|
it("should call readStoredCredential with the provider ID", () => {
|
|
341
347
|
mockReadStoredCredential.mockReturnValue({ key: "test-key" });
|
|
342
348
|
|
|
343
|
-
|
|
349
|
+
manager.resolveApiKey("llama-server=http://127.0.0.1:8080");
|
|
344
350
|
|
|
345
351
|
expect(mockReadStoredCredential).toHaveBeenCalledWith(
|
|
346
352
|
"llama-server=http://127.0.0.1:8080",
|
|
@@ -350,7 +356,7 @@ describe("API key resolution", () => {
|
|
|
350
356
|
|
|
351
357
|
describe("Server with custom id", () => {
|
|
352
358
|
it("should use custom id as providerId when provided", () => {
|
|
353
|
-
const server = new Server(
|
|
359
|
+
const server = new Server(manager, {
|
|
354
360
|
baseUrl: "http://127.0.0.1:8080",
|
|
355
361
|
customId: "my-custom-id",
|
|
356
362
|
});
|
|
@@ -359,7 +365,9 @@ describe("Server with custom id", () => {
|
|
|
359
365
|
});
|
|
360
366
|
|
|
361
367
|
it("should fall back to URL-based providerId when no custom id", () => {
|
|
362
|
-
const server = new Server(
|
|
368
|
+
const server = new Server(manager, {
|
|
369
|
+
baseUrl: "http://127.0.0.1:8080",
|
|
370
|
+
});
|
|
363
371
|
|
|
364
372
|
expect(server.providerId).toEqual(
|
|
365
373
|
`${PROVIDER_PREFIX}=http://127.0.0.1:8080`,
|
|
@@ -367,7 +375,7 @@ describe("Server with custom id", () => {
|
|
|
367
375
|
});
|
|
368
376
|
|
|
369
377
|
it("should try custom id first in getApiKey(), then fall back to URL-based", () => {
|
|
370
|
-
const server = new Server(
|
|
378
|
+
const server = new Server(manager, {
|
|
371
379
|
baseUrl: "http://127.0.0.1:8080",
|
|
372
380
|
customId: "my-custom-id",
|
|
373
381
|
});
|
|
@@ -380,7 +388,7 @@ describe("Server with custom id", () => {
|
|
|
380
388
|
.mockReturnValueOnce(API_KEY_PLACEHOLDER)
|
|
381
389
|
.mockReturnValueOnce({ key: "fallback-key" });
|
|
382
390
|
|
|
383
|
-
const result = server.
|
|
391
|
+
const result = server.apiKey;
|
|
384
392
|
|
|
385
393
|
expect(result).toEqual("fallback-key");
|
|
386
394
|
expect(mockReadStoredCredential).toHaveBeenNthCalledWith(1, "my-custom-id");
|
|
@@ -393,12 +401,12 @@ describe("Server with custom id", () => {
|
|
|
393
401
|
it("should return custom id key directly when found", () => {
|
|
394
402
|
mockReadStoredCredential.mockReturnValue({ key: "custom-key" });
|
|
395
403
|
|
|
396
|
-
const server = new Server(
|
|
404
|
+
const server = new Server(manager, {
|
|
397
405
|
baseUrl: "http://127.0.0.1:8080",
|
|
398
406
|
customId: "my-custom-id",
|
|
399
407
|
});
|
|
400
408
|
|
|
401
|
-
const result = server.
|
|
409
|
+
const result = server.apiKey;
|
|
402
410
|
|
|
403
411
|
expect(result).toEqual("custom-key");
|
|
404
412
|
expect(mockReadStoredCredential).toHaveBeenCalledWith("my-custom-id");
|
|
@@ -407,7 +415,7 @@ describe("Server with custom id", () => {
|
|
|
407
415
|
|
|
408
416
|
describe("Server with custom name", () => {
|
|
409
417
|
it("should use custom name as suffix in providerName", () => {
|
|
410
|
-
const server = new Server(
|
|
418
|
+
const server = new Server(manager, {
|
|
411
419
|
baseUrl: "http://127.0.0.1:8080",
|
|
412
420
|
customName: "Remote Server",
|
|
413
421
|
});
|
|
@@ -416,13 +424,15 @@ describe("Server with custom name", () => {
|
|
|
416
424
|
});
|
|
417
425
|
|
|
418
426
|
it("should fall back to URL-based name when no custom name", () => {
|
|
419
|
-
const server = new Server(
|
|
427
|
+
const server = new Server(manager, {
|
|
428
|
+
baseUrl: "http://127.0.0.1:8080",
|
|
429
|
+
});
|
|
420
430
|
|
|
421
431
|
expect(server.providerName).toEqual(`Llama.cpp (http://127.0.0.1:8080)`);
|
|
422
432
|
});
|
|
423
433
|
|
|
424
434
|
it("should use custom name even with custom id", () => {
|
|
425
|
-
const server = new Server(
|
|
435
|
+
const server = new Server(manager, {
|
|
426
436
|
baseUrl: "http://127.0.0.1:8080",
|
|
427
437
|
customId: "my-custom-id",
|
|
428
438
|
customName: "Remote Server",
|
|
@@ -434,30 +444,22 @@ describe("Server with custom name", () => {
|
|
|
434
444
|
});
|
|
435
445
|
|
|
436
446
|
describe("reactToModelSelect and autoloadOnMessage fallbacks", () => {
|
|
437
|
-
afterEach(() => {
|
|
438
|
-
vi.resetModules();
|
|
439
|
-
});
|
|
447
|
+
afterEach(() => {});
|
|
440
448
|
|
|
441
449
|
it("should return true when reactToModelSelect is not set", async () => {
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
const result = await settings.resolveReactToModelSelect();
|
|
450
|
+
const result = await manager.resolveReactToModelSelect();
|
|
445
451
|
|
|
446
452
|
expect(result).toBe(true);
|
|
447
453
|
});
|
|
448
454
|
|
|
449
455
|
it("should return false when autoloadOnMessage is not set", async () => {
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
const result = await settings.resolveAutoloadOnMessage();
|
|
456
|
+
const result = await manager.resolveAutoloadOnMessage();
|
|
453
457
|
|
|
454
458
|
expect(result).toBe(false);
|
|
455
459
|
});
|
|
456
460
|
|
|
457
461
|
it("should return 'asc' when sortBy is not set", async () => {
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
const result = await settings.resolveSortBy();
|
|
462
|
+
const result = await manager.resolveSortBy();
|
|
461
463
|
|
|
462
464
|
expect(result).toBe("asc");
|
|
463
465
|
});
|
|
@@ -470,10 +472,72 @@ describe("reactToModelSelect and autoloadOnMessage fallbacks", () => {
|
|
|
470
472
|
},
|
|
471
473
|
});
|
|
472
474
|
|
|
473
|
-
const
|
|
475
|
+
const manager = createSettingsManager();
|
|
476
|
+
|
|
477
|
+
expect(await manager.resolveReactToModelSelect()).toBe(false);
|
|
478
|
+
expect(await manager.resolveAutoloadOnMessage()).toBe(true);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
describe("resolveShowServerUrls", () => {
|
|
483
|
+
const mockGetAgentDir = vi.mocked(getAgentDir);
|
|
484
|
+
const mockGetProjectSettings = vi.mocked(
|
|
485
|
+
mockSettingsManager.getProjectSettings,
|
|
486
|
+
);
|
|
487
|
+
const mockGetGlobalSettings = vi.mocked(
|
|
488
|
+
mockSettingsManager.getGlobalSettings,
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
afterEach(() => {});
|
|
492
|
+
|
|
493
|
+
beforeEach(() => {
|
|
494
|
+
vi.clearAllMocks();
|
|
495
|
+
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
496
|
+
mockGetProjectSettings.mockReturnValue({});
|
|
497
|
+
mockGetGlobalSettings.mockReturnValue({});
|
|
498
|
+
manager = createSettingsManager();
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it("should return true (default) when showServerUrls is not set", async () => {
|
|
502
|
+
const result = await manager.resolveShowServerUrls();
|
|
503
|
+
|
|
504
|
+
expect(result).toBe(true);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it("should return false when explicitly set to false", async () => {
|
|
508
|
+
mockGetProjectSettings.mockReturnValue({
|
|
509
|
+
llamaSettings: {
|
|
510
|
+
showServerUrls: false,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const manager = createSettingsManager();
|
|
515
|
+
|
|
516
|
+
expect(await manager.resolveShowServerUrls()).toBe(false);
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it("should return true when explicitly set to true", async () => {
|
|
520
|
+
mockGetProjectSettings.mockReturnValue({
|
|
521
|
+
llamaSettings: {
|
|
522
|
+
showServerUrls: true,
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
const manager = createSettingsManager();
|
|
474
527
|
|
|
475
|
-
expect(await
|
|
476
|
-
|
|
528
|
+
expect(await manager.resolveShowServerUrls()).toBe(true);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it("should use global settings when no project config exists", async () => {
|
|
532
|
+
mockGetGlobalSettings.mockReturnValue({
|
|
533
|
+
llamaSettings: {
|
|
534
|
+
showServerUrls: false,
|
|
535
|
+
},
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const manager = createSettingsManager();
|
|
539
|
+
|
|
540
|
+
expect(await manager.resolveShowServerUrls()).toBe(false);
|
|
477
541
|
});
|
|
478
542
|
});
|
|
479
543
|
|
|
@@ -488,7 +552,6 @@ describe("resolveServers", () => {
|
|
|
488
552
|
|
|
489
553
|
afterEach(() => {
|
|
490
554
|
delete process.env.LLAMA_SERVER_URL;
|
|
491
|
-
vi.resetModules();
|
|
492
555
|
});
|
|
493
556
|
|
|
494
557
|
beforeEach(() => {
|
|
@@ -496,6 +559,7 @@ describe("resolveServers", () => {
|
|
|
496
559
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
497
560
|
mockGetProjectSettings.mockReturnValue({});
|
|
498
561
|
mockGetGlobalSettings.mockReturnValue({});
|
|
562
|
+
manager = createSettingsManager();
|
|
499
563
|
});
|
|
500
564
|
|
|
501
565
|
it("should use llamaSettings.servers when configured", async () => {
|
|
@@ -507,7 +571,7 @@ describe("resolveServers", () => {
|
|
|
507
571
|
},
|
|
508
572
|
});
|
|
509
573
|
|
|
510
|
-
const result = await
|
|
574
|
+
const result = await manager.resolveServers();
|
|
511
575
|
|
|
512
576
|
expect(result).toHaveLength(1);
|
|
513
577
|
expect(result[0].baseUrl).toBe("http://custom:8080");
|
|
@@ -517,14 +581,14 @@ describe("resolveServers", () => {
|
|
|
517
581
|
it("should fall back to resolveUrls when servers is empty", async () => {
|
|
518
582
|
process.env.LLAMA_SERVER_URL = "http://env-server:9090";
|
|
519
583
|
|
|
520
|
-
const result = await
|
|
584
|
+
const result = await manager.resolveServers();
|
|
521
585
|
|
|
522
586
|
expect(result).toHaveLength(1);
|
|
523
587
|
expect(result[0].baseUrl).toBe("http://env-server:9090");
|
|
524
588
|
});
|
|
525
589
|
|
|
526
590
|
it("should fall back to default URL when no config exists", async () => {
|
|
527
|
-
const result = await
|
|
591
|
+
const result = await manager.resolveServers();
|
|
528
592
|
|
|
529
593
|
expect(result).toHaveLength(1);
|
|
530
594
|
expect(result[0].baseUrl).toBe(LLAMA_SERVER_URL);
|
|
@@ -539,7 +603,7 @@ describe("resolveServers", () => {
|
|
|
539
603
|
},
|
|
540
604
|
});
|
|
541
605
|
|
|
542
|
-
const result = await
|
|
606
|
+
const result = await manager.resolveServers();
|
|
543
607
|
|
|
544
608
|
expect(result).toHaveLength(1);
|
|
545
609
|
expect(result[0].baseUrl).toBe("http://127.0.0.1:8080");
|
|
@@ -555,7 +619,7 @@ describe("resolveServers", () => {
|
|
|
555
619
|
});
|
|
556
620
|
process.env.LLAMA_SERVER_URL = "http://first:8080;http://second:9090";
|
|
557
621
|
|
|
558
|
-
const result = await
|
|
622
|
+
const result = await manager.resolveServers();
|
|
559
623
|
|
|
560
624
|
expect(result).toHaveLength(2);
|
|
561
625
|
expect(result[0].baseUrl).toBe("http://first:8080");
|
|
@@ -572,7 +636,7 @@ describe("resolveServers", () => {
|
|
|
572
636
|
},
|
|
573
637
|
});
|
|
574
638
|
|
|
575
|
-
const result = await
|
|
639
|
+
const result = await manager.resolveServers();
|
|
576
640
|
|
|
577
641
|
// env variable takes precedence via resolveUrls
|
|
578
642
|
expect(result).toHaveLength(1);
|
|
@@ -581,14 +645,10 @@ describe("resolveServers", () => {
|
|
|
581
645
|
});
|
|
582
646
|
|
|
583
647
|
describe("resolveTimeouts", () => {
|
|
584
|
-
afterEach(() => {
|
|
585
|
-
vi.resetModules();
|
|
586
|
-
});
|
|
648
|
+
afterEach(() => {});
|
|
587
649
|
|
|
588
650
|
it("should return default timeouts when not configured", async () => {
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
const result = await settings.resolveTimeouts();
|
|
651
|
+
const result = await manager.resolveTimeouts();
|
|
592
652
|
|
|
593
653
|
expect(result).toEqual({
|
|
594
654
|
pollingTimeout: POLLING_TIMEOUT,
|
|
@@ -603,9 +663,7 @@ describe("resolveTimeouts", () => {
|
|
|
603
663
|
},
|
|
604
664
|
});
|
|
605
665
|
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
const result = await settings.resolveTimeouts();
|
|
666
|
+
const result = await manager.resolveTimeouts();
|
|
609
667
|
|
|
610
668
|
expect(result.pollingTimeout).toBe(120000);
|
|
611
669
|
expect(result.serverTimeout).toBe(SERVER_TIMEOUT);
|
|
@@ -618,9 +676,7 @@ describe("resolveTimeouts", () => {
|
|
|
618
676
|
},
|
|
619
677
|
});
|
|
620
678
|
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
const result = await settings.resolveTimeouts();
|
|
679
|
+
const result = await manager.resolveTimeouts();
|
|
624
680
|
|
|
625
681
|
expect(result.pollingTimeout).toBe(POLLING_TIMEOUT);
|
|
626
682
|
expect(result.serverTimeout).toBe(3000);
|
|
@@ -634,9 +690,7 @@ describe("resolveTimeouts", () => {
|
|
|
634
690
|
},
|
|
635
691
|
});
|
|
636
692
|
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
const result = await settings.resolveTimeouts();
|
|
693
|
+
const result = await manager.resolveTimeouts();
|
|
640
694
|
|
|
641
695
|
expect(result).toEqual({
|
|
642
696
|
pollingTimeout: 90000,
|
|
@@ -648,21 +702,20 @@ describe("resolveTimeouts", () => {
|
|
|
648
702
|
describe("Thinking config resolution", () => {
|
|
649
703
|
const mockGetAgentDir = vi.mocked(getAgentDir);
|
|
650
704
|
|
|
651
|
-
afterEach(() => {
|
|
652
|
-
vi.resetModules();
|
|
653
|
-
});
|
|
705
|
+
afterEach(() => {});
|
|
654
706
|
|
|
655
707
|
beforeEach(() => {
|
|
656
708
|
vi.clearAllMocks();
|
|
657
709
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
658
710
|
mockSettingsManager.getDefaultThinkingLevel.mockReturnValue("medium");
|
|
659
711
|
mockSettingsManager.getThinkingBudgets.mockReturnValue({});
|
|
712
|
+
manager = createSettingsManager();
|
|
660
713
|
});
|
|
661
714
|
|
|
662
715
|
it("should return the default thinking level from SettingsManager", () => {
|
|
663
716
|
mockSettingsManager.getDefaultThinkingLevel.mockReturnValue("low");
|
|
664
717
|
|
|
665
|
-
const result =
|
|
718
|
+
const result = manager.resolveThinkingLevel();
|
|
666
719
|
|
|
667
720
|
expect(result).toEqual("low");
|
|
668
721
|
});
|
|
@@ -672,7 +725,7 @@ describe("Thinking config resolution", () => {
|
|
|
672
725
|
low: 4096,
|
|
673
726
|
});
|
|
674
727
|
|
|
675
|
-
const result =
|
|
728
|
+
const result = manager.resolveThinkingBudgets();
|
|
676
729
|
|
|
677
730
|
expect(result).toEqual(
|
|
678
731
|
expect.objectContaining({
|
|
@@ -706,9 +759,7 @@ describe("setLlamaSetting", () => {
|
|
|
706
759
|
const PROJECT_SETTINGS_PATH = "/fake/project/.pi/settings.json";
|
|
707
760
|
const FAKE_CWD = "/fake/project";
|
|
708
761
|
|
|
709
|
-
afterEach(() => {
|
|
710
|
-
vi.resetModules();
|
|
711
|
-
});
|
|
762
|
+
afterEach(() => {});
|
|
712
763
|
|
|
713
764
|
beforeEach(() => {
|
|
714
765
|
vi.clearAllMocks();
|
|
@@ -720,14 +771,14 @@ describe("setLlamaSetting", () => {
|
|
|
720
771
|
mockReadFile.mockResolvedValue("{}");
|
|
721
772
|
mockWriteFile.mockResolvedValue(undefined);
|
|
722
773
|
mockRename.mockResolvedValue(undefined);
|
|
774
|
+
manager = createSettingsManager();
|
|
723
775
|
});
|
|
724
776
|
|
|
725
777
|
it("should write to project settings when .pi/settings.json exists (auto scope)", async () => {
|
|
726
778
|
mockAccess.mockResolvedValue(undefined);
|
|
727
779
|
mockReadFile.mockResolvedValue("{}");
|
|
728
780
|
|
|
729
|
-
|
|
730
|
-
await settings.setLlamaSetting("sortBy", "desc");
|
|
781
|
+
await manager.setLlamaSetting("sortBy", "desc");
|
|
731
782
|
|
|
732
783
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
733
784
|
`${PROJECT_SETTINGS_PATH}.tmp`,
|
|
@@ -744,8 +795,7 @@ describe("setLlamaSetting", () => {
|
|
|
744
795
|
mockAccess.mockRejectedValue(new Error("ENOENT"));
|
|
745
796
|
mockReadFile.mockResolvedValue("{}");
|
|
746
797
|
|
|
747
|
-
|
|
748
|
-
await settings.setLlamaSetting("sortBy", "desc");
|
|
798
|
+
await manager.setLlamaSetting("sortBy", "desc");
|
|
749
799
|
|
|
750
800
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
751
801
|
`${GLOBAL_SETTINGS_PATH}.tmp`,
|
|
@@ -762,8 +812,7 @@ describe("setLlamaSetting", () => {
|
|
|
762
812
|
mockAccess.mockResolvedValue(undefined); // project exists but we override
|
|
763
813
|
mockReadFile.mockResolvedValue("{}");
|
|
764
814
|
|
|
765
|
-
|
|
766
|
-
await settings.setLlamaSetting("sortBy", "desc", "global");
|
|
815
|
+
await manager.setLlamaSetting("sortBy", "desc", "global");
|
|
767
816
|
|
|
768
817
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
769
818
|
`${GLOBAL_SETTINGS_PATH}.tmp`,
|
|
@@ -776,8 +825,7 @@ describe("setLlamaSetting", () => {
|
|
|
776
825
|
mockAccess.mockRejectedValue(new Error("ENOENT")); // project doesn't exist but we override
|
|
777
826
|
mockReadFile.mockResolvedValue("{}");
|
|
778
827
|
|
|
779
|
-
|
|
780
|
-
await settings.setLlamaSetting("sortBy", "desc", "project");
|
|
828
|
+
await manager.setLlamaSetting("sortBy", "desc", "project");
|
|
781
829
|
|
|
782
830
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
783
831
|
`${PROJECT_SETTINGS_PATH}.tmp`,
|
|
@@ -796,8 +844,7 @@ describe("setLlamaSetting", () => {
|
|
|
796
844
|
),
|
|
797
845
|
);
|
|
798
846
|
|
|
799
|
-
|
|
800
|
-
await settings.setLlamaSetting("sortBy", "desc");
|
|
847
|
+
await manager.setLlamaSetting("sortBy", "desc");
|
|
801
848
|
|
|
802
849
|
expect(mockWriteFile).toHaveBeenCalledTimes(1);
|
|
803
850
|
const [tmpPath, written, encoding] = mockWriteFile.mock.calls[0];
|
|
@@ -815,9 +862,7 @@ describe("setLlamaSetting", () => {
|
|
|
815
862
|
expect(mockReload).toHaveBeenCalledTimes(1);
|
|
816
863
|
});
|
|
817
864
|
|
|
818
|
-
afterEach(() => {
|
|
819
|
-
vi.resetModules();
|
|
820
|
-
});
|
|
865
|
+
afterEach(() => {});
|
|
821
866
|
|
|
822
867
|
it("should reflect the new value in resolvers immediately after the write", async () => {
|
|
823
868
|
mockSettingsManager.reload.mockImplementation(async () => {
|
|
@@ -826,18 +871,16 @@ describe("setLlamaSetting", () => {
|
|
|
826
871
|
});
|
|
827
872
|
});
|
|
828
873
|
|
|
829
|
-
|
|
830
|
-
await settings.setLlamaSetting("sortBy", "desc");
|
|
874
|
+
await manager.setLlamaSetting("sortBy", "desc");
|
|
831
875
|
|
|
832
|
-
expect(await
|
|
876
|
+
expect(await manager.resolveSortBy()).toBe("desc");
|
|
833
877
|
});
|
|
834
878
|
|
|
835
879
|
it("should reject and skip reload when the write fails", async () => {
|
|
836
880
|
mockAccess.mockRejectedValue(new Error("ENOENT"));
|
|
837
881
|
mockWriteFile.mockRejectedValue(new Error("ENOSPC: simulated"));
|
|
838
882
|
|
|
839
|
-
|
|
840
|
-
await expect(settings.setLlamaSetting("sortBy", "desc")).rejects.toThrow(
|
|
883
|
+
await expect(manager.setLlamaSetting("sortBy", "desc")).rejects.toThrow(
|
|
841
884
|
"ENOSPC",
|
|
842
885
|
);
|
|
843
886
|
expect(mockReload).not.toHaveBeenCalled();
|
|
@@ -847,8 +890,7 @@ describe("setLlamaSetting", () => {
|
|
|
847
890
|
mockAccess.mockRejectedValue(new Error("ENOENT"));
|
|
848
891
|
mockReadFile.mockResolvedValue("{ broken");
|
|
849
892
|
|
|
850
|
-
|
|
851
|
-
await expect(settings.setLlamaSetting("sortBy", "desc")).rejects.toThrow(
|
|
893
|
+
await expect(manager.setLlamaSetting("sortBy", "desc")).rejects.toThrow(
|
|
852
894
|
/Cannot parse/,
|
|
853
895
|
);
|
|
854
896
|
expect(mockWriteFile).not.toHaveBeenCalled();
|
|
@@ -857,15 +899,15 @@ describe("setLlamaSetting", () => {
|
|
|
857
899
|
|
|
858
900
|
it("should persist booleans and numbers with type fidelity", async () => {
|
|
859
901
|
mockAccess.mockRejectedValue(new Error("ENOENT"));
|
|
860
|
-
|
|
861
|
-
await
|
|
902
|
+
|
|
903
|
+
await manager.setLlamaSetting("reactToModelSelect", false);
|
|
862
904
|
|
|
863
905
|
const [, firstWrite] = mockWriteFile.mock.calls[0];
|
|
864
906
|
expect(JSON.parse(firstWrite as string)).toEqual({
|
|
865
907
|
llamaSettings: { reactToModelSelect: false },
|
|
866
908
|
});
|
|
867
909
|
|
|
868
|
-
await
|
|
910
|
+
await manager.setLlamaSetting("pollingTimeout", 120000);
|
|
869
911
|
|
|
870
912
|
const [, secondWrite] = mockWriteFile.mock.calls[1];
|
|
871
913
|
expect(JSON.parse(secondWrite as string)).toEqual({
|
|
@@ -874,7 +916,8 @@ describe("setLlamaSetting", () => {
|
|
|
874
916
|
});
|
|
875
917
|
|
|
876
918
|
it("should still construct the manager without arguments", async () => {
|
|
877
|
-
const { LlamaSettingsManager } =
|
|
919
|
+
const { LlamaSettingsManager } =
|
|
920
|
+
await import("../../src/managers/settings");
|
|
878
921
|
|
|
879
922
|
expect(() => new LlamaSettingsManager()).not.toThrow();
|
|
880
923
|
});
|
|
@@ -889,15 +932,14 @@ describe("resolveServerOverrides", () => {
|
|
|
889
932
|
mockSettingsManager.getGlobalSettings,
|
|
890
933
|
);
|
|
891
934
|
|
|
892
|
-
afterEach(() => {
|
|
893
|
-
vi.resetModules();
|
|
894
|
-
});
|
|
935
|
+
afterEach(() => {});
|
|
895
936
|
|
|
896
937
|
beforeEach(() => {
|
|
897
938
|
vi.clearAllMocks();
|
|
898
939
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
899
940
|
mockGetProjectSettings.mockReturnValue({});
|
|
900
941
|
mockGetGlobalSettings.mockReturnValue({});
|
|
942
|
+
manager = createSettingsManager();
|
|
901
943
|
});
|
|
902
944
|
|
|
903
945
|
it("should return overrides for a server that has them configured", async () => {
|
|
@@ -922,7 +964,7 @@ describe("resolveServerOverrides", () => {
|
|
|
922
964
|
},
|
|
923
965
|
});
|
|
924
966
|
|
|
925
|
-
const result = await
|
|
967
|
+
const result = await manager.resolveServerOverrides(
|
|
926
968
|
"http://127.0.0.1:8080",
|
|
927
969
|
);
|
|
928
970
|
|
|
@@ -946,7 +988,7 @@ describe("resolveServerOverrides", () => {
|
|
|
946
988
|
},
|
|
947
989
|
});
|
|
948
990
|
|
|
949
|
-
const result = await
|
|
991
|
+
const result = await manager.resolveServerOverrides(
|
|
950
992
|
"http://127.0.0.1:8080",
|
|
951
993
|
);
|
|
952
994
|
|
|
@@ -960,7 +1002,7 @@ describe("resolveServerOverrides", () => {
|
|
|
960
1002
|
},
|
|
961
1003
|
});
|
|
962
1004
|
|
|
963
|
-
const result = await
|
|
1005
|
+
const result = await manager.resolveServerOverrides(
|
|
964
1006
|
"http://127.0.0.1:8080",
|
|
965
1007
|
);
|
|
966
1008
|
|
|
@@ -979,7 +1021,7 @@ describe("resolveServerOverrides", () => {
|
|
|
979
1021
|
},
|
|
980
1022
|
});
|
|
981
1023
|
|
|
982
|
-
const result = await
|
|
1024
|
+
const result = await manager.resolveServerOverrides("http://global:8080");
|
|
983
1025
|
|
|
984
1026
|
expect(result).toEqual({ "model-a": { cost: { input: 0.5 } } });
|
|
985
1027
|
});
|
|
@@ -1006,7 +1048,7 @@ describe("resolveServerOverrides", () => {
|
|
|
1006
1048
|
},
|
|
1007
1049
|
});
|
|
1008
1050
|
|
|
1009
|
-
const result = await
|
|
1051
|
+
const result = await manager.resolveServerOverrides("http://shared:8080");
|
|
1010
1052
|
|
|
1011
1053
|
expect(result).toEqual({
|
|
1012
1054
|
"model-b": { cost: { input: 0.1, output: 0.2 } },
|
|
@@ -1018,7 +1060,7 @@ describe("resolveServerOverrides", () => {
|
|
|
1018
1060
|
llamaSettings: { servers: [] },
|
|
1019
1061
|
});
|
|
1020
1062
|
|
|
1021
|
-
const result = await
|
|
1063
|
+
const result = await manager.resolveServerOverrides(
|
|
1022
1064
|
"http://127.0.0.1:8080",
|
|
1023
1065
|
);
|
|
1024
1066
|
|
|
@@ -1028,7 +1070,7 @@ describe("resolveServerOverrides", () => {
|
|
|
1028
1070
|
it("should return empty object when llamaSettings is missing", async () => {
|
|
1029
1071
|
mockGetProjectSettings.mockReturnValue({});
|
|
1030
1072
|
|
|
1031
|
-
const result = await
|
|
1073
|
+
const result = await manager.resolveServerOverrides(
|
|
1032
1074
|
"http://127.0.0.1:8080",
|
|
1033
1075
|
);
|
|
1034
1076
|
|
|
@@ -1047,7 +1089,7 @@ describe("resolveServerOverrides", () => {
|
|
|
1047
1089
|
},
|
|
1048
1090
|
});
|
|
1049
1091
|
|
|
1050
|
-
const result = await
|
|
1092
|
+
const result = await manager.resolveServerOverrides(
|
|
1051
1093
|
"http://127.0.0.1:8080",
|
|
1052
1094
|
);
|
|
1053
1095
|
|
|
@@ -1057,7 +1099,7 @@ describe("resolveServerOverrides", () => {
|
|
|
1057
1099
|
|
|
1058
1100
|
describe("Server with overrides", () => {
|
|
1059
1101
|
it("should store and expose resolved overrides", () => {
|
|
1060
|
-
const server = new Server(
|
|
1102
|
+
const server = new Server(manager, {
|
|
1061
1103
|
baseUrl: "http://127.0.0.1:8080",
|
|
1062
1104
|
overrides: {
|
|
1063
1105
|
"model-a": { cost: { input: 0.2, output: 0.6 } },
|
|
@@ -1065,18 +1107,20 @@ describe("Server with overrides", () => {
|
|
|
1065
1107
|
},
|
|
1066
1108
|
});
|
|
1067
1109
|
|
|
1068
|
-
expect(server.
|
|
1069
|
-
|
|
1070
|
-
|
|
1110
|
+
expect(server.findOverrideForModel("model-a")).toEqual({
|
|
1111
|
+
cost: { input: 0.2, output: 0.6 },
|
|
1112
|
+
});
|
|
1113
|
+
expect(server.findOverrideForModel("model-b")).toEqual({
|
|
1114
|
+
cost: { input: 0.1, output: 0.3, cacheRead: 0.01 },
|
|
1071
1115
|
});
|
|
1072
1116
|
});
|
|
1073
1117
|
|
|
1074
|
-
it("should return
|
|
1075
|
-
const server = new Server(
|
|
1118
|
+
it("should return undefined for findOverrideForModel when no overrides are provided", () => {
|
|
1119
|
+
const server = new Server(manager, {
|
|
1076
1120
|
baseUrl: "http://127.0.0.1:8080",
|
|
1077
1121
|
});
|
|
1078
1122
|
|
|
1079
|
-
expect(server.
|
|
1123
|
+
expect(server.findOverrideForModel("any-model")).toBeUndefined();
|
|
1080
1124
|
});
|
|
1081
1125
|
});
|
|
1082
1126
|
|
|
@@ -1089,15 +1133,14 @@ describe("resolveServers passes overrides", () => {
|
|
|
1089
1133
|
mockSettingsManager.getGlobalSettings,
|
|
1090
1134
|
);
|
|
1091
1135
|
|
|
1092
|
-
afterEach(() => {
|
|
1093
|
-
vi.resetModules();
|
|
1094
|
-
});
|
|
1136
|
+
afterEach(() => {});
|
|
1095
1137
|
|
|
1096
1138
|
beforeEach(() => {
|
|
1097
1139
|
vi.clearAllMocks();
|
|
1098
1140
|
mockGetAgentDir.mockReturnValue("/fake/agent/dir");
|
|
1099
1141
|
mockGetProjectSettings.mockReturnValue({});
|
|
1100
1142
|
mockGetGlobalSettings.mockReturnValue({});
|
|
1143
|
+
manager = createSettingsManager();
|
|
1101
1144
|
});
|
|
1102
1145
|
|
|
1103
1146
|
it("should pass resolved overrides to Server instances", async () => {
|
|
@@ -1115,19 +1158,19 @@ describe("resolveServers passes overrides", () => {
|
|
|
1115
1158
|
},
|
|
1116
1159
|
});
|
|
1117
1160
|
|
|
1118
|
-
const result = await
|
|
1161
|
+
const result = await manager.resolveServers();
|
|
1119
1162
|
|
|
1120
1163
|
expect(result).toHaveLength(2);
|
|
1121
|
-
expect(result[0].
|
|
1122
|
-
|
|
1164
|
+
expect(result[0].findOverrideForModel("model-x")).toEqual({
|
|
1165
|
+
cost: { input: 0.5, output: 1.0 },
|
|
1123
1166
|
});
|
|
1124
|
-
expect(result[1].
|
|
1167
|
+
expect(result[1].findOverrideForModel("any-model")).toBeUndefined();
|
|
1125
1168
|
});
|
|
1126
1169
|
});
|
|
1127
1170
|
|
|
1128
1171
|
describe("Server.findOverrideForModel", () => {
|
|
1129
1172
|
function createServer(overrides: Record<string, ModelOverride>): Server {
|
|
1130
|
-
return new Server(
|
|
1173
|
+
return new Server(createSettingsManager() as any, {
|
|
1131
1174
|
baseUrl: "http://127.0.0.1:8080",
|
|
1132
1175
|
overrides,
|
|
1133
1176
|
});
|