fix: harden multi-model chat selection
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { reserveConsultationModel } from "../src/lib/consultation-model-selection.ts";
|
||||
|
||||
test("rejects an unknown model before credit reservation", async () => {
|
||||
let reservationCalls = 0;
|
||||
|
||||
const result = await reserveConsultationModel(
|
||||
"removed-model",
|
||||
() => null,
|
||||
async () => {
|
||||
reservationCalls += 1;
|
||||
return { success: true };
|
||||
},
|
||||
);
|
||||
|
||||
assert.deepEqual(result, { status: "unavailable" });
|
||||
assert.equal(reservationCalls, 0);
|
||||
});
|
||||
|
||||
test("keeps the resolved agent model and ledger model id together", async () => {
|
||||
const model = { id: "deepseek-pro", model: "deepseek-v4-pro" };
|
||||
|
||||
const result = await reserveConsultationModel(
|
||||
"deepseek-pro",
|
||||
(modelId) => modelId === model.id ? model : null,
|
||||
async () => ({ success: true, credits: 4 }),
|
||||
);
|
||||
|
||||
assert.deepEqual(result, {
|
||||
status: "reserved",
|
||||
model,
|
||||
usageModelId: "deepseek-pro",
|
||||
reservation: { success: true, credits: 4 },
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,11 @@ test("resolves configured models while returning sanitized public metadata", ()
|
||||
});
|
||||
assert.equal(JSON.stringify(catalog.publicModels).includes("secret"), false);
|
||||
assert.equal(JSON.stringify(catalog.publicModels).includes("baseURL"), false);
|
||||
assert.equal(catalog.models[1]?.model, "openai/gpt-5-mini");
|
||||
assert.deepEqual(catalog.models[1]?.model, {
|
||||
providerId: "openai",
|
||||
modelId: "gpt-5-mini",
|
||||
apiKey: "openai-secret",
|
||||
});
|
||||
});
|
||||
|
||||
test("excludes an invalid catalog entry without leaking its secret", () => {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
SessionModelPersistenceQueue,
|
||||
persistSessionModelSelection,
|
||||
} from "../src/lib/session-model-persistence.ts";
|
||||
|
||||
test("persists only model_id for the owned session", async () => {
|
||||
const writes: unknown[] = [];
|
||||
|
||||
await persistSessionModelSelection(async (write) => {
|
||||
writes.push(write);
|
||||
return { found: true, error: null };
|
||||
}, "user-1", "session-1", "gpt-mini");
|
||||
|
||||
assert.deepEqual(writes, [{
|
||||
values: { model_id: "gpt-mini" },
|
||||
sessionId: "session-1",
|
||||
userId: "user-1",
|
||||
}]);
|
||||
});
|
||||
|
||||
test("serializes model writes for the same session", async () => {
|
||||
const queue = new SessionModelPersistenceQueue();
|
||||
const calls: string[] = [];
|
||||
let releaseFirst = () => {};
|
||||
const firstGate = new Promise<void>((resolve) => { releaseFirst = resolve; });
|
||||
|
||||
const first = queue.enqueue("session-1", async () => {
|
||||
calls.push("first");
|
||||
await firstGate;
|
||||
});
|
||||
const second = queue.enqueue("session-1", async () => {
|
||||
calls.push("second");
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
assert.deepEqual(calls, ["first"]);
|
||||
releaseFirst();
|
||||
await Promise.all([first, second]);
|
||||
assert.deepEqual(calls, ["first", "second"]);
|
||||
});
|
||||
|
||||
test("continues with the latest model write after an earlier sync fails", async () => {
|
||||
const queue = new SessionModelPersistenceQueue();
|
||||
const calls: string[] = [];
|
||||
|
||||
const failed = queue.enqueue("session-1", async () => {
|
||||
calls.push("failed");
|
||||
throw new Error("offline");
|
||||
});
|
||||
const latest = queue.enqueue("session-1", async () => {
|
||||
calls.push("latest");
|
||||
});
|
||||
|
||||
const results = await Promise.allSettled([failed, latest]);
|
||||
assert.equal(results[0]?.status, "rejected");
|
||||
assert.equal(results[1]?.status, "fulfilled");
|
||||
assert.deepEqual(calls, ["failed", "latest"]);
|
||||
});
|
||||
Reference in New Issue
Block a user