Merge pull request #3987 from mastertyko/fix/3911-preserve-anthropic-api-provider
fix(cli): preserve anthropic api provider
This commit is contained in:
commit
9dde1b9410
3 changed files with 122 additions and 2 deletions
13
src/cli.ts
13
src/cli.ts
|
|
@ -18,6 +18,7 @@ import { ensureManagedTools } from './tool-bootstrap.js'
|
|||
import { loadStoredEnvKeys } from './wizard.js'
|
||||
import { migratePiCredentials } from './pi-migration.js'
|
||||
import { validateConfiguredModel } from './startup-model-validation.js'
|
||||
import { shouldMigrateAnthropicToClaudeCode } from './provider-migrations.js'
|
||||
import { shouldRunOnboarding, runOnboarding } from './onboarding.js'
|
||||
import chalk from 'chalk'
|
||||
import { checkForUpdates } from './update-check.js'
|
||||
|
|
@ -470,7 +471,11 @@ if (isPrintMode) {
|
|||
// Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
|
||||
// Anthropic blocks third-party apps from using subscription quotas — routing through
|
||||
// the local claude CLI binary is TOS-compliant.
|
||||
if (modelRegistry.isProviderRequestReady('claude-code') && settingsManager.getDefaultProvider() === 'anthropic') {
|
||||
if (shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage,
|
||||
isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
|
||||
defaultProvider: settingsManager.getDefaultProvider(),
|
||||
})) {
|
||||
const currentModelId = settingsManager.getDefaultModel()
|
||||
if (currentModelId) {
|
||||
const ccModel = modelRegistry.find('claude-code', currentModelId)
|
||||
|
|
@ -662,7 +667,11 @@ markStartup('createAgentSession')
|
|||
// Migrate anthropic OAuth users to claude-code provider when CLI is available (#3772).
|
||||
// Anthropic blocks third-party apps from using subscription quotas — routing through
|
||||
// the local claude CLI binary is TOS-compliant.
|
||||
if (modelRegistry.isProviderRequestReady('claude-code') && settingsManager.getDefaultProvider() === 'anthropic') {
|
||||
if (shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage,
|
||||
isClaudeCodeReady: modelRegistry.isProviderRequestReady('claude-code'),
|
||||
defaultProvider: settingsManager.getDefaultProvider(),
|
||||
})) {
|
||||
const currentModelId = settingsManager.getDefaultModel()
|
||||
if (currentModelId) {
|
||||
const ccModel = modelRegistry.find('claude-code', currentModelId)
|
||||
|
|
|
|||
34
src/provider-migrations.ts
Normal file
34
src/provider-migrations.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import type { AuthStorage } from "@gsd/pi-coding-agent"
|
||||
|
||||
type AnthropicMigrationDeps = {
|
||||
authStorage: Pick<AuthStorage, "getCredentialsForProvider">
|
||||
isClaudeCodeReady: boolean
|
||||
defaultProvider: string | undefined
|
||||
env?: NodeJS.ProcessEnv
|
||||
}
|
||||
|
||||
export function hasDirectAnthropicApiKey(
|
||||
authStorage: Pick<AuthStorage, "getCredentialsForProvider">,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
if ((env.ANTHROPIC_API_KEY ?? "").trim()) {
|
||||
return true
|
||||
}
|
||||
|
||||
return authStorage.getCredentialsForProvider("anthropic").some((credential: any) =>
|
||||
credential?.type === "api_key" && typeof credential?.key === "string" && credential.key.trim().length > 0,
|
||||
)
|
||||
}
|
||||
|
||||
export function shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage,
|
||||
isClaudeCodeReady,
|
||||
defaultProvider,
|
||||
env = process.env,
|
||||
}: AnthropicMigrationDeps): boolean {
|
||||
if (!isClaudeCodeReady || defaultProvider !== "anthropic") {
|
||||
return false
|
||||
}
|
||||
|
||||
return !hasDirectAnthropicApiKey(authStorage, env)
|
||||
}
|
||||
77
src/tests/provider-migrations.test.ts
Normal file
77
src/tests/provider-migrations.test.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import test from "node:test"
|
||||
import assert from "node:assert/strict"
|
||||
import { hasDirectAnthropicApiKey, shouldMigrateAnthropicToClaudeCode } from "../provider-migrations.ts"
|
||||
|
||||
function makeAuthStorage(credentials: unknown[]) {
|
||||
return {
|
||||
getCredentialsForProvider(provider: string) {
|
||||
return provider === "anthropic" ? credentials : []
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test("hasDirectAnthropicApiKey detects non-empty auth storage keys", () => {
|
||||
assert.equal(
|
||||
hasDirectAnthropicApiKey(
|
||||
makeAuthStorage([{ type: "api_key", key: "sk-ant-test" }]) as any,
|
||||
{} as NodeJS.ProcessEnv,
|
||||
),
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test("hasDirectAnthropicApiKey ignores empty placeholder keys", () => {
|
||||
assert.equal(
|
||||
hasDirectAnthropicApiKey(
|
||||
makeAuthStorage([{ type: "api_key", key: "" }]) as any,
|
||||
{} as NodeJS.ProcessEnv,
|
||||
),
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
test("hasDirectAnthropicApiKey detects ANTHROPIC_API_KEY env fallback", () => {
|
||||
assert.equal(
|
||||
hasDirectAnthropicApiKey(
|
||||
makeAuthStorage([]) as any,
|
||||
{ ANTHROPIC_API_KEY: "sk-ant-env" } as NodeJS.ProcessEnv,
|
||||
),
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test("shouldMigrateAnthropicToClaudeCode blocks migration for direct-key users", () => {
|
||||
assert.equal(
|
||||
shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage: makeAuthStorage([{ type: "api_key", key: "sk-ant-test" }]) as any,
|
||||
isClaudeCodeReady: true,
|
||||
defaultProvider: "anthropic",
|
||||
env: {} as NodeJS.ProcessEnv,
|
||||
}),
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
test("shouldMigrateAnthropicToClaudeCode allows OAuth-only anthropic users", () => {
|
||||
assert.equal(
|
||||
shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage: makeAuthStorage([{ type: "oauth" }]) as any,
|
||||
isClaudeCodeReady: true,
|
||||
defaultProvider: "anthropic",
|
||||
env: {} as NodeJS.ProcessEnv,
|
||||
}),
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test("shouldMigrateAnthropicToClaudeCode stays off for other providers", () => {
|
||||
assert.equal(
|
||||
shouldMigrateAnthropicToClaudeCode({
|
||||
authStorage: makeAuthStorage([{ type: "oauth" }]) as any,
|
||||
isClaudeCodeReady: true,
|
||||
defaultProvider: "openai",
|
||||
env: {} as NodeJS.ProcessEnv,
|
||||
}),
|
||||
false,
|
||||
)
|
||||
})
|
||||
Loading…
Add table
Reference in a new issue