初始化:记忆系统源代码上传(已脱敏)
- 排除 .env / *.bak / 内部运维文档(README_INTERNAL.html) - config.py 默认密码已替换为占位符 CHANGE_ME_* - init_db.sql 移除生产数据库用户 GRANT 段 - README.html 数据库用户名已脱敏 - 保留:源码 + 公网 API 文档 + 建表 SQL(无授权语句)
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""Working Memory Compressor"""
|
||||
import logging
|
||||
from typing import Optional, Callable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MemoryCompressor:
|
||||
"""Compress working memories when they exceed threshold."""
|
||||
|
||||
def __init__(self, mysql_store, redis_cache, embedding_service):
|
||||
self.mysql = mysql_store
|
||||
self.redis = redis_cache
|
||||
self.embedder = embedding_service
|
||||
|
||||
def compress(self, agent_id: str, max_items: int = 20,
|
||||
summary_callback: Optional[Callable] = None) -> str:
|
||||
"""
|
||||
Compress working memories into a single long-term memory.
|
||||
|
||||
If working memory exceeds max_items, take the oldest items,
|
||||
summarize them (via callback or simple concatenation), and
|
||||
store as a personal long-term memory.
|
||||
|
||||
Returns: Summary text of compressed memories.
|
||||
"""
|
||||
# Get agent info to find team_id
|
||||
agent = self.mysql.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise ValueError(f"Agent {agent_id} not found")
|
||||
|
||||
items = self.redis.get_working_memories(agent_id, limit=100)
|
||||
if len(items) <= max_items:
|
||||
return {
|
||||
"compressed": 0,
|
||||
"remaining": len(items),
|
||||
"total_before": len(items),
|
||||
"target_count": max_items,
|
||||
"summary": None,
|
||||
}
|
||||
|
||||
# Take items beyond max_items (oldest)
|
||||
to_compress = items[max_items:]
|
||||
remaining = items[:max_items]
|
||||
|
||||
# Build summary
|
||||
contents = [item.get("content", "") for item in to_compress]
|
||||
if summary_callback:
|
||||
summary = summary_callback(contents)
|
||||
else:
|
||||
summary = " | ".join(contents[:50]) # Simple concat, limit 50 items
|
||||
|
||||
# Store as personal long-term memory
|
||||
embedding = self.embedder.embed(summary)
|
||||
from storage.vector_search import embedding_to_bytes
|
||||
emb_bytes = embedding_to_bytes(embedding)
|
||||
|
||||
self.mysql.add_personal_memory(
|
||||
agent_id=agent_id,
|
||||
team_id=agent["team_id"],
|
||||
content=summary,
|
||||
embedding=emb_bytes,
|
||||
importance=0.6, # Slightly elevated importance for compressed memories
|
||||
metadata={
|
||||
"source": "compression",
|
||||
"item_count": len(to_compress),
|
||||
"source_items": [
|
||||
{"content": item.get("content", "")[:200], "timestamp": item.get("timestamp")}
|
||||
for item in to_compress
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
# Replace working memory with remaining items
|
||||
self.redis.clear_working_memory(agent_id)
|
||||
for item in reversed(remaining): # lpush reverses order
|
||||
self.redis.add_working_memory(
|
||||
agent_id, item["content"],
|
||||
metadata=item.get("metadata", {}),
|
||||
)
|
||||
|
||||
logger.info(f"Compressed {len(to_compress)} working memories for agent {agent_id}")
|
||||
return {
|
||||
"compressed": len(to_compress),
|
||||
"remaining": len(remaining),
|
||||
"total_before": len(items),
|
||||
"target_count": max_items,
|
||||
"summary": summary,
|
||||
}
|
||||
Reference in New Issue
Block a user