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:
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user