diff --git a/runtime.lock.json b/runtime.lock.json index 0bd8b72d..639b8e59 100644 --- a/runtime.lock.json +++ b/runtime.lock.json @@ -1,27 +1,27 @@ { - "version": "0.0.28", - "sourceRef": "v0.0.28", + "version": "0.0.29", + "sourceRef": "v0.0.29", "sourceRepository": "777genius/agent_teams_orchestrator", "releaseRepository": "777genius/agent-teams-ai", "releaseTag": "v1.2.0", "assets": { "darwin-arm64": { - "file": "agent-teams-runtime-darwin-arm64-v0.0.28.tar.gz", + "file": "agent-teams-runtime-darwin-arm64-v0.0.29.tar.gz", "archiveKind": "tar.gz", "binaryName": "claude-multimodel" }, "darwin-x64": { - "file": "agent-teams-runtime-darwin-x64-v0.0.28.tar.gz", + "file": "agent-teams-runtime-darwin-x64-v0.0.29.tar.gz", "archiveKind": "tar.gz", "binaryName": "claude-multimodel" }, "linux-x64": { - "file": "agent-teams-runtime-linux-x64-v0.0.28.tar.gz", + "file": "agent-teams-runtime-linux-x64-v0.0.29.tar.gz", "archiveKind": "tar.gz", "binaryName": "claude-multimodel" }, "win32-x64": { - "file": "agent-teams-runtime-win32-x64-v0.0.28.zip", + "file": "agent-teams-runtime-win32-x64-v0.0.29.zip", "archiveKind": "zip", "binaryName": "claude-multimodel.exe" } diff --git a/src/main/services/runtime/providerRuntimeEnv.test.ts b/src/main/services/runtime/providerRuntimeEnv.test.ts new file mode 100644 index 00000000..f3cf4444 --- /dev/null +++ b/src/main/services/runtime/providerRuntimeEnv.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from 'vitest'; + +import { applyProviderRuntimeEnv } from './providerRuntimeEnv'; + +describe('applyProviderRuntimeEnv', () => { + it('preserves Bedrock as an Anthropic runtime backend', () => { + const env: NodeJS.ProcessEnv = { + CLAUDE_CODE_USE_BEDROCK: '1', + AWS_PROFILE: 'cc', + AWS_REGION: 'us-east-1', + }; + + applyProviderRuntimeEnv(env, 'anthropic'); + + expect(env.CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST).toBe('1'); + expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('bedrock'); + expect(env.CLAUDE_CODE_USE_BEDROCK).toBe('1'); + expect(env.CLAUDE_CODE_USE_VERTEX).toBeUndefined(); + expect(env.CLAUDE_CODE_USE_FOUNDRY).toBeUndefined(); + expect(env.AWS_PROFILE).toBe('cc'); + expect(env.AWS_REGION).toBe('us-east-1'); + }); + + it('preserves Vertex as an Anthropic runtime backend', () => { + const env: NodeJS.ProcessEnv = { + CLAUDE_CODE_USE_VERTEX: 'true', + GOOGLE_CLOUD_PROJECT: 'project-1', + }; + + applyProviderRuntimeEnv(env, 'anthropic'); + + expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('vertex'); + expect(env.CLAUDE_CODE_USE_VERTEX).toBe('1'); + expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined(); + expect(env.GOOGLE_CLOUD_PROJECT).toBe('project-1'); + }); + + it('still strips Anthropic backend routing when Codex is selected', () => { + const env: NodeJS.ProcessEnv = { + CLAUDE_CODE_USE_BEDROCK: '1', + AWS_PROFILE: 'cc', + }; + + applyProviderRuntimeEnv(env, 'codex'); + + expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('codex'); + expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined(); + expect(env.AWS_PROFILE).toBe('cc'); + }); +}); diff --git a/src/main/services/runtime/providerRuntimeEnv.ts b/src/main/services/runtime/providerRuntimeEnv.ts index f16d6559..d21078b3 100644 --- a/src/main/services/runtime/providerRuntimeEnv.ts +++ b/src/main/services/runtime/providerRuntimeEnv.ts @@ -4,6 +4,8 @@ import type { CliProviderId, TeamProviderId } from '@shared/types'; type RuntimeEnvProviderId = CliProviderId | TeamProviderId; +type AnthropicRuntimeBackendProviderId = 'anthropic' | 'bedrock' | 'vertex' | 'foundry'; + const PROVIDER_ROUTING_ENV_KEYS = [ 'CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST', 'CLAUDE_CODE_ENTRY_PROVIDER', @@ -32,11 +34,46 @@ export function applyConfiguredRuntimeBackendsEnv( return env; } +function isTruthyEnvValue(value: string | undefined): boolean { + const normalized = value?.trim().toLowerCase(); + return Boolean(normalized && normalized !== '0' && normalized !== 'false' && normalized !== 'no'); +} + +function resolveAnthropicRuntimeBackendFromEnv( + env: NodeJS.ProcessEnv +): AnthropicRuntimeBackendProviderId { + if (isTruthyEnvValue(env.CLAUDE_CODE_USE_BEDROCK)) { + return 'bedrock'; + } + if (isTruthyEnvValue(env.CLAUDE_CODE_USE_VERTEX)) { + return 'vertex'; + } + if (isTruthyEnvValue(env.CLAUDE_CODE_USE_FOUNDRY)) { + return 'foundry'; + } + return 'anthropic'; +} + +function applyAnthropicRuntimeBackendEnv( + env: NodeJS.ProcessEnv, + backend: AnthropicRuntimeBackendProviderId +): void { + if (backend === 'bedrock') { + env.CLAUDE_CODE_USE_BEDROCK = '1'; + } else if (backend === 'vertex') { + env.CLAUDE_CODE_USE_VERTEX = '1'; + } else if (backend === 'foundry') { + env.CLAUDE_CODE_USE_FOUNDRY = '1'; + } +} + export function applyProviderRuntimeEnv( env: NodeJS.ProcessEnv, providerId: RuntimeEnvProviderId | undefined ): NodeJS.ProcessEnv { const resolvedProvider = resolveRuntimeProviderId(providerId); + const anthropicBackend = + resolvedProvider === 'anthropic' ? resolveAnthropicRuntimeBackendFromEnv(env) : 'anthropic'; for (const key of PROVIDER_ROUTING_ENV_KEYS) { env[key] = undefined; @@ -48,7 +85,9 @@ export function applyProviderRuntimeEnv( // host-managed and set the exact entry provider so anthropic teammates do not // silently fall back into the host's current routing world. env.CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST = '1'; - env.CLAUDE_CODE_ENTRY_PROVIDER = resolvedProvider; + env.CLAUDE_CODE_ENTRY_PROVIDER = + resolvedProvider === 'anthropic' ? anthropicBackend : resolvedProvider; + applyAnthropicRuntimeBackendEnv(env, anthropicBackend); return env; }