Spaces:
Runtime error
Runtime error
File size: 5,085 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import { NextResponse } from "next/server";
import { getModelAliases, setModelAlias, getProviderConnections } from "@/models";
import { AI_MODELS, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/models";
import { updateModelAliasSchema } from "@/shared/validation/schemas";
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
import { hasEligibleConnectionForModel } from "@/domain/connectionModelRules";
// GET /api/models - Get models with aliases (only from active providers by default)
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const showAll = searchParams.get("all") === "true";
const modelAliases = await getModelAliases();
// Get active provider connections to filter available models
let activeProviders: Set<string> | null = null;
if (!showAll) {
try {
const connections = await getProviderConnections();
const active = connections.filter((c: any) => c.isActive !== false);
// Include both provider IDs and their aliases in the active set.
// PROVIDER_MODELS keys are aliases (e.g. 'cc' for 'claude', 'gh' for 'github').
// DB connections are stored under provider IDs ('claude', 'github').
// Without this, models for aliased providers always appear unconfigured.
activeProviders = new Set<string>();
for (const c of active) {
const pId = String((c as Record<string, unknown>).provider);
activeProviders.add(pId);
const alias = PROVIDER_ID_TO_ALIAS[pId];
if (alias) activeProviders.add(alias);
}
const connectionsByProvider = new Map<string, typeof active>();
const registerConnectionKey = (
key: string | null | undefined,
connection: (typeof active)[number]
) => {
if (!key) return;
const existing = connectionsByProvider.get(key) || [];
existing.push(connection);
connectionsByProvider.set(key, existing);
};
for (const connection of active) {
registerConnectionKey(connection.provider, connection);
registerConnectionKey(PROVIDER_ID_TO_ALIAS[connection.provider], connection);
}
const getConnectionsForProvider = (...keys: Array<string | null | undefined>) => {
const seen = new Set<string>();
const collected: typeof active = [];
for (const key of keys) {
if (!key) continue;
for (const connection of connectionsByProvider.get(key) || []) {
if (!connection?.id || seen.has(connection.id)) continue;
seen.add(connection.id);
collected.push(connection);
}
}
return collected;
};
activeProviders = new Set(
AI_MODELS.flatMap((model: any) => {
const providerKeys = [model.provider, PROVIDER_ID_TO_ALIAS[model.provider]];
return hasEligibleConnectionForModel(
getConnectionsForProvider(...providerKeys),
model.model
)
? providerKeys.filter(Boolean)
: [];
})
);
} catch {
// If DB unavailable, show all models
}
}
const models = AI_MODELS.map((m: any) => {
const fullModel = `${m.provider}/${m.model}`;
const available = !activeProviders || activeProviders.has(m.provider);
return {
...m,
fullModel,
alias: modelAliases[fullModel] || m.model,
available,
};
}).filter((m: any) => showAll || m.available);
return NextResponse.json({ models });
} catch (error) {
console.log("Error fetching models:", error);
return NextResponse.json({ error: "Failed to fetch models" }, { status: 500 });
}
}
// PUT /api/models - Update model alias
export async function PUT(request) {
let rawBody;
try {
rawBody = await request.json();
} catch {
return NextResponse.json(
{
error: {
message: "Invalid request",
details: [{ field: "body", message: "Invalid JSON body" }],
},
},
{ status: 400 }
);
}
try {
const validation = validateBody(updateModelAliasSchema, rawBody);
if (isValidationFailure(validation)) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const { model, alias } = validation.data;
const modelAliases = await getModelAliases();
// Check if alias already exists for different model
const existingModel = Object.entries(modelAliases).find(
([key, val]) => val === alias && key !== model
);
if (existingModel) {
return NextResponse.json({ error: "Alias already in use" }, { status: 400 });
}
// Update alias
await setModelAlias(model, alias);
return NextResponse.json({ success: true, model, alias });
} catch (error) {
console.log("Error updating alias:", error);
return NextResponse.json({ error: "Failed to update alias" }, { status: 500 });
}
}
|