feat: add QR login and browser-backed web tools

This commit is contained in:
Azimkin
2026-09-14 14:19:20 +02:00
parent 3a8c198caa
commit b68e715267
19 changed files with 2740 additions and 8 deletions

101
tests/test_llm.py Normal file
View File

@@ -0,0 +1,101 @@
from __future__ import annotations
import unittest
from types import SimpleNamespace
from unittest.mock import AsyncMock
from micro_agents import Conversation, LlmMessage, Tool, ToolCallMessage, ToolCallResponseMessage, UserMessage
from micro_agents.conversation import ReasoningMessage
from app.llm import ChatCompletionsLLM
class ChatCompletionsLlmTests(unittest.IsolatedAsyncioTestCase):
async def test_uses_chat_completions_with_system_prompt_and_thinking(self) -> None:
response_message = SimpleNamespace(
content="done",
reasoning_content="reasoning",
tool_calls=None,
)
create = AsyncMock(
return_value=SimpleNamespace(
choices=[SimpleNamespace(message=response_message)],
)
)
llm = ChatCompletionsLLM("https://glm.example/v4", "key", "glm-model")
llm._ai = SimpleNamespace( # type: ignore[assignment]
chat=SimpleNamespace(completions=SimpleNamespace(create=create))
)
result = await llm.ask(
Conversation([UserMessage("hello")]),
[],
instructions="system prompt",
thinking=True,
)
request = create.await_args.kwargs
self.assertEqual(request["model"], "glm-model")
self.assertEqual(
request["messages"],
[
{"role": "system", "content": "system prompt"},
{"role": "user", "content": "hello"},
],
)
self.assertEqual(request["extra_body"], {"thinking": {"type": "enabled"}})
self.assertIsInstance(result[0], ReasoningMessage)
self.assertIsInstance(result[1], LlmMessage)
async def test_serializes_and_parses_tool_calls(self) -> None:
model_call = SimpleNamespace(
id="call-2",
function=SimpleNamespace(name="lookup", arguments='{"query":"news"}'),
)
create = AsyncMock(
return_value=SimpleNamespace(
choices=[
SimpleNamespace(
message=SimpleNamespace(
content="",
reasoning_content=None,
tool_calls=[model_call],
)
)
],
)
)
llm = ChatCompletionsLLM("https://glm.example/v4", "key", "glm-model")
llm._ai = SimpleNamespace( # type: ignore[assignment]
chat=SimpleNamespace(completions=SimpleNamespace(create=create))
)
def lookup(query: str) -> str:
"""Look up a query."""
return query
conversation = Conversation(
[
UserMessage("find it"),
ReasoningMessage("need a tool"),
LlmMessage("checking"),
ToolCallMessage("call-1", "lookup", {"query": "weather"}),
ToolCallResponseMessage("call-1", "sunny"),
]
)
result = await llm.ask(conversation, [Tool(lookup)], thinking=False)
request = create.await_args.kwargs
self.assertEqual(request["extra_body"], {"thinking": {"type": "disabled"}})
self.assertEqual(request["tools"][0]["type"], "function")
self.assertEqual(request["tools"][0]["function"]["name"], "lookup")
self.assertEqual(request["messages"][1]["role"], "assistant")
self.assertEqual(request["messages"][1]["reasoning_content"], "need a tool")
self.assertEqual(request["messages"][2]["role"], "tool")
self.assertIsInstance(result[0], ToolCallMessage)
self.assertEqual(result[0].tool_name(), "lookup")
self.assertEqual(result[0].arguments(), {"query": "news"})
if __name__ == "__main__":
unittest.main()