fix: align explicit group route picker and details (#158)

* fix: align explicit group route picker and details

* fix: move responses stream closeout into transformer facade
This commit is contained in:
Cita
2026-03-19 00:47:22 +08:00
committed by GitHub
parent 45fe687c0d
commit c0c993f448
12 changed files with 1065 additions and 199 deletions
@@ -244,6 +244,75 @@ describe('PUT /api/routes/:id route rebuild', () => {
]));
});
it('fills missing sourceModel from source exact routes when loading explicit-group channels', async () => {
const sourceA = await seedAccountWithToken('deepseek-chat');
const sourceB = await seedAccountWithToken('deepseek-reasoner');
const exactRouteA = await db.insert(schema.tokenRoutes).values({
modelPattern: 'deepseek-chat',
enabled: true,
}).returning().get();
const exactRouteB = await db.insert(schema.tokenRoutes).values({
modelPattern: 'deepseek-reasoner',
enabled: true,
}).returning().get();
await db.insert(schema.routeChannels).values([
{
routeId: exactRouteA.id,
accountId: sourceA.account.id,
tokenId: sourceA.token.id,
sourceModel: null,
priority: 0,
weight: 10,
enabled: true,
manualOverride: false,
},
{
routeId: exactRouteB.id,
accountId: sourceB.account.id,
tokenId: sourceB.token.id,
sourceModel: null,
priority: 1,
weight: 8,
enabled: true,
manualOverride: false,
},
]).run();
const createResponse = await app.inject({
method: 'POST',
url: '/api/routes',
payload: {
routeMode: 'explicit_group',
displayName: 'deepseekv1',
sourceRouteIds: [exactRouteA.id, exactRouteB.id],
},
});
expect(createResponse.statusCode).toBe(200);
const createdRouteId = (createResponse.json() as { id: number }).id;
const channelsResponse = await app.inject({
method: 'GET',
url: `/api/routes/${createdRouteId}/channels`,
});
expect(channelsResponse.statusCode).toBe(200);
expect(channelsResponse.json()).toEqual(expect.arrayContaining([
expect.objectContaining({
routeId: exactRouteA.id,
accountId: sourceA.account.id,
sourceModel: 'deepseek-chat',
}),
expect.objectContaining({
routeId: exactRouteB.id,
accountId: sourceB.account.id,
sourceModel: 'deepseek-reasoner',
}),
]));
});
it('rejects invalid explicit-group payloads', async () => {
const response = await app.inject({
method: 'POST',
+20 -5
View File
@@ -534,7 +534,7 @@ async function fetchChannelsForRouteRows(routes: RouteRow[]): Promise<Map<number
const explicitSourceRouteIds = Array.from(new Set(routes
.filter((route) => isExplicitGroupRoute(route))
.flatMap((route) => route.sourceRouteIds)));
const enabledExplicitSourceRouteIds = explicitSourceRouteIds.length > 0
const explicitSourceRoutes = explicitSourceRouteIds.length > 0
? (await db.select({
id: schema.tokenRoutes.id,
modelPattern: schema.tokenRoutes.modelPattern,
@@ -543,9 +543,10 @@ async function fetchChannelsForRouteRows(routes: RouteRow[]): Promise<Map<number
}).from(schema.tokenRoutes)
.where(inArray(schema.tokenRoutes.id, explicitSourceRouteIds))
.all())
.filter((route) => route.enabled && !isExplicitGroupRoute(route) && isExactModelPattern(route.modelPattern))
.map((route) => route.id)
: [];
const enabledExplicitSourceRouteIds = explicitSourceRoutes
.filter((route) => route.enabled && !isExplicitGroupRoute(route) && isExactModelPattern(route.modelPattern))
.map((route) => route.id);
const actualRouteIds = Array.from(new Set([
...routes.filter((route) => !isExplicitGroupRoute(route)).map((route) => route.id),
...enabledExplicitSourceRouteIds,
@@ -554,6 +555,14 @@ async function fetchChannelsForRouteRows(routes: RouteRow[]): Promise<Map<number
return new Map(routes.map((route) => [route.id, []]));
}
const actualRouteById = new Map<number, { modelPattern: string; routeMode: string | null }>();
for (const route of routes.filter((item) => !isExplicitGroupRoute(item))) {
actualRouteById.set(route.id, { modelPattern: route.modelPattern, routeMode: route.routeMode ?? null });
}
for (const route of explicitSourceRoutes) {
actualRouteById.set(route.id, { modelPattern: route.modelPattern, routeMode: route.routeMode ?? null });
}
const channelRows = await db.select().from(schema.routeChannels)
.innerJoin(schema.accounts, eq(schema.routeChannels.accountId, schema.accounts.id))
.innerJoin(schema.sites, eq(schema.accounts.siteId, schema.sites.id))
@@ -565,13 +574,19 @@ async function fetchChannelsForRouteRows(routes: RouteRow[]): Promise<Map<number
for (const row of channelRows) {
const routeId = row.route_channels.routeId;
const actualRoute = actualRouteById.get(routeId);
const fallbackSourceModel = actualRoute && !isExplicitGroupRoute(actualRoute) && isExactModelPattern(actualRoute.modelPattern)
? actualRoute.modelPattern
: null;
const resolvedSourceModel = (row.route_channels.sourceModel || fallbackSourceModel || '').trim();
if (!channelsByActualRouteId.has(routeId)) channelsByActualRouteId.set(routeId, []);
channelsByActualRouteId.get(routeId)!.push({
...row.route_channels,
sourceModel: resolvedSourceModel || null,
account: row.accounts,
site: row.sites,
token: row.account_tokens
? {
token: row.account_tokens
? {
id: row.account_tokens.id,
name: row.account_tokens.name,
accountId: row.account_tokens.accountId,