- Факты о пользователе в SQLite, в системном промпте с номерами - Инструменты remember / update_memory / forget, автоматическое запоминание отключается - Цикл вызова инструментов со стримингом (до 5 кругов), проверка и приведение аргументов - Откат без инструментов для моделей, которые их не поддерживают, с одним предупреждением - Действия в журнале, вкладка «Память» в настройках - Фейковый OpenAI-совместимый сервер для тестов, тесты полного цикла через Assistant Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
65 lines
2.4 KiB
Python
65 lines
2.4 KiB
Python
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
|