refactor: remove Anthropic OAuth provider implementation and related metadata overrides
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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):
|
||||
|
||||
@@ -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 字段添加描述和提示
|
||||
|
||||
@@ -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."
|
||||
},
|
||||
|
||||
@@ -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 内网通信。"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user