From dbeadb6833be35860c09e1f5556199724c6b1b09 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Sat, 21 Feb 2026 23:40:04 +0800 Subject: [PATCH] refactor: remove Anthropic OAuth provider implementation and related metadata overrides --- astrbot/core/config/default.py | 12 -- astrbot/core/provider/manager.py | 4 - .../sources/anthropic_oauth_source.py | 140 ------------------ astrbot/dashboard/routes/config.py | 21 --- .../src/composables/useProviderSources.ts | 4 +- .../i18n/locales/en-US/features/provider.json | 1 - .../i18n/locales/zh-CN/features/provider.json | 1 - 7 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 astrbot/core/provider/sources/anthropic_oauth_source.py diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 94c8282f6..0f352808d 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -981,18 +981,6 @@ CONFIG_METADATA_2 = { "proxy": "", "anth_thinking_config": {"type": "", "budget": 0, "effort": ""}, }, - "Anthropic (Claude Code OAuth)": { - "id": "anthropic_claude_code_oauth", - "provider": "anthropic", - "type": "anthropic_oauth", - "provider_type": "chat_completion", - "enable": True, - "api_base": "https://api.anthropic.com", - "timeout": 120, - "proxy": "", - "anth_thinking_config": {"type": "", "budget": 0, "effort": ""}, - "key": [], - }, "Moonshot": { "id": "moonshot", "provider": "moonshot", diff --git a/astrbot/core/provider/manager.py b/astrbot/core/provider/manager.py index 42502975b..a331c97e9 100644 --- a/astrbot/core/provider/manager.py +++ b/astrbot/core/provider/manager.py @@ -309,10 +309,6 @@ class ProviderManager: from .sources.anthropic_source import ( ProviderAnthropic as ProviderAnthropic, ) - case "anthropic_oauth": - from .sources.anthropic_oauth_source import ( - ProviderAnthropicOAuth as ProviderAnthropicOAuth, - ) case "googlegenai_chat_completion": from .sources.gemini_source import ( ProviderGoogleGenAI as ProviderGoogleGenAI, diff --git a/astrbot/core/provider/sources/anthropic_oauth_source.py b/astrbot/core/provider/sources/anthropic_oauth_source.py deleted file mode 100644 index 57ded1a2c..000000000 --- a/astrbot/core/provider/sources/anthropic_oauth_source.py +++ /dev/null @@ -1,140 +0,0 @@ -from collections.abc import AsyncGenerator - -from anthropic import AsyncAnthropic - -from astrbot.core.provider.entities import LLMResponse - -from ..register import register_provider_adapter -from .anthropic_source import ProviderAnthropic - -_OAUTH_DEFAULT_HEADERS = { - "anthropic-beta": "claude-code-20250219,oauth-2025-04-20,context-1m-2025-08-07", - "user-agent": "claude-cli/1.0.0 (external, cli)", - "x-app": "cli", - "anthropic-dangerous-direct-browser-access": "true", -} - -_CLAUDE_CODE_SYSTEM_PREFIX = ( - "You are Claude Code, Anthropic's official CLI for Claude.\n\n" -) - -# 支持 1M 上下文窗口的模型前缀(需配合 context-1m beta header)。 -# 新增 4.6+ 模型时需同步更新此列表。 -_1M_CONTEXT_MODEL_PREFIXES = ( - "claude-opus-4-6", - "claude-sonnet-4-6", -) - - -@register_provider_adapter( - "anthropic_oauth", - "Anthropic Claude Code OAuth provider adapter", -) -class ProviderAnthropicOAuth(ProviderAnthropic): - def __init__( - self, - provider_config: dict, - provider_settings: dict, - ) -> None: - # 禁用父类的 API key 客户端初始化,避免重复构造客户端 - super().__init__(provider_config, provider_settings, use_api_key=False) - - # 手动解析 key 列表(父类跳过了 _init_api_key) - self.api_keys: list = self.get_keys() - self.chosen_api_key: str = self.api_keys[0] if self.api_keys else "" - - # 使用 auth_token(OAuth Bearer 认证)构建客户端 - self.client = AsyncAnthropic( - auth_token=self.chosen_api_key, - timeout=self.timeout, - base_url=self.base_url, - default_headers=_OAUTH_DEFAULT_HEADERS, - http_client=self._create_http_client(provider_config), - ) - - def set_model(self, model_name: str) -> None: - super().set_model(model_name) - if any(model_name.startswith(p) for p in _1M_CONTEXT_MODEL_PREFIXES): - if self.provider_config.get("max_context_tokens", 0) <= 0: - self.provider_config["max_context_tokens"] = 1_000_000 - - def get_model_metadata_overrides(self, model_ids: list[str]) -> dict[str, dict]: - overrides = {} - for mid in model_ids: - if any(mid.startswith(p) for p in _1M_CONTEXT_MODEL_PREFIXES): - overrides[mid] = {"limit": {"context": 1_000_000}} - return overrides - - def set_key(self, key: str) -> None: - self.chosen_api_key = key - # 切换 key 时需要重建客户端以使用新的 auth_token - self.client = AsyncAnthropic( - auth_token=key, - timeout=self.timeout, - base_url=self.base_url, - default_headers=_OAUTH_DEFAULT_HEADERS, - http_client=self._create_http_client(self.provider_config), - ) - - async def get_models(self) -> list[str]: - return await super().get_models() - - async def test(self, timeout: float = 45.0) -> None: - await super().test(timeout) - - async def text_chat( - self, - prompt=None, - session_id=None, - image_urls=None, - func_tool=None, - contexts=None, - system_prompt=None, - tool_calls_result=None, - model=None, - extra_user_content_parts=None, - **kwargs, - ) -> LLMResponse: - system_prompt = _CLAUDE_CODE_SYSTEM_PREFIX + (system_prompt or "") - - return await super().text_chat( - prompt=prompt, - session_id=session_id, - image_urls=image_urls, - func_tool=func_tool, - contexts=contexts, - system_prompt=system_prompt, - tool_calls_result=tool_calls_result, - model=model, - extra_user_content_parts=extra_user_content_parts, - **kwargs, - ) - - async def text_chat_stream( - self, - prompt=None, - session_id=None, - image_urls=None, - func_tool=None, - contexts=None, - system_prompt=None, - tool_calls_result=None, - model=None, - extra_user_content_parts=None, - **kwargs, - ) -> AsyncGenerator[LLMResponse, None]: - system_prompt = _CLAUDE_CODE_SYSTEM_PREFIX + (system_prompt or "") - - async for llm_response in super().text_chat_stream( - prompt=prompt, - session_id=session_id, - image_urls=image_urls, - func_tool=func_tool, - contexts=contexts, - system_prompt=system_prompt, - tool_calls_result=tool_calls_result, - model=model, - extra_user_content_parts=extra_user_content_parts, - **kwargs, - ): - yield llm_response diff --git a/astrbot/dashboard/routes/config.py b/astrbot/dashboard/routes/config.py index 4a72853ec..6d60fb6de 100644 --- a/astrbot/dashboard/routes/config.py +++ b/astrbot/dashboard/routes/config.py @@ -40,23 +40,6 @@ from .util import ( MAX_FILE_BYTES = 500 * 1024 * 1024 -def _apply_provider_metadata_overrides( - provider: Any, model_ids: list[str], metadata_map: dict -) -> None: - override_fn = getattr(provider, "get_model_metadata_overrides", None) - if not callable(override_fn): - return - overrides_map = override_fn(model_ids) or {} - for mid, overrides in overrides_map.items(): - merged = dict(metadata_map.get(mid, {})) - for key, value in overrides.items(): - if isinstance(value, dict): - merged[key] = {**merged.get(key, {}), **value} - else: - merged[key] = value - metadata_map[mid] = merged - - def try_cast(value: Any, type_: str): if type_ == "int": try: @@ -744,8 +727,6 @@ class ConfigRoute(Route): if meta: metadata_map[model_id] = meta - _apply_provider_metadata_overrides(provider, models, metadata_map) - ret = { "models": models, "provider_id": provider_id, @@ -891,8 +872,6 @@ class ConfigRoute(Route): if meta: metadata_map[model_id] = meta - _apply_provider_metadata_overrides(inst, models, metadata_map) - # 销毁实例(如果有 terminate 方法) terminate_fn = getattr(inst, "terminate", None) if inspect.iscoroutinefunction(terminate_fn): diff --git a/dashboard/src/composables/useProviderSources.ts b/dashboard/src/composables/useProviderSources.ts index 5329c150b..97eb044da 100644 --- a/dashboard/src/composables/useProviderSources.ts +++ b/dashboard/src/composables/useProviderSources.ts @@ -241,9 +241,7 @@ export function useProviderSources(options: UseProviderSourcesOptions) { // 为 provider source 的 id 字段添加自定义 hint if (customSchema.provider?.items?.id) { customSchema.provider.items.id.hint = tm('providerSources.hints.id') - customSchema.provider.items.key.hint = editableProviderSource.value?.type === 'anthropic_oauth' - ? tm('providerSources.hints.oauthToken') - : tm('providerSources.hints.key') + customSchema.provider.items.key.hint = tm('providerSources.hints.key') customSchema.provider.items.api_base.hint = tm('providerSources.hints.apiBase') } // 为 proxy 字段添加描述和提示 diff --git a/dashboard/src/i18n/locales/en-US/features/provider.json b/dashboard/src/i18n/locales/en-US/features/provider.json index 5d6e935c7..f36053f72 100644 --- a/dashboard/src/i18n/locales/en-US/features/provider.json +++ b/dashboard/src/i18n/locales/en-US/features/provider.json @@ -114,7 +114,6 @@ "hints": { "id": "Provider source ID (not provider ID)", "key": "API key for authentication", - "oauthToken": "Run `claude setup-token` in your terminal to get a long-lived OAuth token, then paste it here. Token is valid for 1 year.", "apiBase": "Custom API endpoint URL", "proxy": "HTTP/HTTPS proxy address, e.g. http://127.0.0.1:7890. Only affects this provider's API requests, doesn't interfere with Docker internal networking." }, diff --git a/dashboard/src/i18n/locales/zh-CN/features/provider.json b/dashboard/src/i18n/locales/zh-CN/features/provider.json index 3e5c0109d..cf3cdba0c 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/provider.json +++ b/dashboard/src/i18n/locales/zh-CN/features/provider.json @@ -115,7 +115,6 @@ "hints": { "id": "提供商源唯一 ID(不是提供商 ID)", "key": "API 密钥", - "oauthToken": "在终端运行 `claude setup-token` 获取长期有效的 OAuth Token,然后粘贴到此处。Token 有效期为 1 年。", "apiBase": "自定义 API 端点 URL", "proxy": "HTTP/HTTPS 代理地址,格式如 http://127.0.0.1:7890。仅对该提供商的 API 请求生效,不影响 Docker 内网通信。" },