feat: auto-summarize trigger for agent memory

- Memory Service: POST /agents/{agent_id}/summarize endpoint
  - Fetches recent events by agent_id (new db.list_facts_by_agent)
  - Generates structured summary via DeepSeek LLM
  - Saves summary to PostgreSQL facts + Qdrant vector store
  - Returns structured JSON (summary, goals, decisions, key_facts)

- Gateway memory_client: auto-trigger after 30 turns
  - Turn counter per chat (agent_id:channel_id)
  - 5-minute debounce between summarize calls
  - Fire-and-forget via asyncio.ensure_future (non-blocking)
  - Configurable via SUMMARIZE_TURN_THRESHOLD / SUMMARIZE_DEBOUNCE_SECONDS

- Database: list_facts_by_agent() for agent-level queries without user_id

Tested on NODE1: Helion summarize returns valid Ukrainian summary with 20 events.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Apple
2026-02-09 10:15:43 -08:00
parent acceac6929
commit 0cfd3619ea
3 changed files with 263 additions and 0 deletions

View File

@@ -517,6 +517,25 @@ class Database:
return [dict(row) for row in rows]
async def list_facts_by_agent(
self,
agent_id: str,
channel_id: str = None,
limit: int = 60
) -> list:
"""List facts for an agent (any user), ordered by most recent."""
async with self.pool.acquire() as conn:
query = "SELECT * FROM user_facts WHERE agent_id = $1"
params = [agent_id]
if channel_id:
query += " AND fact_key LIKE '%' || $2 || '%'"
params.append(channel_id)
query += " ORDER BY updated_at DESC"
query += f" LIMIT ${len(params) + 1}"
params.append(limit)
rows = await conn.fetch(query, *params)
return [dict(row) for row in rows]
async def delete_fact(
self,
user_id: str,