Этап 7: долговременная память
- Факты о пользователе в SQLite, в системном промпте с номерами - Инструменты remember / update_memory / forget, автоматическое запоминание отключается - Цикл вызова инструментов со стримингом (до 5 кругов), проверка и приведение аргументов - Откат без инструментов для моделей, которые их не поддерживают, с одним предупреждением - Действия в журнале, вкладка «Память» в настройках - Фейковый OpenAI-совместимый сервер для тестов, тесты полного цикла через Assistant Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
542389c0f9
commit
84d8aaa848
@@ -0,0 +1,67 @@
|
||||
import pytest
|
||||
|
||||
from agr_assistent.config import ProviderConfig
|
||||
from agr_assistent.llm.client import (
|
||||
LLMClient,
|
||||
LLMError,
|
||||
TextDelta,
|
||||
ToolCall,
|
||||
ToolCalls,
|
||||
ToolsNotSupportedError,
|
||||
)
|
||||
from tests.fake_llm import FakeLLMServer, Reply
|
||||
|
||||
_TOOLS = [{"type": "function", "function": {"name": "remember", "parameters": {"type": "object"}}}]
|
||||
|
||||
|
||||
def _client(server: FakeLLMServer) -> LLMClient:
|
||||
return LLMClient(
|
||||
ProviderConfig("fake", server.base_url, "key", "fake-model"),
|
||||
temperature=0.5,
|
||||
timeout_seconds=10,
|
||||
)
|
||||
|
||||
|
||||
def test_text_and_tool_calls_are_assembled(fake_llm: FakeLLMServer) -> None:
|
||||
fake_llm.replies.append(
|
||||
Reply(text="Сейчас запомню.", tool_calls=[("remember", '{"text": "Любит кофе"}')])
|
||||
)
|
||||
|
||||
events = list(_client(fake_llm).stream_chat([{"role": "user", "content": "привет"}], _TOOLS))
|
||||
|
||||
text = "".join(event.text for event in events if isinstance(event, TextDelta))
|
||||
assert text == "Сейчас запомню."
|
||||
assert events[-1] == ToolCalls([ToolCall("call_0", "remember", '{"text": "Любит кофе"}')])
|
||||
assert fake_llm.requests[0]["tools"] == _TOOLS
|
||||
|
||||
|
||||
def test_tools_are_not_sent_when_absent(fake_llm: FakeLLMServer) -> None:
|
||||
fake_llm.replies.append(Reply(text="ок"))
|
||||
|
||||
list(_client(fake_llm).stream_chat([{"role": "user", "content": "привет"}]))
|
||||
|
||||
assert "tools" not in fake_llm.requests[0]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"message",
|
||||
[
|
||||
"registry.ollama.ai/library/gemma:2b does not support tools",
|
||||
"No endpoints found that support tool use",
|
||||
],
|
||||
)
|
||||
def test_tools_not_supported_is_recognized(fake_llm: FakeLLMServer, message: str) -> None:
|
||||
fake_llm.replies.append(Reply(status=400, error=message))
|
||||
|
||||
with pytest.raises(ToolsNotSupportedError):
|
||||
list(_client(fake_llm).stream_chat([{"role": "user", "content": "привет"}], _TOOLS))
|
||||
|
||||
|
||||
def test_other_api_errors_stay_generic(fake_llm: FakeLLMServer) -> None:
|
||||
fake_llm.replies.append(Reply(status=400, error="context too long"))
|
||||
|
||||
with pytest.raises(LLMError) as error:
|
||||
list(_client(fake_llm).stream_chat([{"role": "user", "content": "привет"}], _TOOLS))
|
||||
|
||||
assert not isinstance(error.value, ToolsNotSupportedError)
|
||||
assert "context too long" in str(error.value)
|
||||
Reference in New Issue
Block a user