diff --git a/runtime/chat/history_tool_result_compact.py b/runtime/chat/history_tool_result_compact.py index 995eb27e..02179314 100644 --- a/runtime/chat/history_tool_result_compact.py +++ b/runtime/chat/history_tool_result_compact.py @@ -25,6 +25,13 @@ class HistoryCompactionResult: detail: str = "" +def _chat_message_id_content(row: Any) -> tuple[int, str]: + """Normalize SQLite Row/tuple vs PostgreSQL dict_row for ``select id, content``.""" + if isinstance(row, dict): + return int(row["id"]), str(row.get("content") or "") + return int(row[0]), str(row[1] or "") # type: ignore[index] + + def _json_dumps_safe(obj: Any) -> str: try: return json.dumps(obj, ensure_ascii=False, default=str) @@ -150,7 +157,8 @@ def compact_tool_results_in_session_history( (sid, max(1, min(int(limit_messages or 5000), 200_000))), ) rows = cur.fetchall() or [] - for mid, raw in rows: + for row in rows: + mid, raw = _chat_message_id_content(row) scanned += 1 txt = str(raw or "") max_seen = max(max_seen, len(txt)) diff --git a/runtime/tools/public/memory_wiki_tools.py b/runtime/tools/public/memory_wiki_tools.py index 84767b08..1a90a2c9 100644 --- a/runtime/tools/public/memory_wiki_tools.py +++ b/runtime/tools/public/memory_wiki_tools.py @@ -99,10 +99,27 @@ def _search_tool(public_name: str, desc: str) -> ToolSpec: parameters={ "type": "object", "properties": { - "query": {"type": "string"}, - "limit": {"type": "integer"}, + "query": {"type": "string", "description": "Search query string."}, + "limit": {"type": "integer", "description": "Max hits per page (server caps to wiki max)."}, + "offset": {"type": "integer", "description": "Hit offset for pagination (0-based)."}, + "context_lines": { + "type": "integer", + "description": "Lines of context around each match (server caps at 5).", + }, "is_regex": {"type": "boolean"}, "case_sensitive": {"type": "boolean"}, + "path_prefix": { + "type": "string", + "description": "Only search under this relative path prefix (e.g. users/).", + }, + "expand_query": { + "type": "boolean", + "description": "If true, try synonym-expanded variants (ignored when is_regex is true).", + }, + "max_rounds": { + "type": "integer", + "description": "Max expansion rounds when expand_query is true (1–5).", + }, }, "required": ["query"], "additionalProperties": False, diff --git a/tests/test_history_tool_result_compact.py b/tests/test_history_tool_result_compact.py index 864be346..dc1eb59a 100644 --- a/tests/test_history_tool_result_compact.py +++ b/tests/test_history_tool_result_compact.py @@ -3,7 +3,18 @@ from __future__ import annotations import json from svc.persistence.sqlite_store import SqliteStore -from runtime.chat.history_tool_result_compact import compact_tool_results_in_session_history +from runtime.chat.history_tool_result_compact import ( + _chat_message_id_content, + compact_tool_results_in_session_history, +) + + +def test_chat_message_id_content_dict_row() -> None: + assert _chat_message_id_content({"id": 42, "content": "hello"}) == (42, "hello") + + +def test_chat_message_id_content_tuple_like() -> None: + assert _chat_message_id_content((9, "z")) == (9, "z") def test_compact_tool_results_in_session_history_rewrites_large_tool_message(tmp_path) -> None: # noqa: ANN001 diff --git a/tests/test_memory_wiki_tools_loader.py b/tests/test_memory_wiki_tools_loader.py index d0d11ed3..bb9a4bcd 100644 --- a/tests/test_memory_wiki_tools_loader.py +++ b/tests/test_memory_wiki_tools_loader.py @@ -12,6 +12,22 @@ from runtime.tools.public.memory_wiki_tools import ( ) +def test_memory_wiki_search_tool_schema_exposes_wiki_search_args() -> None: + props = memory_wiki_search_tool().parameters.get("properties") or {} + for key in ( + "query", + "limit", + "offset", + "context_lines", + "is_regex", + "case_sensitive", + "path_prefix", + "expand_query", + "max_rounds", + ): + assert key in props, f"missing schema property: {key}" + + def test_memory_wiki_tools_handlers_load_without_dataclass_module_error() -> None: status = memory_wiki_status_tool().handler({}) assert isinstance(status, dict)