fix gateway loopback validation chains

This commit is contained in:
2026-05-11 08:48:02 +08:00
parent ff666b1ece
commit ca7e76e815
42 changed files with 1641 additions and 129 deletions
+19 -2
View File
@@ -49,6 +49,7 @@ import {
listPricingRules,
listPricingRuleSets,
listRuntimePolicySets,
listTasks,
listPublicBaseModels,
listPublicCatalogProviders,
listRateLimitWindows,
@@ -121,6 +122,7 @@ type DataKey =
| 'tenants'
| 'users'
| 'userGroups'
| 'tasks'
| 'accessRules'
| 'apiKeys';
@@ -157,6 +159,7 @@ export function App() {
const [selectedPlaygroundApiKeyId, setSelectedPlaygroundApiKeyId] = useState('');
const [taskForm, setTaskForm] = useState<TaskForm>({ kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '用一句话确认 AI Gateway simulation 链路正常。' });
const [taskResult, setTaskResult] = useState<GatewayTask | null>(null);
const [tasks, setTasks] = useState<GatewayTask[]>([]);
const [coreState, setCoreState] = useState<LoadState>('idle');
const [coreMessage, setCoreMessage] = useState('');
const [state, setState] = useState<LoadState>('idle');
@@ -228,10 +231,11 @@ export function App() {
rateLimitWindows,
runtimePolicySets,
taskResult,
tasks,
tenants,
userGroups,
users,
}), [accessRules, apiKeys, baseModels, models, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runtimePolicySets, taskResult, tenants, userGroups, users]);
}), [accessRules, apiKeys, baseModels, models, platforms, pricingRuleSets, pricingRules, providers, rateLimitWindows, runtimePolicySets, taskResult, tasks, tenants, userGroups, users]);
async function refresh(nextToken = token) {
await ensureRouteData(nextToken, true);
@@ -327,6 +331,9 @@ export function App() {
case 'userGroups':
setUserGroups((await listUserGroups(nextToken)).items);
return;
case 'tasks':
setTasks((await listTasks(nextToken)).items);
return;
case 'accessRules':
setAccessRules((await (activePage === 'workspace' && workspaceSection === 'apiKeys'
? listApiKeyAccessRules(nextToken)
@@ -628,6 +635,8 @@ export function App() {
const response = await runTask(credential, taskForm);
const detail = await getTask(credential, response.task.id);
setTaskResult(detail);
setTasks((current) => [detail, ...current.filter((item) => item.id !== detail.id)]);
invalidateDataKeys('tasks');
setCoreState('ready');
setCoreMessage(`${taskForm.kind} 已通过 ${apiKeySecret ? '本地 API Key' : '当前 Access Token'} 完成 simulation。`);
} catch (err) {
@@ -660,6 +669,7 @@ export function App() {
setApiKeySecretsById({});
setSelectedPlaygroundApiKeyId('');
setTaskResult(null);
setTasks([]);
setCoreMessage('');
navigatePath('/');
}
@@ -852,10 +862,16 @@ export function App() {
function platformModelIsSelected(model: PlatformModel, selectedModels: PlatformModelBindingInput[]) {
return selectedModels.some((selected) => {
if (selected.baseModelId && model.baseModelId) return selected.baseModelId === model.baseModelId;
return selected.modelName === model.modelName && selected.modelType === model.modelType;
return selected.modelName === model.modelName && sameModelTypes(selected.modelType, model.modelType);
});
}
function sameModelTypes(left: string[], right: string[]) {
if (left.length !== right.length) return false;
const rightSet = new Set(right);
return left.every((type) => rightSet.has(type));
}
function mergeExistingPlatformModelInput(input: PlatformModelBindingInput, currentModels: PlatformModel[], platformId: string): PlatformModelBindingInput {
const existing = currentModels.find((model) => model.platformId === platformId && platformModelIsSelected(model, [input]));
if (!existing) return input;
@@ -924,6 +940,7 @@ function dataKeysForRoute(
if (activePage === 'workspace') {
if (workspaceSection === 'overview') return ['users', 'userGroups', 'apiKeys'];
if (workspaceSection === 'apiKeys') return ['apiKeys', 'accessRules', 'playgroundModels'];
if (workspaceSection === 'tasks') return ['tasks'];
return [];
}