fix(team): propagate cross-provider member args to lead subprocess

* fix(team): propagate cross-provider member args to lead subprocess

When a team has an anthropic lead and codex teammates, the lead was
launched without --settings {"codex":{"forced_login_method":"chatgpt"}}.
buildInheritedCliFlags in the lead had nothing to pass to the codex
teammate, which started without knowing the required auth method and
crashed with "no CODEX_API_KEY or OPENAI_API_KEY configured".

Adds buildCrossProviderMemberArgs that collects provider launch args for
member providers that differ from the primary, and merges them into the
lead's launch args so they propagate to teammates via buildInheritedCliFlags.

* fix: log cross-provider env resolution failures instead of silently swallowing
This commit is contained in:
Artem Rootman 2026-04-28 11:26:52 +00:00 committed by GitHub
parent 82f73e58c2
commit 6c43380846
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -12947,6 +12947,16 @@ export class TeamProvisioningService {
}
launchArgs.push(...parseCliArgs(request.extraCliArgs));
launchArgs.push(...providerArgs);
// When the lead uses a different provider than some teammates (e.g., anthropic lead
// with codex teammates), the lead needs the teammate provider's launch args so they
// can be inherited by the teammate subprocess via buildInheritedCliFlags.
// Without this, a codex teammate spawned from an anthropic lead has no way to learn
// about the required forced_login_method (chatgpt/api) and fails to start.
const crossProviderMemberArgs = await this.buildCrossProviderMemberArgs(
resolvedProviderId,
effectiveMemberSpecs
);
launchArgs.push(...crossProviderMemberArgs);
const finalLaunchArgs = mergeJsonSettingsArgs(launchArgs);
const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, {
geminiRuntimeAuth,
@ -21417,6 +21427,37 @@ export class TeamProvisioningService {
};
}
private async buildCrossProviderMemberArgs(
primaryProviderId: TeamProviderId,
memberSpecs: TeamCreateRequest['members']
): Promise<string[]> {
const crossProviderIds = new Set<TeamProviderId>();
for (const member of memberSpecs) {
const memberId = resolveTeamProviderId(
normalizeTeamMemberProviderId(member.providerId) ?? primaryProviderId
);
if (memberId !== primaryProviderId) {
crossProviderIds.add(memberId);
}
}
const args: string[] = [];
for (const providerId of crossProviderIds) {
try {
const env = await this.buildProvisioningEnv(providerId);
if (env.providerArgs) {
args.push(...env.providerArgs);
}
} catch (error) {
console.error(
`[TeamProvisioningService] Failed to build cross-provider args for provider "${providerId}"`,
error
);
// Best-effort: don't block launch if cross-provider env resolution fails
}
}
return args;
}
private async resolveControlApiBaseUrl(): Promise<string | null> {
if (!this.controlApiBaseUrlResolver) {
return null;