This commit is contained in:
k
2026-09-21 22:31:18 +02:00
parent c639f43891
commit 360f203ca2
7 changed files with 36 additions and 16 deletions
+3
View File
@@ -13,6 +13,9 @@ export interface DriverModel {
label: string;
/** Display category in the model picker (defaults to `driver`). */
group?: string;
/** True when served through the caller's own provider key (BYOK) rather
* than the platform key — the UI lists these in their own section. */
personal?: boolean;
}
export interface ChatOptions {
+8 -7
View File
@@ -1274,16 +1274,17 @@ const server = Bun.serve<{ ticketId: string | null; isAdmin: boolean }>({
// mutated by the per-user merge below.
const models = [...(await registry.listAllModelsCached(wantRefresh && admin))];
// Personal providers (BYOK): merge the caller's own-key models.
// Same ids as the global drivers, so already-listed ones are skipped
// and the model picker groups them with their driver.
// A personal entry replaces the platform entry with the same id so
// the menu shows one clearly-marked (personal: true) section per
// connected provider — matching /api/chat, which bills those ids
// to the personal key.
try {
const personal = await listUserProviderModels(user.id);
const seen = new Set(models.map((m) => m.id));
const at = new Map(models.map((m, i) => [m.id, i]));
for (const m of personal) {
if (!seen.has(m.id)) {
seen.add(m.id);
models.push(m);
}
const idx = at.get(m.id);
if (idx === undefined) models.push(m);
else models[idx] = m;
}
} catch {
// personal listing is best-effort — global models still served
+7 -4
View File
@@ -99,9 +99,10 @@ export function buildUserProviderDriver(provider: UserProviderId, apiKey: string
}
/**
* List models reachable with the user's own keys. Never throws: a failing
* provider is skipped (its driver falls back to a static list, and only a
* total failure is swallowed here).
* List models reachable with the user's own keys. Every entry is marked
* `personal: true` so the UI can list them in their own menu section.
* Never throws: a failing provider is skipped (its driver falls back to a
* static list, and only a total failure is swallowed here).
*/
export async function listUserProviderModels(userId: string): Promise<DriverModel[]> {
const out: DriverModel[] = [];
@@ -109,7 +110,9 @@ export async function listUserProviderModels(userId: string): Promise<DriverMode
const key = getUserProviderKey(userId, p);
if (!key) return;
try {
out.push(...(await buildUserProviderDriver(p, key).listModels()));
for (const m of await buildUserProviderDriver(p, key).listModels()) {
out.push({ ...m, personal: true });
}
} catch (e) {
console.error(`[providers] user ${p} listModels failed:`, (e as Error).message);
}