feat: add Claude and OpenRouter AI providers

OpenRouter is used when no provider flag is set. Claude is selected with .cl, and GLM stays available via .glm.
This commit is contained in:
Azimkin
2026-10-13 08:56:16 +00:00
parent c6b93c9aa8
commit a84467c385
10 changed files with 712 additions and 20 deletions

View File

@@ -15,7 +15,7 @@ from micro_agents_tools import BraveSearchTools, FilesystemTools, PythonTools
from app.agent_tools import AgentToolManager, TelegramTools
from app.config import AiConfig, AiProviderConfig
from app.llm import ChatCompletionsLLM
from app.llm import AnthropicMessagesLLM, ChatCompletionsLLM, OpenRouterChatLLM
from app.web_tools import WebPageTools
@@ -32,6 +32,8 @@ class AgentInvocation:
prompt: str
context_messages: int = 0
use_deepseek: bool = False
use_claude: bool = False
use_openrouter: bool = False
thinking: bool = False
@@ -176,12 +178,18 @@ def parse_agent_invocation(value: str, config: AiConfig) -> AgentInvocation:
raise AgentSyntaxError("Context message count is outside the configured range")
index = 1
use_deepseek = False
provider = "openrouter"
thinking = False
while index < len(tokens) and tokens[index].startswith("."):
flag = tokens[index].lower()
if flag == ".ds":
use_deepseek = True
if flag == ".glm":
provider = "glm"
elif flag == ".ds":
provider = "deepseek"
elif flag in {".cl", ".claude"}:
provider = "claude"
elif flag in {".or", ".openrouter"}:
provider = "openrouter"
elif flag == ".th":
thinking = True
index += 1
@@ -193,7 +201,9 @@ def parse_agent_invocation(value: str, config: AiConfig) -> AgentInvocation:
return AgentInvocation(
prompt=prompt,
context_messages=context_messages,
use_deepseek=use_deepseek,
use_deepseek=provider == "deepseek",
use_claude=provider == "claude",
use_openrouter=provider == "openrouter",
thinking=thinking,
)
@@ -255,7 +265,7 @@ def _agent_context(command_message: Any, account: Any, invocation: AgentInvocati
"name": getattr(account_config, "name", None),
"session": getattr(account_config, "session", None),
},
"provider": "deepseek" if invocation.use_deepseek else "glm",
"provider": _provider_name(invocation),
"thinking": invocation.thinking,
"context_messages": invocation.context_messages,
}
@@ -401,12 +411,35 @@ async def _build_context_messages(
return messages
def _provider_name(invocation: AgentInvocation) -> str:
if invocation.use_openrouter:
return "openrouter"
if invocation.use_claude:
return "claude"
if invocation.use_deepseek:
return "deepseek"
return "glm"
def _provider(config: AiConfig, invocation: AgentInvocation) -> AiProviderConfig:
return config.deepseek if invocation.use_deepseek else config.glm
if invocation.use_openrouter:
return config.openrouter
if invocation.use_claude:
return config.claude
if invocation.use_deepseek:
return config.deepseek
return config.glm
def _create_llm(provider: AiProviderConfig, invocation: AgentInvocation) -> Any:
llm_class = OpenAIBasedLLM if invocation.use_deepseek else ChatCompletionsLLM
if invocation.use_openrouter:
llm_class: type[Any] = OpenRouterChatLLM
elif invocation.use_claude:
llm_class = AnthropicMessagesLLM
elif invocation.use_deepseek:
llm_class = OpenAIBasedLLM
else:
llm_class = ChatCompletionsLLM
return llm_class(
api_url=provider.api_url,
api_key=provider.api_key,