fix(validate): normalize provider backend ids
This commit is contained in:
parent
66409ca56b
commit
98a9c25cfe
7 changed files with 100 additions and 48 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { validateTeamName } from '@main/ipc/guards';
|
||||
import { getErrorMessage } from '@shared/utils/errorHandling';
|
||||
import { createLogger } from '@shared/utils/logger';
|
||||
import { migrateProviderBackendId } from '@shared/utils/providerBackend';
|
||||
import { isAbsolute } from 'path';
|
||||
|
||||
import type { HttpServices } from './index';
|
||||
|
|
@ -100,7 +101,13 @@ function parseLaunchRequest(teamName: string, body: unknown): TeamLaunchRequest
|
|||
throw new HttpBadRequestError('providerId must be anthropic, codex, or gemini');
|
||||
})();
|
||||
const prompt = assertOptionalString(payload.prompt, 'prompt');
|
||||
const providerBackendId = assertOptionalString(payload.providerBackendId, 'providerBackendId');
|
||||
const rawProviderBackendId = assertOptionalString(payload.providerBackendId, 'providerBackendId');
|
||||
const providerBackendId = migrateProviderBackendId(providerId, rawProviderBackendId);
|
||||
if (rawProviderBackendId && !providerBackendId) {
|
||||
throw new HttpBadRequestError(
|
||||
'providerBackendId must be one of auto, adapter, api, cli-sdk, or codex-native'
|
||||
);
|
||||
}
|
||||
const model = assertOptionalString(payload.model, 'model');
|
||||
const effort = assertOptionalEffort(payload.effort);
|
||||
const clearContext = assertOptionalBoolean(payload.clearContext, 'clearContext');
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ import {
|
|||
PROTECTED_CLI_FLAGS,
|
||||
} from '@shared/utils/cliArgsParser';
|
||||
import { createLogger } from '@shared/utils/logger';
|
||||
import { migrateProviderBackendId } from '@shared/utils/providerBackend';
|
||||
import { isTeamProviderBackendId, migrateProviderBackendId } from '@shared/utils/providerBackend';
|
||||
import { isRateLimitMessage } from '@shared/utils/rateLimitDetector';
|
||||
import {
|
||||
buildStandaloneSlashCommandMeta,
|
||||
|
|
@ -186,6 +186,8 @@ import type {
|
|||
TeamLaunchResponse,
|
||||
TeamMemberActivityMeta,
|
||||
TeamMessageNotificationData,
|
||||
TeamProviderBackendId,
|
||||
TeamProviderId,
|
||||
TeamProvisioningPrepareResult,
|
||||
TeamProvisioningProgress,
|
||||
TeamSummary,
|
||||
|
|
@ -1131,8 +1133,9 @@ function parseOptionalMemberProviderId(
|
|||
}
|
||||
|
||||
function parseOptionalProviderBackendId(
|
||||
value: unknown
|
||||
): { valid: true; value: string | undefined } | { valid: false; error: string } {
|
||||
value: unknown,
|
||||
providerId?: TeamProviderId
|
||||
): { valid: true; value: TeamProviderBackendId | undefined } | { valid: false; error: string } {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return { valid: true, value: undefined };
|
||||
}
|
||||
|
|
@ -1146,7 +1149,19 @@ function parseOptionalProviderBackendId(
|
|||
if (trimmed.length > 64) {
|
||||
return { valid: false, error: 'providerBackendId too long (max 64)' };
|
||||
}
|
||||
return { valid: true, value: trimmed };
|
||||
if (providerId) {
|
||||
const migratedBackendId = migrateProviderBackendId(providerId, trimmed);
|
||||
if (migratedBackendId) {
|
||||
return { valid: true, value: migratedBackendId };
|
||||
}
|
||||
} else if (isTeamProviderBackendId(trimmed)) {
|
||||
return { valid: true, value: trimmed };
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
error: 'providerBackendId must be one of auto, adapter, api, cli-sdk, or codex-native',
|
||||
};
|
||||
}
|
||||
|
||||
function parseOptionalMemberEffort(
|
||||
|
|
@ -1242,7 +1257,16 @@ async function validateProvisioningRequest(
|
|||
if (payload.prompt !== undefined && typeof payload.prompt !== 'string') {
|
||||
return { valid: false, error: 'prompt must be a string' };
|
||||
}
|
||||
const providerBackendValidation = parseOptionalProviderBackendId(payload.providerBackendId);
|
||||
const providerId =
|
||||
payload.providerId === 'codex'
|
||||
? 'codex'
|
||||
: payload.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic';
|
||||
const providerBackendValidation = parseOptionalProviderBackendId(
|
||||
payload.providerBackendId,
|
||||
providerId
|
||||
);
|
||||
if (!providerBackendValidation.valid) {
|
||||
return { valid: false, error: providerBackendValidation.error };
|
||||
}
|
||||
|
|
@ -1297,12 +1321,7 @@ async function validateProvisioningRequest(
|
|||
members,
|
||||
cwd,
|
||||
prompt: typeof payload.prompt === 'string' ? payload.prompt.trim() || undefined : undefined,
|
||||
providerId:
|
||||
payload.providerId === 'codex'
|
||||
? 'codex'
|
||||
: payload.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic',
|
||||
providerId,
|
||||
providerBackendId: providerBackendValidation.value,
|
||||
model: typeof payload.model === 'string' ? payload.model.trim() || undefined : undefined,
|
||||
effort: isValidEffort(payload.effort) ? payload.effort : undefined,
|
||||
|
|
@ -1413,7 +1432,16 @@ async function handleLaunchTeam(
|
|||
if (payload.model !== undefined && typeof payload.model !== 'string') {
|
||||
return { success: false, error: 'model must be a string' };
|
||||
}
|
||||
const providerBackendValidation = parseOptionalProviderBackendId(payload.providerBackendId);
|
||||
const providerId =
|
||||
payload.providerId === 'codex'
|
||||
? 'codex'
|
||||
: payload.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic';
|
||||
const providerBackendValidation = parseOptionalProviderBackendId(
|
||||
payload.providerBackendId,
|
||||
providerId
|
||||
);
|
||||
if (!providerBackendValidation.valid) {
|
||||
return { success: false, error: providerBackendValidation.error };
|
||||
}
|
||||
|
|
@ -1439,15 +1467,13 @@ async function handleLaunchTeam(
|
|||
const members = membersMeta?.members ?? [];
|
||||
|
||||
const resolvedProviderId =
|
||||
payload.providerId === 'codex'
|
||||
? 'codex'
|
||||
: payload.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: meta?.providerId === 'codex'
|
||||
? 'codex'
|
||||
: meta?.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic';
|
||||
providerId === 'codex' || providerId === 'gemini'
|
||||
? providerId
|
||||
: meta?.providerId === 'codex'
|
||||
? 'codex'
|
||||
: meta?.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic';
|
||||
|
||||
const createRequest: TeamCreateRequest = {
|
||||
teamName: tn,
|
||||
|
|
@ -1501,12 +1527,7 @@ async function handleLaunchTeam(
|
|||
teamName: validatedTeamName.value!,
|
||||
cwd,
|
||||
prompt: typeof payload.prompt === 'string' ? payload.prompt.trim() || undefined : undefined,
|
||||
providerId:
|
||||
payload.providerId === 'codex'
|
||||
? 'codex'
|
||||
: payload.providerId === 'gemini'
|
||||
? 'gemini'
|
||||
: 'anthropic',
|
||||
providerId,
|
||||
providerBackendId: providerBackendValidation.value,
|
||||
model: typeof payload.model === 'string' ? payload.model.trim() || undefined : undefined,
|
||||
effort: isValidEffort(payload.effort) ? payload.effort : undefined,
|
||||
|
|
|
|||
|
|
@ -38,10 +38,9 @@ import { getMemberColorByName } from '@shared/constants/memberColors';
|
|||
import { DEFAULT_TOOL_APPROVAL_SETTINGS } from '@shared/types/team';
|
||||
import { resolveLanguageName } from '@shared/utils/agentLanguage';
|
||||
import { getAnthropicDefaultTeamModel } from '@shared/utils/anthropicModelDefaults';
|
||||
import { getErrorMessage } from '@shared/utils/errorHandling';
|
||||
import { buildTeamMemberColorMap } from '@shared/utils/teamMemberColors';
|
||||
import { parseCliArgs } from '@shared/utils/cliArgsParser';
|
||||
import { deriveContextMetrics, inferContextWindowTokens } from '@shared/utils/contextMetrics';
|
||||
import { getErrorMessage } from '@shared/utils/errorHandling';
|
||||
import {
|
||||
isInboxNoiseMessage,
|
||||
isMeaningfulBootstrapCheckInMessage,
|
||||
|
|
@ -57,6 +56,7 @@ import {
|
|||
parseAllTeammateMessages,
|
||||
type ParsedTeammateContent,
|
||||
} from '@shared/utils/teammateMessageParser';
|
||||
import { buildTeamMemberColorMap } from '@shared/utils/teamMemberColors';
|
||||
import { createCliAutoSuffixNameGuard, parseNumericSuffixName } from '@shared/utils/teamMemberName';
|
||||
import { normalizeOptionalTeamProviderId } from '@shared/utils/teamProvider';
|
||||
import {
|
||||
|
|
@ -4540,7 +4540,10 @@ export class TeamProvisioningService {
|
|||
teamName,
|
||||
updatedAt,
|
||||
runId: run?.runId ?? null,
|
||||
providerBackendId: run?.request.providerBackendId ?? persistedTeamMeta?.providerBackendId,
|
||||
providerBackendId: migrateProviderBackendId(
|
||||
run?.request.providerId ?? persistedTeamMeta?.providerId,
|
||||
run?.request.providerBackendId ?? persistedTeamMeta?.providerBackendId
|
||||
),
|
||||
members: snapshotMembers,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -50,14 +50,15 @@ import {
|
|||
normalizeCreateLaunchProviderForUi,
|
||||
} from '@renderer/utils/geminiUiFreeze';
|
||||
import { normalizePath } from '@renderer/utils/pathNormalize';
|
||||
import { nameColorSet } from '@renderer/utils/projectColor';
|
||||
import { resolveUiOwnedProviderBackendId } from '@renderer/utils/providerBackendIdentity';
|
||||
import { refreshCliStatusForCurrentMode } from '@renderer/utils/refreshCliStatus';
|
||||
import { nameColorSet } from '@renderer/utils/projectColor';
|
||||
import {
|
||||
getTeamModelSelectionError,
|
||||
normalizeExplicitTeamModelForUi,
|
||||
} from '@renderer/utils/teamModelAvailability';
|
||||
import { getTeamProviderLabel as getCatalogTeamProviderLabel } from '@renderer/utils/teamModelCatalog';
|
||||
import { migrateProviderBackendId } from '@shared/utils/providerBackend';
|
||||
import { DEFAULT_PROVIDER_MODEL_SELECTION } from '@shared/utils/providerModelSelection';
|
||||
import { isTeamProviderId, normalizeOptionalTeamProviderId } from '@shared/utils/teamProvider';
|
||||
import {
|
||||
|
|
@ -1454,8 +1455,10 @@ export const LaunchTeamDialog = (props: LaunchTeamDialogProps): React.JSX.Elemen
|
|||
selectedProviderId,
|
||||
runtimeProviderStatusById.get(selectedProviderId)
|
||||
) ??
|
||||
previousLaunchParams?.providerBackendId ??
|
||||
savedLaunchProviderBackendId ??
|
||||
migrateProviderBackendId(
|
||||
selectedProviderId,
|
||||
previousLaunchParams?.providerBackendId ?? savedLaunchProviderBackendId
|
||||
) ??
|
||||
undefined,
|
||||
model: computeEffectiveTeamModel(selectedModel, limitContext, selectedProviderId),
|
||||
effort: (selectedEffort as EffortLevel) || undefined,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import {
|
||||
formatProviderBackendLabel,
|
||||
getDefaultProviderBackendId,
|
||||
isTeamProviderBackendId,
|
||||
migrateProviderBackendId,
|
||||
} from '@shared/utils/providerBackend';
|
||||
|
||||
import type { CliProviderStatus, TeamProviderId } from '@shared/types';
|
||||
import type { CliProviderStatus, TeamProviderBackendId, TeamProviderId } from '@shared/types';
|
||||
|
||||
function normalizeOptionalBackendId(value: string | null | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
|
|
@ -15,14 +16,17 @@ export { formatProviderBackendLabel, getDefaultProviderBackendId };
|
|||
|
||||
export function resolveEffectiveProviderBackendId(
|
||||
provider: Pick<CliProviderStatus, 'selectedBackendId' | 'resolvedBackendId'> | null | undefined
|
||||
): string | undefined {
|
||||
return normalizeOptionalBackendId(provider?.resolvedBackendId ?? provider?.selectedBackendId);
|
||||
): TeamProviderBackendId | undefined {
|
||||
const backendId = normalizeOptionalBackendId(
|
||||
provider?.resolvedBackendId ?? provider?.selectedBackendId
|
||||
);
|
||||
return isTeamProviderBackendId(backendId) ? backendId : undefined;
|
||||
}
|
||||
|
||||
export function resolveUiOwnedProviderBackendId(
|
||||
providerId: TeamProviderId | CliProviderStatus['providerId'] | undefined,
|
||||
provider: Pick<CliProviderStatus, 'selectedBackendId' | 'resolvedBackendId'> | null | undefined
|
||||
): string | undefined {
|
||||
): TeamProviderBackendId | undefined {
|
||||
return migrateProviderBackendId(
|
||||
providerId,
|
||||
provider?.selectedBackendId ?? provider?.resolvedBackendId
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ export interface TeamViewSnapshot {
|
|||
|
||||
export type EffortLevel = 'low' | 'medium' | 'high';
|
||||
export type TeamProviderId = 'anthropic' | 'codex' | 'gemini';
|
||||
export type TeamProviderBackendId = string;
|
||||
export type TeamProviderBackendId = 'auto' | 'adapter' | 'api' | 'cli-sdk' | 'codex-native';
|
||||
|
||||
export interface TeamLaunchRequest {
|
||||
teamName: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
import type { TeamProviderId } from '@shared/types';
|
||||
import type { TeamProviderBackendId, TeamProviderId } from '@shared/types';
|
||||
|
||||
type RuntimeProviderId = TeamProviderId;
|
||||
const TEAM_PROVIDER_BACKEND_IDS = new Set<TeamProviderBackendId>([
|
||||
'auto',
|
||||
'adapter',
|
||||
'api',
|
||||
'cli-sdk',
|
||||
'codex-native',
|
||||
]);
|
||||
|
||||
function normalizeOptionalBackendId(value: unknown): string | undefined {
|
||||
if (typeof value !== 'string') {
|
||||
|
|
@ -11,8 +17,8 @@ function normalizeOptionalBackendId(value: unknown): string | undefined {
|
|||
}
|
||||
|
||||
export function getDefaultProviderBackendId(
|
||||
providerId: TeamProviderId | RuntimeProviderId | undefined
|
||||
): string | undefined {
|
||||
providerId: TeamProviderId | undefined
|
||||
): TeamProviderBackendId | undefined {
|
||||
return providerId === 'codex' ? 'codex-native' : undefined;
|
||||
}
|
||||
|
||||
|
|
@ -27,20 +33,28 @@ export function isLegacyCodexProviderBackendId(
|
|||
);
|
||||
}
|
||||
|
||||
export function migrateProviderBackendId(
|
||||
providerId: TeamProviderId | RuntimeProviderId | undefined,
|
||||
export function isTeamProviderBackendId(
|
||||
providerBackendId: string | null | undefined
|
||||
): string | undefined {
|
||||
): providerBackendId is TeamProviderBackendId {
|
||||
return (
|
||||
!!providerBackendId && TEAM_PROVIDER_BACKEND_IDS.has(providerBackendId as TeamProviderBackendId)
|
||||
);
|
||||
}
|
||||
|
||||
export function migrateProviderBackendId(
|
||||
providerId: TeamProviderId | undefined,
|
||||
providerBackendId: string | null | undefined
|
||||
): TeamProviderBackendId | undefined {
|
||||
const normalizedBackendId = normalizeOptionalBackendId(providerBackendId);
|
||||
if (providerId !== 'codex') {
|
||||
return normalizedBackendId;
|
||||
return isTeamProviderBackendId(normalizedBackendId) ? normalizedBackendId : undefined;
|
||||
}
|
||||
|
||||
if (!normalizedBackendId || isLegacyCodexProviderBackendId(normalizedBackendId)) {
|
||||
return 'codex-native';
|
||||
}
|
||||
|
||||
return normalizedBackendId;
|
||||
return isTeamProviderBackendId(normalizedBackendId) ? normalizedBackendId : undefined;
|
||||
}
|
||||
|
||||
export function formatProviderBackendLabel(
|
||||
|
|
|
|||
Loading…
Reference in a new issue