Этап 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,64 @@
|
||||
from typing import Any
|
||||
|
||||
from agr_assistent.llm.tools import Tool, ToolError, ToolRegistry, ToolResult, validate_arguments
|
||||
|
||||
_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"level": {"type": "integer"},
|
||||
"ratio": {"type": "number"},
|
||||
"loud": {"type": "boolean"},
|
||||
"mode": {"type": "string", "enum": ["on", "off"]},
|
||||
},
|
||||
"required": ["level"],
|
||||
}
|
||||
|
||||
|
||||
def test_arguments_are_converted_from_strings() -> None:
|
||||
arguments, errors = validate_arguments(
|
||||
_SCHEMA, {"level": "30", "ratio": "0,5", "loud": "true", "mode": "on", "extra": 1}
|
||||
)
|
||||
|
||||
assert errors == []
|
||||
assert arguments == {"level": 30, "ratio": 0.5, "loud": True, "mode": "on"}
|
||||
|
||||
|
||||
def test_invalid_arguments_are_reported() -> None:
|
||||
_arguments, errors = validate_arguments(_SCHEMA, {"ratio": "много", "loud": 1, "mode": "auto"})
|
||||
|
||||
assert "не указан параметр level" in errors
|
||||
assert any(error.startswith("ratio:") for error in errors)
|
||||
assert any(error.startswith("loud:") for error in errors)
|
||||
assert any("недопустимое значение 'auto'" in error for error in errors)
|
||||
|
||||
|
||||
def _registry() -> ToolRegistry:
|
||||
def handler(arguments: dict[str, Any]) -> ToolResult:
|
||||
if arguments["level"] > 100:
|
||||
raise ToolError("слишком громко")
|
||||
if arguments["level"] < 0:
|
||||
raise RuntimeError("сломалось")
|
||||
return ToolResult(True, f"ok {arguments['level']}", "готово")
|
||||
|
||||
return ToolRegistry([Tool("volume", "Громкость", _SCHEMA, handler)])
|
||||
|
||||
|
||||
def test_registry_executes_tool_and_exposes_schema() -> None:
|
||||
registry = _registry()
|
||||
|
||||
assert registry.schemas()[0]["function"]["name"] == "volume"
|
||||
assert registry.execute("volume", '{"level": 30}') == ToolResult(True, "ok 30", "готово")
|
||||
|
||||
|
||||
def test_registry_turns_problems_into_failed_results() -> None:
|
||||
registry = _registry()
|
||||
|
||||
assert not registry.execute("missing", "{}").ok
|
||||
assert not registry.execute("volume", "{not json").ok
|
||||
assert not registry.execute("volume", "[1]").ok
|
||||
assert not registry.execute("volume", "{}").ok
|
||||
assert registry.execute("volume", '{"level": 101}') == ToolResult(
|
||||
False, "слишком громко", "слишком громко"
|
||||
)
|
||||
failed = registry.execute("volume", '{"level": -1}')
|
||||
assert not failed.ok and "сломалось" in failed.content
|
||||
Reference in New Issue
Block a user