diff --git a/main.py b/main.py index b16e5ee..33148d0 100644 --- a/main.py +++ b/main.py @@ -101,11 +101,20 @@ async def build_context(request: ChatRequest) -> list[dict]: summary_block = f"## Earlier conversation summary\n{summary}" if summary else "" # 4. Assemble system prompt - base_system = ( - "You are an expert coding assistant with deep knowledge of the project architecture. " - "Use the provided memory and code context to give precise, informed answers. " - "Always reason about the full architecture, not just isolated snippets." - ) + base_system = """Ты — AI-ассистент по программированию с постоянной памятью. + +У тебя есть три уровня памяти: +1. Долгосрочная память — факты о пользователе и проектах (показаны ниже в "Relevant memories") +2. История диалога — последние 20 сообщений текущей сессии +3. Контекст кода — граф архитектуры проекта (если проиндексирован) + +Используй память чтобы давать точные ответы с учётом контекста пользователя. \ +Если в памяти есть релевантный факт — опирайся на него, не переспрашивай то что уже известно. + +Пользователь может управлять твоей памятью прямо в чате: +- "запомни что X" — ты сохранишь X с высоким приоритетом +- "забудь про X" — ты удалишь похожие воспоминания +- "что ты помнишь?" — покажи список активных воспоминаний через GET /v1/memories""" context_parts = [p for p in [base_system, summary_block, mem_block, code_block] if p] system_content = "\n\n".join(context_parts) diff --git a/memory.py b/memory.py index e90393a..de8dfc0 100644 --- a/memory.py +++ b/memory.py @@ -134,24 +134,51 @@ async def get_summary(session_id: str) -> str | None: # ── extract & store facts after each turn ──────────────────────────────────── -EXTRACT_PROMPT = """Extract important facts, preferences, or technical details from this message. -Return a JSON array of strings (facts). Max 5 items. If nothing important, return []. -Only technical or personal facts worth remembering long-term. -Message: {msg}""" +EXTRACT_SYSTEM = """Ты — система извлечения фактов из переписки. Твоя задача: найти факты о ПОЛЬЗОВАТЕЛЕ, достойные долгосрочного хранения. + +СОХРАНЯЙ: +- Имя, роль, профессия пользователя ("я разработчик", "меня зовут Иван") +- Язык программирования, фреймворк, стек ("пишу на Go", "использую FastAPI") +- ОС, редактор, инструменты ("сижу на Arch", "использую Neovim") +- Характеристики проекта ("проект на Django", "БД PostgreSQL", "деплой на Proxmox") +- Явные предпочтения ("предпочитаю tabs", "не люблю TypeScript") +- Технические ограничения ("сервер 4GB RAM", "Python 3.11") +- Личные факты которые пользователь сообщил о себе + +НЕ СОХРАНЯЙ: +- Вопросы (строки со знаком ?) +- Приветствия ("привет", "hello", "окей") +- Одиночные слова или короткие реплики без факта +- То что сказал ассистент — только слова пользователя +- Запросы без фактов ("помоги мне", "объясни как") +- Мусор, шутки, эмоции без информации + +ФОРМАТ ОТВЕТА: только JSON массив строк, без пояснений, без markdown. +Правильно: ["пользователь пишет на Python 3.12", "использует Neovim"] +Неправильно: ```json\n["факт"]\n``` или "Вот факты: [...]" + +Если фактов нет — верни пустой массив: []""" + +EXTRACT_PROMPT = """Извлеки факты из сообщения пользователя. Максимум 5 фактов. + +Сообщение пользователя: +{msg} + +JSON массив:""" async def extract_and_store(content: str, user_id: str = "default"): try: raw = await chat([ - {"role": "user", "content": EXTRACT_PROMPT.format(msg=content[:1500])} + {"role": "system", "content": EXTRACT_SYSTEM}, + {"role": "user", "content": EXTRACT_PROMPT.format(msg=content[:1500])} ]) - # find JSON array in response start = raw.find("[") end = raw.rfind("]") + 1 if start == -1 or end == 0: return facts = json.loads(raw[start:end]) for fact in facts[:5]: - if isinstance(fact, str) and len(fact) > 10: + if isinstance(fact, str) and len(fact) > 15: await store_memory(fact, user_id=user_id, memory_type="fact") except Exception: pass # never crash the main flow