Phase 4-6: Message Bus, Memory Search (ChromaDB), Token Tracking, Topology Graph
Phase 4: Message Bus Viewer
- Backend: get_message_bus_status(), send_bus_message() in agents.py
- Route: GET /api/agents/message-bus, POST /api/agents/{id}/bus-message
- Frontend: Message Bus tab in agent detail overlay
Phase 5: Memory Search (ChromaDB)
- Backend: _search_agent_memory(), _search_all_agents_memory() via ChromaDB rose_memory collection
- Route: GET /api/agents/memory/search, GET /api/agents/{id}/memory/search
- Frontend: Search bar added to Memory tab, renders confidence scores + topics
Phase 6: Token Tracking + Topology Graph
- Backend: get_agent_usage() reads ~/.hermes/agents/{id}/usage.json
- Route: GET /api/agents/{id}/usage
- Frontend: Usage tab with today/week/month token counts and cost
- Frontend: Topology tab with SVG radial graph of agent network
This commit is contained in:
80
api/agents_memory.py
Normal file
80
api/agents_memory.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
Phase 5 — Memory Search (ChromaDB)
|
||||
Appended to agents.py functions for Memory Search.
|
||||
"""
|
||||
import chromadb
|
||||
|
||||
|
||||
def _get_chroma_client():
|
||||
"""Get or create the shared ChromaDB HTTP client (thread-safe singleton)."""
|
||||
if not hasattr(_get_chroma_client, "_client"):
|
||||
_get_chroma_client._client = chromadb.HttpClient(host="127.0.0.1", port=8000)
|
||||
return _get_chroma_client._client
|
||||
|
||||
|
||||
def _search_agent_memory(agent_id: str, query: str, limit: int = 10) -> list:
|
||||
"""
|
||||
Search memory for a specific agent.
|
||||
Searches the rose_memory collection filtered by topic matching agent_id.
|
||||
"""
|
||||
try:
|
||||
client = _get_chroma_client()
|
||||
coll = client.get_collection(name="rose_memory")
|
||||
results = coll.query(
|
||||
query_texts=[query],
|
||||
n_results=limit,
|
||||
include=["metadatas", "documents"],
|
||||
)
|
||||
matches = []
|
||||
for i, doc in enumerate(results.get("documents", [[]])[0] or []):
|
||||
meta = (results.get("metadatas", [[{}]])[0] or [{}])[i] or {}
|
||||
topic = meta.get("topic", "")
|
||||
# Filter: only docs that belong to this agent (topic starts with agent_id)
|
||||
if not topic.startswith(agent_id):
|
||||
continue
|
||||
matches.append({
|
||||
"id": (results.get("ids", [["?"]])[0] or ["?"])[i],
|
||||
"topic": topic,
|
||||
"content": doc,
|
||||
"confidence": float(meta.get("confidence", 0.0)),
|
||||
"tags": meta.get("tags", ""),
|
||||
"vault_path": meta.get("vault_path", ""),
|
||||
})
|
||||
return matches
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
def _search_all_agents_memory(query: str, limit: int = 20) -> list:
|
||||
"""
|
||||
Search across all agent memories in ChromaDB.
|
||||
Returns matches with agent attribution from topic.
|
||||
Topic format: "agent-name/fact-name" or flat topic name.
|
||||
"""
|
||||
try:
|
||||
client = _get_chroma_client()
|
||||
coll = client.get_collection(name="rose_memory")
|
||||
results = coll.query(
|
||||
query_texts=[query],
|
||||
n_results=limit,
|
||||
include=["metadatas", "documents"],
|
||||
)
|
||||
matches = []
|
||||
for i, doc in enumerate(results.get("documents", [[]])[0] or []):
|
||||
meta = (results.get("metadatas", [[{}]])[0] or [{}])[i] or {}
|
||||
topic = meta.get("topic", "")
|
||||
# Extract agent from topic: "agent-name/ffact" -> agent
|
||||
parts = topic.split("/")
|
||||
agent = parts[0] if len(parts) > 1 else topic
|
||||
matches.append({
|
||||
"id": (results.get("ids", [["?"]])[0] or ["?"])[i],
|
||||
"topic": topic,
|
||||
"agent": agent,
|
||||
"content": doc,
|
||||
"confidence": float(meta.get("confidence", 0.0)),
|
||||
"tags": meta.get("tags", ""),
|
||||
"vault_path": meta.get("vault_path", ""),
|
||||
})
|
||||
return matches
|
||||
except Exception:
|
||||
return []
|
||||
Reference in New Issue
Block a user