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:
@@ -13,6 +13,7 @@ from app.agentic import (
|
||||
_build_context_messages,
|
||||
_create_llm,
|
||||
_download_message_media,
|
||||
_provider,
|
||||
render_prompt_template,
|
||||
parse_agent_invocation,
|
||||
run_agent_turn,
|
||||
@@ -28,9 +29,13 @@ class AgentInvocationTests(unittest.TestCase):
|
||||
with (
|
||||
patch("app.agentic.ChatCompletionsLLM") as chat_llm,
|
||||
patch("app.agentic.OpenAIBasedLLM") as responses_llm,
|
||||
patch("app.agentic.AnthropicMessagesLLM") as claude_llm,
|
||||
patch("app.agentic.OpenRouterChatLLM") as openrouter_llm,
|
||||
):
|
||||
_create_llm(provider, parse_agent_invocation("prompt", AiConfig()))
|
||||
_create_llm(provider, parse_agent_invocation(".glm prompt", AiConfig()))
|
||||
_create_llm(provider, parse_agent_invocation(".ds prompt", AiConfig()))
|
||||
_create_llm(provider, parse_agent_invocation(".cl prompt", AiConfig()))
|
||||
_create_llm(provider, parse_agent_invocation("prompt", AiConfig()))
|
||||
|
||||
chat_llm.assert_called_once_with(
|
||||
api_url="https://example.test",
|
||||
@@ -42,6 +47,16 @@ class AgentInvocationTests(unittest.TestCase):
|
||||
api_key="key",
|
||||
model="model",
|
||||
)
|
||||
claude_llm.assert_called_once_with(
|
||||
api_url="https://example.test",
|
||||
api_key="key",
|
||||
model="model",
|
||||
)
|
||||
openrouter_llm.assert_called_once_with(
|
||||
api_url="https://example.test",
|
||||
api_key="key",
|
||||
model="model",
|
||||
)
|
||||
|
||||
def test_prompt_comments_are_removed_without_breaking_urls(self) -> None:
|
||||
value = strip_prompt_comments(
|
||||
@@ -72,9 +87,50 @@ class AgentInvocationTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(invocation.context_messages, 12)
|
||||
self.assertTrue(invocation.use_deepseek)
|
||||
self.assertFalse(invocation.use_claude)
|
||||
self.assertFalse(invocation.use_openrouter)
|
||||
self.assertTrue(invocation.thinking)
|
||||
self.assertEqual(invocation.prompt, "explain this")
|
||||
|
||||
claude = parse_agent_invocation("3 .ds .cl .th summarize", AiConfig())
|
||||
self.assertFalse(claude.use_deepseek)
|
||||
self.assertTrue(claude.use_claude)
|
||||
self.assertFalse(claude.use_openrouter)
|
||||
self.assertTrue(claude.thinking)
|
||||
self.assertEqual(claude.prompt, "summarize")
|
||||
self.assertEqual(claude.context_messages, 3)
|
||||
selected = _provider(
|
||||
AiConfig(claude=AiProviderConfig("https://api.anthropic.com", "key", "claude-haiku-5-5")),
|
||||
claude,
|
||||
)
|
||||
self.assertEqual(selected.model, "claude-haiku-5-5")
|
||||
|
||||
plain = parse_agent_invocation("just ask", AiConfig())
|
||||
self.assertTrue(plain.use_openrouter)
|
||||
self.assertFalse(plain.use_deepseek)
|
||||
self.assertFalse(plain.use_claude)
|
||||
self.assertEqual(
|
||||
_provider(AiConfig(), plain).api_url,
|
||||
"https://openrouter.ai/api/v1",
|
||||
)
|
||||
|
||||
routed = parse_agent_invocation(".cl .or .th route this", AiConfig())
|
||||
self.assertFalse(routed.use_claude)
|
||||
self.assertTrue(routed.use_openrouter)
|
||||
self.assertEqual(routed.prompt, "route this")
|
||||
selected_router = _provider(
|
||||
AiConfig(
|
||||
openrouter=AiProviderConfig(
|
||||
"https://openrouter.ai/api/v1",
|
||||
"key",
|
||||
"anthropic/claude-haiku-5.5",
|
||||
)
|
||||
),
|
||||
routed,
|
||||
)
|
||||
self.assertEqual(selected_router.api_url, "https://openrouter.ai/api/v1")
|
||||
self.assertEqual(selected_router.model, "anthropic/claude-haiku-5.5")
|
||||
|
||||
def test_ignores_unknown_leading_dot_arguments(self) -> None:
|
||||
invocation = parse_agent_invocation(".unknown .ds prompt", AiConfig())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user