forked from boos/BoosAPI
Merge pull request #207 from cita-777/codex/issue-200-group-route-alias
[codex] fix explicit-group source-model fallback
This commit is contained in:
@@ -93,6 +93,27 @@ describe('TokenRouter patterns and model mapping', () => {
|
|||||||
return { route, channel };
|
return { route, channel };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createExplicitGroupRoute(
|
||||||
|
displayName: string,
|
||||||
|
sourceRouteIds: number[],
|
||||||
|
) {
|
||||||
|
const route = await db.insert(schema.tokenRoutes).values({
|
||||||
|
modelPattern: displayName,
|
||||||
|
displayName,
|
||||||
|
routeMode: 'explicit_group',
|
||||||
|
enabled: true,
|
||||||
|
}).returning().get();
|
||||||
|
|
||||||
|
await db.insert(schema.routeGroupSources).values(
|
||||||
|
sourceRouteIds.map((sourceRouteId) => ({
|
||||||
|
groupRouteId: route.id,
|
||||||
|
sourceRouteId,
|
||||||
|
})),
|
||||||
|
).run();
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
it('matches routes with re: regex patterns', async () => {
|
it('matches routes with re: regex patterns', async () => {
|
||||||
await createRouteWithSingleChannel('re:^claude-(opus|sonnet)-4-6$');
|
await createRouteWithSingleChannel('re:^claude-(opus|sonnet)-4-6$');
|
||||||
const router = new TokenRouter();
|
const router = new TokenRouter();
|
||||||
@@ -181,4 +202,19 @@ describe('TokenRouter patterns and model mapping', () => {
|
|||||||
expect(selected?.actualModel).toBe('claude-opus-4-6');
|
expect(selected?.actualModel).toBe('claude-opus-4-6');
|
||||||
expect(decision.actualModel).toBe('claude-opus-4-6');
|
expect(decision.actualModel).toBe('claude-opus-4-6');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('falls back to the source exact-route model when explicit-group channels omit sourceModel', async () => {
|
||||||
|
const source = await createRouteWithSingleChannel('claude-opus-4-5');
|
||||||
|
await createExplicitGroupRoute('claude-test-4.6-sonnet', [source.route.id]);
|
||||||
|
const router = new TokenRouter();
|
||||||
|
|
||||||
|
const selected = await router.selectChannel('claude-test-4.6-sonnet');
|
||||||
|
const decision = await router.explainSelection('claude-test-4.6-sonnet');
|
||||||
|
|
||||||
|
expect(selected).toBeTruthy();
|
||||||
|
expect(selected?.actualModel).toBe('claude-opus-4-5');
|
||||||
|
expect(decision.actualModel).toBe('claude-opus-4-5');
|
||||||
|
expect(decision.summary).toContain('按显示名命中:claude-test-4.6-sonnet');
|
||||||
|
expect(decision.summary).toContain('实际转发模型:claude-opus-4-5');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -748,21 +748,26 @@ async function loadRouteMatch(route: RouteRow, nowMs = Date.now()): Promise<Rout
|
|||||||
return cached.match;
|
return cached.match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enabledRoutes = await loadEnabledRoutes(nowMs);
|
||||||
const routeIds = (() => {
|
const routeIds = (() => {
|
||||||
if (!isExplicitGroupRoute(route)) {
|
if (!isExplicitGroupRoute(route)) {
|
||||||
return [route.id];
|
return [route.id];
|
||||||
}
|
}
|
||||||
return Array.from(new Set(route.sourceRouteIds.filter((routeId) => Number.isFinite(routeId) && routeId > 0)));
|
return Array.from(new Set(route.sourceRouteIds.filter((routeId) => Number.isFinite(routeId) && routeId > 0)));
|
||||||
})();
|
})();
|
||||||
const enabledSourceRouteIds = isExplicitGroupRoute(route)
|
const enabledSourceRoutes = isExplicitGroupRoute(route)
|
||||||
? (await loadEnabledRoutes(nowMs))
|
? enabledRoutes.filter((item) => (
|
||||||
.filter((item) => (
|
routeIds.includes(item.id)
|
||||||
routeIds.includes(item.id)
|
&& !isExplicitGroupRoute(item)
|
||||||
&& !isExplicitGroupRoute(item)
|
&& isExactRouteModelPattern(item.modelPattern)
|
||||||
&& isExactRouteModelPattern(item.modelPattern)
|
))
|
||||||
))
|
: enabledRoutes.filter((item) => routeIds.includes(item.id));
|
||||||
.map((item) => item.id)
|
const enabledSourceRouteIds = enabledSourceRoutes.map((item) => item.id);
|
||||||
: routeIds;
|
const fallbackSourceModelByRouteId = new Map<number, string>(
|
||||||
|
enabledSourceRoutes
|
||||||
|
.filter((item) => isExactRouteModelPattern(item.modelPattern))
|
||||||
|
.map((item) => [item.id, (item.modelPattern || '').trim()]),
|
||||||
|
);
|
||||||
const channels = enabledSourceRouteIds.length > 0
|
const channels = enabledSourceRouteIds.length > 0
|
||||||
? await db
|
? await db
|
||||||
.select()
|
.select()
|
||||||
@@ -774,12 +779,17 @@ async function loadRouteMatch(route: RouteRow, nowMs = Date.now()): Promise<Rout
|
|||||||
.all()
|
.all()
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const mapped = channels.map((row) => ({
|
const mapped = channels.map((row) => ({
|
||||||
channel: row.route_channels,
|
channel: {
|
||||||
account: row.accounts,
|
...row.route_channels,
|
||||||
site: row.sites,
|
sourceModel: normalizeChannelSourceModel(row.route_channels.sourceModel)
|
||||||
token: row.account_tokens,
|
|| fallbackSourceModelByRouteId.get(row.route_channels.routeId)
|
||||||
}));
|
|| null,
|
||||||
|
},
|
||||||
|
account: row.accounts,
|
||||||
|
site: row.sites,
|
||||||
|
token: row.account_tokens,
|
||||||
|
}));
|
||||||
|
|
||||||
const match = { route, channels: mapped };
|
const match = { route, channels: mapped };
|
||||||
routeMatchCache.set(route.id, {
|
routeMatchCache.set(route.id, {
|
||||||
|
|||||||
Reference in New Issue
Block a user