added memmory

This commit is contained in:
2026-06-10 08:23:45 +03:00
parent 2c86a634bb
commit 5a9d26fbf4
13 changed files with 629 additions and 11 deletions
+30 -1
View File
@@ -47,9 +47,18 @@ POMODORO_TOOL_NAMES = frozenset({
"get_pomodoro_history",
})
MEMORY_TOOL_NAMES = frozenset({
"remember_fact",
"recall_memories",
"forget_memory",
"update_profile",
"update_session_summary",
})
# Не засорять чат служебными ответами
TOOLS_SKIP_CHAT_NOTICE = frozenset({
"get_pomodoro_status",
"recall_memories",
})
@@ -63,7 +72,12 @@ def format_tool_notice(tool_name: str, raw_result: str) -> str | None:
return None
if isinstance(data, dict) and "error" in data:
prefix = "" if tool_name in POMODORO_TOOL_NAMES else "📋"
if tool_name in POMODORO_TOOL_NAMES:
prefix = ""
elif tool_name in MEMORY_TOOL_NAMES:
prefix = "🧠"
else:
prefix = "📋"
return f"{prefix} {data['error']}"
if tool_name == "reset_pomodoro_cycle":
@@ -109,6 +123,21 @@ def format_tool_notice(tool_name: str, raw_result: str) -> str | None:
lines.append(f"- `{p.get('slug')}`: {p.get('name')} · Gitea: {gitea}")
return "\n".join(lines)
if tool_name == "remember_fact" and data.get("ok"):
action = "обновлено" if data.get("action") == "updated" else "сохранено"
return f"🧠 **Память {action}** · #{data.get('memory_id')}: {data.get('content')}"
if tool_name == "forget_memory" and data.get("ok"):
return f"🧠 **Забыто** · #{data.get('memory_id')}: {data.get('forgotten')}"
if tool_name == "update_profile" and data.get("ok"):
profile = data.get("profile") or {}
parts = [f"{k}={v}" for k, v in profile.items() if v]
return f"🧠 **Профиль обновлён** · {', '.join(parts) or 'пусто'}"
if tool_name == "update_session_summary" and data.get("ok"):
return "🧠 **Сводка чата сохранена**"
return None
+18 -6
View File
@@ -11,6 +11,7 @@ from app.chat.notices import (
format_pomodoro_context,
format_tool_notice,
)
from app.memory.context import format_memory_context, get_memory_snapshot
from app.projects.context import format_projects_context, get_projects_snapshot
from app.db.models import ChatSession, Message
from app.llm.client import LLMClient
@@ -18,6 +19,7 @@ from app.pomodoro.service import PomodoroService
from app.tools.registry import TOOL_DEFINITIONS, execute_tool
MAX_TOOL_ROUNDS = 5
MAX_HISTORY_MESSAGES = 40
class ChatService:
@@ -48,23 +50,31 @@ class ChatService:
self.db.commit()
return True
def _build_system_prompt(self) -> str:
def _build_system_prompt(self, session_id: int | None = None) -> str:
status = PomodoroService(self.db).get_status()
memory_snapshot = get_memory_snapshot(self.db, session_id)
projects_snapshot = get_projects_snapshot(self.db)
return (
f"{self.character.get_system_prompt()}\n\n"
f"{format_memory_context(memory_snapshot)}\n\n"
f"{format_pomodoro_context(status)}\n\n"
f"{format_projects_context(projects_snapshot)}"
)
def _build_messages(self, session: ChatSession) -> list[dict[str, Any]]:
system_prompt = self._build_system_prompt(session.id)
all_chat = [m for m in session.messages if m.role != "notice"]
if len(all_chat) > MAX_HISTORY_MESSAGES:
system_prompt += (
f"\n\n[История чата: в контексте последние {MAX_HISTORY_MESSAGES} "
f"из {len(all_chat)} сообщений. Раннее — в сводке сессии, если сохранена.]"
)
messages: list[dict[str, Any]] = [
{"role": "system", "content": self._build_system_prompt()}
{"role": "system", "content": system_prompt}
]
for msg in session.messages:
if msg.role == "notice":
continue
chat_messages = all_chat[-MAX_HISTORY_MESSAGES:] if len(all_chat) > MAX_HISTORY_MESSAGES else all_chat
for msg in chat_messages:
content = msg.content or None
entry: dict[str, Any] = {"role": msg.role, "content": content}
if msg.tool_calls_json:
@@ -136,7 +146,9 @@ class ChatService:
for tool_call in tool_calls:
fn = tool_call["function"]
args = LLMClient.parse_tool_arguments(fn.get("arguments", ""))
result = await execute_tool(self.db, fn["name"], args)
result = await execute_tool(
self.db, fn["name"], args, session_id=session_id
)
tool_message = {
"role": "tool",
"tool_call_id": tool_call["id"],