mirror of
https://github.com/OpenBMB/ChatDev.git
synced 2026-04-25 11:18:06 +00:00
100 lines
3.2 KiB
Python
Executable File
100 lines
3.2 KiB
Python
Executable File
"""Lightweight append-only Blackboard memory implementation."""
|
|
|
|
import json
|
|
import os
|
|
import time
|
|
import uuid
|
|
from typing import List
|
|
|
|
from entity.configs import MemoryStoreConfig
|
|
from entity.configs.node.memory import BlackboardMemoryConfig
|
|
from runtime.node.agent.memory.memory_base import (
|
|
MemoryBase,
|
|
MemoryContentSnapshot,
|
|
MemoryItem,
|
|
MemoryWritePayload,
|
|
)
|
|
|
|
|
|
class BlackboardMemory(MemoryBase):
|
|
"""Simple append-only memory: save raw outputs, retrieve by recency."""
|
|
|
|
def __init__(self, store: MemoryStoreConfig):
|
|
config = store.as_config(BlackboardMemoryConfig)
|
|
if not config:
|
|
raise ValueError("BlackboardMemory requires a blackboard memory store configuration")
|
|
super().__init__(store)
|
|
self.config = config
|
|
self.memory_path = config.memory_path
|
|
self.max_items = config.max_items
|
|
|
|
# -------- Persistence --------
|
|
def load(self) -> None:
|
|
if not self.memory_path or not os.path.exists(self.memory_path):
|
|
self.contents = []
|
|
return
|
|
|
|
try:
|
|
with open(self.memory_path, "r", encoding="utf-8") as file:
|
|
data = json.load(file)
|
|
contents: List[MemoryItem] = []
|
|
for raw in data:
|
|
try:
|
|
contents.append(MemoryItem.from_dict(raw))
|
|
except Exception:
|
|
continue
|
|
self.contents = contents
|
|
except Exception:
|
|
# Corrupted file -> reset to empty to avoid blocking execution
|
|
self.contents = []
|
|
|
|
def save(self) -> None:
|
|
if not self.memory_path:
|
|
return
|
|
|
|
os.makedirs(os.path.dirname(self.memory_path), exist_ok=True)
|
|
payload = [item.to_dict() for item in self.contents[-self.max_items :]]
|
|
with open(self.memory_path, "w", encoding="utf-8") as file:
|
|
json.dump(payload, file, ensure_ascii=False, indent=2)
|
|
|
|
# -------- Memory operations --------
|
|
def retrieve(
|
|
self,
|
|
agent_role: str,
|
|
query: MemoryContentSnapshot,
|
|
top_k: int,
|
|
similarity_threshold: float,
|
|
) -> List[MemoryItem]:
|
|
if not self.contents:
|
|
return []
|
|
|
|
if top_k <= 0 or top_k >= len(self.contents):
|
|
return list(self.contents)
|
|
|
|
return list(self.contents[-top_k:])
|
|
|
|
def update(self, payload: MemoryWritePayload) -> None:
|
|
snapshot = payload.output_snapshot or payload.input_snapshot
|
|
content = (snapshot.text if snapshot else payload.inputs_text or "").strip()
|
|
if not content:
|
|
return
|
|
|
|
metadata = {
|
|
"agent_role": payload.agent_role,
|
|
"input_preview": (payload.inputs_text or "")[:200],
|
|
"attachments": snapshot.attachment_overview() if snapshot else [],
|
|
}
|
|
|
|
memory_item = MemoryItem(
|
|
id=f"bb_{uuid.uuid4().hex}",
|
|
content_summary=content,
|
|
metadata=metadata,
|
|
timestamp=time.time(),
|
|
input_snapshot=payload.input_snapshot,
|
|
output_snapshot=payload.output_snapshot,
|
|
)
|
|
|
|
self.contents.append(memory_item)
|
|
if len(self.contents) > self.max_items:
|
|
self.contents = self.contents[-self.max_items :]
|