fix: address gemini native and route coverage regressions

This commit is contained in:
ciat-777
2026-03-15 21:47:00 +08:00
parent a64a51aa0c
commit 4b42751953
15 changed files with 1006 additions and 74 deletions
@@ -9,6 +9,7 @@ import {
buildApiPayload,
buildEmbeddingsRequestEnvelope,
buildFileUploadRequestEnvelope,
buildGeminiNativeConversationProxyEnvelope,
buildRawProxyRequestEnvelope,
buildSearchRequestEnvelope,
collectModelTesterModelNames,
@@ -321,6 +322,39 @@ describe('modelTesterSession', () => {
});
});
it('builds gemini native proxy envelope without loading assistant placeholders', () => {
const payload = buildGeminiNativeConversationProxyEnvelope(
[
{ id: 'u1', role: 'user', content: 'hello', createAt: 1 },
{ id: 'a1', role: 'assistant', content: '', createAt: 2, status: MESSAGE_STATUS.LOADING },
{ id: 'a2', role: 'assistant', content: 'partial', createAt: 3, status: MESSAGE_STATUS.INCOMPLETE },
{ id: 'a3', role: 'assistant', content: 'done', createAt: 4, status: MESSAGE_STATUS.COMPLETE },
],
{
...DEFAULT_INPUTS,
model: 'gemini-2.5-pro',
protocol: 'gemini',
systemPrompt: 'system text',
stream: true,
},
{
...DEFAULT_PARAMETER_ENABLED,
max_tokens: true,
},
);
expect(payload.path).toBe('/gemini/v1beta/models/gemini-2.5-pro:generateContent?alt=sse');
expect(payload.jobMode).toBe(false);
expect(payload.jsonBody).toEqual({
systemInstruction: { parts: [{ text: 'system text' }] },
contents: [
{ role: 'user', parts: [{ text: 'hello' }] },
{ role: 'model', parts: [{ text: 'done' }] },
],
generationConfig: { temperature: 0.7, maxOutputTokens: 4096 },
});
});
it('serializes conversation file parts into openai and responses payloads', () => {
const message = {
id: 'u1',
@@ -949,6 +949,19 @@ export const buildConversationRequestEnvelope = (
jsonBody: buildConversationJsonBody(messages, inputs, parameterEnabled),
});
export const buildGeminiNativeConversationProxyEnvelope = (
messages: ChatMessage[],
inputs: ModelTesterInputs,
parameterEnabled: ParameterEnabled,
): TesterProxyEnvelope => {
const envelope = buildConversationRequestEnvelope(messages, { ...inputs, protocol: 'gemini' }, parameterEnabled);
return {
...envelope,
path: `/gemini${envelope.path}${inputs.stream ? '?alt=sse' : ''}`,
jobMode: false,
};
};
export const buildEmbeddingsRequestEnvelope = (
inputText: string,
inputs: ModelTesterInputs,
@@ -16,6 +16,12 @@ export function buildVisibleRouteList<T extends RouteListVisibilityItem>(
isExactModelPattern: (pattern: string) => boolean,
matchesModelPattern: (model: string, pattern: string) => boolean,
): T[] {
const exactModelNames = new Set(
routes
.filter((route) => isExactModelPattern(route.modelPattern))
.map((route) => (route.modelPattern || '').trim())
.filter(Boolean),
);
const coveringGroups = routes.filter((route) => (
route.enabled
&& !isExactModelPattern(route.modelPattern)
@@ -33,6 +39,7 @@ export function buildVisibleRouteList<T extends RouteListVisibilityItem>(
return !coveringGroups.some((groupRoute) => (
groupRoute.id !== route.id
&& !exactModelNames.has((groupRoute.displayName || '').trim())
&& matchesModelPattern(exactModel, groupRoute.modelPattern)
));
});
@@ -3,6 +3,10 @@ export type MissingTokenModelAccount = {
username: string | null;
siteId: number;
siteName: string;
missingGroups?: string[];
requiredGroups?: string[];
availableGroups?: string[];
groupCoverageUncertain?: boolean;
};
export type MissingTokenModelsByName = Record<string, MissingTokenModelAccount[]>;
@@ -29,11 +33,21 @@ export function normalizeMissingTokenModels(
if (!account || !Number.isFinite(account.accountId)) continue;
const accountName = (account.username || '').trim();
const siteName = String(account.siteName || '').trim();
const normalizeLabels = (labels: unknown): string[] => Array.isArray(labels)
? Array.from(new Set(labels
.map((label) => String(label || '').trim())
.filter(Boolean)))
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))
: [];
accountMap.set(account.accountId, {
accountId: account.accountId,
username: accountName || null,
siteId: account.siteId,
siteName,
...(normalizeLabels(account.missingGroups).length > 0 ? { missingGroups: normalizeLabels(account.missingGroups) } : {}),
...(normalizeLabels(account.requiredGroups).length > 0 ? { requiredGroups: normalizeLabels(account.requiredGroups) } : {}),
...(normalizeLabels(account.availableGroups).length > 0 ? { availableGroups: normalizeLabels(account.availableGroups) } : {}),
...(account.groupCoverageUncertain === true ? { groupCoverageUncertain: true } : {}),
});
}
if (accountMap.size > 0) {