pi-llama-cpp 0.13.0 → 0.14.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 +7 -8
- package/package.json +2 -2
- package/src/api/client.ts +25 -0
- package/src/constants.ts +0 -5
- package/src/enums/status.ts +0 -1
- package/src/interfaces/endpoints/models.ts +1 -1
- package/src/interfaces/settings.ts +1 -1
- package/src/interfaces/sortBy.ts +4 -0
- package/src/managers/command/models.ts +247 -0
- package/src/managers/command.ts +29 -461
- package/src/managers/events.ts +2 -2
- package/src/managers/server.ts +27 -3
- package/src/managers/settings.ts +12 -88
- 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 +11 -29
- 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 +43 -0
- package/src/ui/editors/itemBuilder.ts +47 -0
- package/src/ui/editors/listEditor.ts +291 -0
- package/src/ui/editors/override/entry.ts +24 -0
- package/src/ui/editors/override/entryEditor.ts +166 -0
- package/src/ui/editors/override/fields.ts +294 -0
- package/src/ui/editors/override/handlers.ts +118 -0
- package/src/ui/editors/override/itemBuilder.ts +42 -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/handlers.ts +32 -0
- package/src/ui/editors/server/itemBuilder.ts +68 -0
- package/src/ui/editors/server/serverEditor.ts +161 -0
- package/src/ui/editors/server/utils.ts +45 -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 +237 -0
- package/src/ui/strings.ts +8 -4
- 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 +14 -9
- package/tests/dialog.test.ts +55 -4
- package/tests/legacyModel.test.ts +34 -28
- package/tests/overrides.test.ts +111 -88
- package/tests/routerModel.test.ts +67 -68
- package/tests/server.test.ts +0 -12
- package/tests/settings.test.ts +10 -8
- package/tests/singleModel.test.ts +12 -12
- package/tests/sseManager.test.ts +6 -24
- 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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { FALLBACK_CTX } from "../src/constants";
|
|
2
3
|
import { Mode } from "../src/enums/mode";
|
|
3
4
|
import { DataProperty } from "../src/interfaces/endpoints/models";
|
|
4
5
|
import { LegacyModel } from "../src/models/legacyModel";
|
|
@@ -28,70 +29,75 @@ describe("LegacyModel mode", () => {
|
|
|
28
29
|
});
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
describe("LegacyModel capabilities", () => {
|
|
32
|
+
describe("LegacyModel capabilities (via toProviderConfig)", () => {
|
|
32
33
|
it("should detect image capability when multimodal is in capabilities", async () => {
|
|
33
34
|
mockRpc.mockResolvedValueOnce({ modalities: { vision: true } });
|
|
35
|
+
mockRpc.mockResolvedValue({ n_ctx: 4096, data: [{ max_model_len: 8192 }] });
|
|
34
36
|
|
|
35
37
|
const model = createModel();
|
|
36
|
-
const
|
|
38
|
+
const { input } = await model.toProviderConfig();
|
|
37
39
|
|
|
38
|
-
expect(
|
|
40
|
+
expect(input).toEqual(["text", "image"]);
|
|
39
41
|
});
|
|
40
42
|
|
|
41
43
|
it("should detect text-only capability when multimodal is not in capabilities", async () => {
|
|
42
44
|
mockRpc.mockResolvedValueOnce({ modalities: { vision: false } });
|
|
45
|
+
mockRpc.mockResolvedValue({ n_ctx: 4096, data: [{ max_model_len: 8192 }] });
|
|
43
46
|
|
|
44
47
|
const model = createModel();
|
|
45
|
-
const
|
|
48
|
+
const { input } = await model.toProviderConfig();
|
|
46
49
|
|
|
47
|
-
expect(
|
|
50
|
+
expect(input).toEqual(["text"]);
|
|
48
51
|
});
|
|
49
52
|
|
|
50
53
|
it("should fall back to text-only when auth fails", async () => {
|
|
51
|
-
mockRpc.
|
|
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
|
+
});
|
|
52
61
|
|
|
53
62
|
const model = createModel();
|
|
54
|
-
const
|
|
63
|
+
const { input } = await model.toProviderConfig();
|
|
55
64
|
|
|
56
|
-
expect(
|
|
65
|
+
expect(input).toEqual(["text"]);
|
|
57
66
|
});
|
|
58
67
|
});
|
|
59
68
|
|
|
60
|
-
describe("LegacyModel
|
|
69
|
+
describe("LegacyModel context size (via toProviderConfig)", () => {
|
|
61
70
|
it("should use max_model_len when it is non-zero", async () => {
|
|
62
|
-
mockRpc.mockResolvedValueOnce({
|
|
63
|
-
mockRpc.mockResolvedValueOnce({
|
|
64
|
-
|
|
65
|
-
});
|
|
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
|
|
66
74
|
|
|
67
75
|
const model = createModel();
|
|
68
|
-
const
|
|
76
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
69
77
|
|
|
70
|
-
expect(
|
|
78
|
+
expect(contextWindow).toBe(8192);
|
|
71
79
|
expect(mockRpc).toHaveBeenCalledWith("/v1/models");
|
|
72
80
|
});
|
|
73
81
|
|
|
74
82
|
it("should fall back to n_ctx when max_model_len is 0", async () => {
|
|
75
|
-
mockRpc.mockResolvedValueOnce({
|
|
76
|
-
mockRpc.mockResolvedValueOnce({
|
|
77
|
-
|
|
78
|
-
});
|
|
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
|
|
79
86
|
|
|
80
87
|
const model = createModel();
|
|
81
|
-
const
|
|
88
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
82
89
|
|
|
83
|
-
expect(
|
|
90
|
+
expect(contextWindow).toBe(4096);
|
|
84
91
|
});
|
|
85
92
|
|
|
86
|
-
it("should return
|
|
87
|
-
mockRpc.mockResolvedValueOnce({});
|
|
88
|
-
mockRpc.mockResolvedValueOnce({
|
|
89
|
-
|
|
90
|
-
});
|
|
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
|
|
91
97
|
|
|
92
98
|
const model = createModel();
|
|
93
|
-
const
|
|
99
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
94
100
|
|
|
95
|
-
expect(
|
|
101
|
+
expect(contextWindow).toBe(FALLBACK_CTX);
|
|
96
102
|
});
|
|
97
103
|
});
|
package/tests/overrides.test.ts
CHANGED
|
@@ -3,15 +3,12 @@ import { FALLBACK_CTX } from "../src/constants";
|
|
|
3
3
|
import type { LlamaServer, ModelOverride } from "../src/interfaces/settings";
|
|
4
4
|
import { SingleModel } from "../src/models/singleModel";
|
|
5
5
|
import { Server } from "../src/server";
|
|
6
|
+
import { OverrideEntry } from "../src/ui/editors/override/entry";
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
removeOverrideEntry,
|
|
12
|
-
updateOverrideEntry,
|
|
13
|
-
} from "../src/ui/overrideEntryEditor";
|
|
14
|
-
import { overrideFieldValue } from "../src/ui/overrideSettingsList";
|
|
8
|
+
OverrideFields,
|
|
9
|
+
OverrideSummary,
|
|
10
|
+
} from "../src/ui/editors/override/fields";
|
|
11
|
+
import { OverrideEntryMutator } from "../src/ui/editors/override/handlers";
|
|
15
12
|
import { createMockServer, mockRpc } from "./mocks";
|
|
16
13
|
|
|
17
14
|
beforeEach(() => {
|
|
@@ -94,16 +91,18 @@ describe("BaseModel reasoning override", () => {
|
|
|
94
91
|
|
|
95
92
|
// ─── capabilities override ────────────────────────────────────────────────
|
|
96
93
|
|
|
97
|
-
describe("BaseModel capabilities override", () => {
|
|
94
|
+
describe("BaseModel capabilities override (via toProviderConfig)", () => {
|
|
98
95
|
it("should fully replace detection without contacting the server", async () => {
|
|
99
96
|
mockRpc.mockImplementation(() => {
|
|
100
97
|
throw new Error("override must not trigger a fetch");
|
|
101
98
|
});
|
|
102
99
|
|
|
103
|
-
const model = createModel({
|
|
104
|
-
|
|
100
|
+
const model = createModel({
|
|
101
|
+
test: { capabilities: ["text", "image"], contextSize: 8192 },
|
|
102
|
+
});
|
|
103
|
+
const { input } = await model.toProviderConfig();
|
|
105
104
|
|
|
106
|
-
expect(
|
|
105
|
+
expect(input).toEqual(["text", "image"]);
|
|
107
106
|
expect(mockRpc).not.toHaveBeenCalled();
|
|
108
107
|
});
|
|
109
108
|
|
|
@@ -111,41 +110,41 @@ describe("BaseModel capabilities override", () => {
|
|
|
111
110
|
mockDetection(8192);
|
|
112
111
|
|
|
113
112
|
const model = createModel({ other: { capabilities: ["text"] } });
|
|
114
|
-
const
|
|
113
|
+
const { input } = await model.toProviderConfig();
|
|
115
114
|
|
|
116
|
-
expect(
|
|
115
|
+
expect(input).toEqual(["text"]);
|
|
117
116
|
expect(mockRpc).toHaveBeenCalled();
|
|
118
117
|
});
|
|
119
118
|
});
|
|
120
119
|
|
|
121
120
|
// ─── contextSize override ─────────────────────────────────────────────────
|
|
122
121
|
|
|
123
|
-
describe("BaseModel
|
|
122
|
+
describe("BaseModel contextSize override (via toProviderConfig)", () => {
|
|
124
123
|
it("should return the overridden context size instead of the detected one", async () => {
|
|
125
124
|
mockDetection(8192);
|
|
126
125
|
|
|
127
126
|
const model = createModel({ test: { contextSize: 32768 } });
|
|
128
|
-
const
|
|
127
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
129
128
|
|
|
130
|
-
expect(
|
|
129
|
+
expect(contextWindow).toBe(32768);
|
|
131
130
|
});
|
|
132
131
|
|
|
133
132
|
it("should treat a stored 0 as absent and autodetect", async () => {
|
|
134
133
|
mockDetection(8192);
|
|
135
134
|
|
|
136
135
|
const model = createModel({ test: { contextSize: 0 } });
|
|
137
|
-
const
|
|
136
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
138
137
|
|
|
139
|
-
expect(
|
|
138
|
+
expect(contextWindow).toBe(8192);
|
|
140
139
|
});
|
|
141
140
|
|
|
142
141
|
it("should autodetect when no override matches", async () => {
|
|
143
142
|
mockDetection(8192);
|
|
144
143
|
|
|
145
144
|
const model = createModel({ other: { contextSize: 32768 } });
|
|
146
|
-
const
|
|
145
|
+
const { contextWindow } = await model.toProviderConfig();
|
|
147
146
|
|
|
148
|
-
expect(
|
|
147
|
+
expect(contextWindow).toBe(8192);
|
|
149
148
|
});
|
|
150
149
|
});
|
|
151
150
|
|
|
@@ -251,11 +250,14 @@ describe("toProviderConfig overrides", () => {
|
|
|
251
250
|
});
|
|
252
251
|
});
|
|
253
252
|
|
|
254
|
-
// ───
|
|
253
|
+
// ─── OverrideEntry.summary ────────────────────────────────────────────────────
|
|
254
|
+
|
|
255
|
+
describe("OverrideSummary.of", () => {
|
|
256
|
+
const summary = (override: ModelOverride): string =>
|
|
257
|
+
OverrideSummary.of(override);
|
|
255
258
|
|
|
256
|
-
describe("formatOverrideSummary", () => {
|
|
257
259
|
it("should render every configured field", () => {
|
|
258
|
-
const
|
|
260
|
+
const rendered = summary({
|
|
259
261
|
cost: { input: 0.2, output: 0.6, cacheRead: 0.01 },
|
|
260
262
|
capabilities: ["text", "image"],
|
|
261
263
|
reasoning: false,
|
|
@@ -263,31 +265,31 @@ describe("formatOverrideSummary", () => {
|
|
|
263
265
|
maxTokens: 4096,
|
|
264
266
|
});
|
|
265
267
|
|
|
266
|
-
expect(
|
|
267
|
-
expect(
|
|
268
|
-
expect(
|
|
269
|
-
expect(
|
|
270
|
-
expect(
|
|
271
|
-
expect(
|
|
272
|
-
expect(
|
|
268
|
+
expect(rendered).toContain("input: $0.2");
|
|
269
|
+
expect(rendered).toContain("output: $0.6");
|
|
270
|
+
expect(rendered).toContain("cache read: $0.01");
|
|
271
|
+
expect(rendered).toContain("capabilities: text,image");
|
|
272
|
+
expect(rendered).toContain("reasoning: false");
|
|
273
|
+
expect(rendered).toContain("contextSize: 32768");
|
|
274
|
+
expect(rendered).toContain("maxTokens: 4096");
|
|
273
275
|
});
|
|
274
276
|
|
|
275
277
|
it("should omit zero, undefined and empty fields", () => {
|
|
276
|
-
const
|
|
278
|
+
const rendered = summary({
|
|
277
279
|
cost: { input: 0, output: 0.6 },
|
|
278
280
|
reasoning: undefined,
|
|
279
281
|
});
|
|
280
282
|
|
|
281
|
-
expect(
|
|
282
|
-
expect(
|
|
283
|
-
expect(
|
|
284
|
-
expect(
|
|
285
|
-
expect(
|
|
286
|
-
expect(
|
|
283
|
+
expect(rendered).not.toContain("input:");
|
|
284
|
+
expect(rendered).toContain("output: $0.6");
|
|
285
|
+
expect(rendered).not.toContain("capabilities");
|
|
286
|
+
expect(rendered).not.toContain("reasoning");
|
|
287
|
+
expect(rendered).not.toContain("contextSize");
|
|
288
|
+
expect(rendered).not.toContain("maxTokens");
|
|
287
289
|
});
|
|
288
290
|
|
|
289
291
|
it("should render an em dash for an empty override", () => {
|
|
290
|
-
expect(
|
|
292
|
+
expect(summary({})).toBe("—");
|
|
291
293
|
});
|
|
292
294
|
});
|
|
293
295
|
|
|
@@ -299,86 +301,107 @@ describe("override entry list helpers", () => {
|
|
|
299
301
|
{ url: "http://b" },
|
|
300
302
|
] as LlamaServer[];
|
|
301
303
|
|
|
302
|
-
it("
|
|
303
|
-
const next =
|
|
304
|
+
it("addEntry should append a pattern → override entry", () => {
|
|
305
|
+
const next = new OverrideEntryMutator(servers, 0).addEntry("a-2", {
|
|
306
|
+
contextSize: 4096,
|
|
307
|
+
});
|
|
304
308
|
expect(next[0].overrides).toEqual({
|
|
305
309
|
"a-1": { reasoning: false },
|
|
306
310
|
"a-2": { contextSize: 4096 },
|
|
307
311
|
});
|
|
308
312
|
});
|
|
309
313
|
|
|
310
|
-
it("
|
|
311
|
-
const
|
|
312
|
-
|
|
314
|
+
it("pattern renames should replace in place without reordering", () => {
|
|
315
|
+
const mutator = new OverrideEntryMutator(servers, 0);
|
|
316
|
+
const result = mutator.applyFieldChange(0, "pattern", "a-renamed");
|
|
317
|
+
expect(result).not.toBeNull();
|
|
318
|
+
expect(Object.keys(result!.next[0].overrides!)).toEqual(["a-renamed"]);
|
|
319
|
+
expect(result!.next[0].overrides!["a-renamed"]).toEqual({
|
|
320
|
+
reasoning: false,
|
|
313
321
|
});
|
|
314
|
-
expect(
|
|
315
|
-
expect(next[0].overrides!["a-renamed"]).toEqual({ reasoning: true });
|
|
316
|
-
expect(next[1]).toBe(servers[1]);
|
|
322
|
+
expect(result!.next[1]).toBe(servers[1]);
|
|
317
323
|
});
|
|
318
324
|
|
|
319
|
-
it("
|
|
320
|
-
const withTwo =
|
|
321
|
-
const next =
|
|
325
|
+
it("removeEntry should drop only the targeted entry", () => {
|
|
326
|
+
const withTwo = new OverrideEntryMutator(servers, 0).addEntry("a-2");
|
|
327
|
+
const next = new OverrideEntryMutator(withTwo, 0).removeEntry(0);
|
|
322
328
|
expect(Object.keys(next[0].overrides!)).toEqual(["a-2"]);
|
|
323
329
|
});
|
|
324
330
|
|
|
325
|
-
it("
|
|
326
|
-
|
|
327
|
-
expect(
|
|
328
|
-
expect(
|
|
329
|
-
expect(
|
|
330
|
-
expect(
|
|
331
|
+
it("CostField.validate should accept blank, non-negative numbers; reject the rest", () => {
|
|
332
|
+
const cost = OverrideFields.byId("cost.input");
|
|
333
|
+
expect(cost.validate("")).toBe("0");
|
|
334
|
+
expect(cost.validate(" 0.5 ")).toBe("0.5");
|
|
335
|
+
expect(cost.validate("-1")).toBeNull();
|
|
336
|
+
expect(cost.validate("abc")).toBeNull();
|
|
337
|
+
expect(cost.validate("Infinity")).toBeNull();
|
|
331
338
|
});
|
|
332
339
|
|
|
333
|
-
it("
|
|
334
|
-
const
|
|
335
|
-
|
|
340
|
+
it("CostField.apply should set a positive value, keeping other fields", () => {
|
|
341
|
+
const override: ModelOverride = { cost: { input: 0.2 } };
|
|
342
|
+
OverrideFields.byId("cost.output").apply(override, "0.6");
|
|
343
|
+
expect(override.cost).toEqual({ input: 0.2, output: 0.6 });
|
|
336
344
|
});
|
|
337
345
|
|
|
338
|
-
it("
|
|
339
|
-
const
|
|
340
|
-
|
|
346
|
+
it("CostField.apply should remove the field on zero", () => {
|
|
347
|
+
const override: ModelOverride = { cost: { input: 0.2, output: 0.6 } };
|
|
348
|
+
OverrideFields.byId("cost.input").apply(override, "0");
|
|
349
|
+
expect(override.cost).toEqual({ output: 0.6 });
|
|
341
350
|
});
|
|
342
351
|
|
|
343
|
-
it("
|
|
344
|
-
|
|
345
|
-
|
|
352
|
+
it("CostField.apply should drop the whole cost object when the last field is zeroed", () => {
|
|
353
|
+
const single: ModelOverride = { cost: { input: 0.2 } };
|
|
354
|
+
OverrideFields.byId("cost.input").apply(single, "0");
|
|
355
|
+
expect(single.cost).toBeUndefined();
|
|
356
|
+
|
|
357
|
+
const empty: ModelOverride = {};
|
|
358
|
+
OverrideFields.byId("cost.input").apply(empty, "0");
|
|
359
|
+
expect(empty.cost).toBeUndefined();
|
|
346
360
|
});
|
|
347
361
|
|
|
348
|
-
it("
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
});
|
|
362
|
+
it("CostField.apply should treat an empty override as unset cost", () => {
|
|
363
|
+
const override: ModelOverride = {};
|
|
364
|
+
OverrideFields.byId("cost.input").apply(override, "0.5");
|
|
365
|
+
expect(override.cost).toEqual({ input: 0.5 });
|
|
352
366
|
});
|
|
353
367
|
});
|
|
354
368
|
|
|
355
|
-
describe("
|
|
369
|
+
describe("OverrideField.displayValue", () => {
|
|
370
|
+
const display = (id: string, override: ModelOverride): string =>
|
|
371
|
+
OverrideFields.byId(id).displayValue(new OverrideEntry("gpt-*", override));
|
|
372
|
+
|
|
356
373
|
it("formats cost fields, defaulting to 0", () => {
|
|
357
|
-
expect(
|
|
358
|
-
expect(
|
|
359
|
-
|
|
360
|
-
);
|
|
361
|
-
expect(overrideFieldValue("cost.cacheWrite", {})).toBe("0");
|
|
374
|
+
expect(display("cost.input", {})).toBe("0");
|
|
375
|
+
expect(display("cost.input", { cost: { input: 0.2 } })).toBe("0.2");
|
|
376
|
+
expect(display("cost.cacheWrite", {})).toBe("0");
|
|
362
377
|
});
|
|
363
378
|
|
|
364
379
|
it("formats capabilities and reasoning labels", () => {
|
|
365
|
-
expect(
|
|
366
|
-
expect(
|
|
367
|
-
|
|
368
|
-
)
|
|
369
|
-
expect(
|
|
370
|
-
expect(
|
|
380
|
+
expect(display("capabilities", {})).toBe("text");
|
|
381
|
+
expect(display("capabilities", { capabilities: ["text", "image"] })).toBe(
|
|
382
|
+
"text | image",
|
|
383
|
+
);
|
|
384
|
+
expect(display("reasoning", {})).toBe("true");
|
|
385
|
+
expect(display("reasoning", { reasoning: false })).toBe("false");
|
|
371
386
|
});
|
|
372
387
|
|
|
373
388
|
it("formats maxTokens/contextSize, defaulting to 0", () => {
|
|
374
|
-
expect(
|
|
375
|
-
expect(
|
|
376
|
-
expect(
|
|
377
|
-
"8192",
|
|
378
|
-
);
|
|
389
|
+
expect(display("maxTokens", {})).toBe("0");
|
|
390
|
+
expect(display("maxTokens", { maxTokens: 4096 })).toBe("4096");
|
|
391
|
+
expect(display("contextSize", { contextSize: 8192 })).toBe("8192");
|
|
379
392
|
});
|
|
380
393
|
|
|
381
|
-
it("returns
|
|
382
|
-
expect(
|
|
394
|
+
it("returns the entry's pattern for the pattern field", () => {
|
|
395
|
+
expect(
|
|
396
|
+
OverrideFields.byId("pattern").displayValue(
|
|
397
|
+
new OverrideEntry("gpt-*", {}),
|
|
398
|
+
),
|
|
399
|
+
).toBe("gpt-*");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it("throws for unknown fields", () => {
|
|
403
|
+
expect(() => OverrideFields.byId("other")).toThrow(
|
|
404
|
+
"Unknown override field: other",
|
|
405
|
+
);
|
|
383
406
|
});
|
|
384
407
|
});
|