Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4883b14ab6 |
@@ -50,78 +50,6 @@ def sanitize_context(text: str) -> str:
|
||||
return _FENCE_TAG_RE.sub('', text)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Prefetch filtering helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Meta-instruction debris that memory providers sometimes echo back.
|
||||
# These are prompts/instructions, not user-generated content.
|
||||
_META_INSTRUCTION_PATTERNS = [
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Focus on:\s*", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Note:\s*", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*System\s+(note|prompt|instruction):", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*You are\s+", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Please\s+(provide|respond|answer|write)", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Do not\s+", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Always\s+", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Consider\s+(the following|these|this)\b", re.IGNORECASE),
|
||||
re.compile(r"^\s*[\-\*]?\s*>?\s*Here\s+(is|are)\s+(some|the|a few)\b", re.IGNORECASE),
|
||||
]
|
||||
|
||||
|
||||
def _is_meta_instruction_line(line: str) -> bool:
|
||||
"""Return True if the line looks like a prompt/template instruction, not memory content."""
|
||||
for pat in _META_INSTRUCTION_PATTERNS:
|
||||
if pat.search(line):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _is_low_signal_line(line: str) -> bool:
|
||||
"""Return True for very short or content-free lines."""
|
||||
stripped = line.strip()
|
||||
# Empty or just punctuation/list marker
|
||||
if not stripped or stripped in {"-", "*", ">", "•", "—", "--"}:
|
||||
return True
|
||||
# Too short to be meaningful (< 15 chars after stripping markers)
|
||||
cleaned = re.sub(r"^[\-\*•>\s]+", "", stripped)
|
||||
if len(cleaned) < 15:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _filter_prefetch_lines(text: str) -> str:
|
||||
"""Filter and deduplicate prefetch result lines.
|
||||
|
||||
Removes:
|
||||
- exact duplicate lines
|
||||
- meta-instruction debris (prompts, templates)
|
||||
- very short / content-free lines
|
||||
|
||||
Returns cleaned text, preserving original line grouping.
|
||||
"""
|
||||
if not text or not text.strip():
|
||||
return ""
|
||||
|
||||
seen: set = set()
|
||||
kept: list = []
|
||||
for line in text.splitlines(keepends=False):
|
||||
stripped = line.strip()
|
||||
# Deduplicate exact lines
|
||||
if stripped in seen:
|
||||
continue
|
||||
# Skip meta-instructions
|
||||
if _is_meta_instruction_line(line):
|
||||
continue
|
||||
# Skip low-signal lines
|
||||
if _is_low_signal_line(line):
|
||||
continue
|
||||
seen.add(stripped)
|
||||
kept.append(line)
|
||||
|
||||
return "\n".join(kept)
|
||||
|
||||
|
||||
def build_memory_context_block(raw_context: str) -> str:
|
||||
"""Wrap prefetched memory in a fenced block with system note.
|
||||
|
||||
@@ -252,14 +180,7 @@ class MemoryManager:
|
||||
"Memory provider '%s' prefetch failed (non-fatal): %s",
|
||||
provider.name, e,
|
||||
)
|
||||
raw = "\n\n".join(parts)
|
||||
if not raw:
|
||||
return ""
|
||||
# Apply line-level filtering: dedupe, strip meta-instructions,
|
||||
# remove very short fragments. This prevents noisy providers
|
||||
# (e.g. MemPalace transcript recall) from bloating context.
|
||||
filtered = _filter_prefetch_lines(raw)
|
||||
return filtered
|
||||
return "\n\n".join(parts)
|
||||
|
||||
def queue_prefetch_all(self, query: str, *, session_id: str = "") -> None:
|
||||
"""Queue background prefetch on all providers for the next turn."""
|
||||
|
||||
157
docs/research/ai-tools-evaluation-842.md
Normal file
157
docs/research/ai-tools-evaluation-842.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# AI Tools Evaluation Report (#842)
|
||||
|
||||
**Source:** [formatho/awesome-ai-tools](https://github.com/formatho/awesome-ai-tools)
|
||||
**Date:** 2026-04-15
|
||||
**Tools Analyzed:** 414 across 9 categories
|
||||
**Scope:** Hermes-agent integration potential
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Scanned 414 tools from awesome-ai-tools. Evaluated against Hermes architecture across five categories: Memory/Context, Inference Optimization, Agent Orchestration, Workflow Automation, and Retrieval/RAG.
|
||||
|
||||
## Top 5 Recommendations & Implementation Status
|
||||
|
||||
### P1 — Mem0 (Memory/Context) ✅ IMPLEMENTED
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| GitHub | [mem0ai/mem0](https://github.com/mem0ai/mem0) |
|
||||
| Stars | 53.1k ⭐ |
|
||||
| Integration Effort | 3/5 |
|
||||
| Impact | 5/5 |
|
||||
|
||||
**Status:** Both cloud (mem0ai) and local (ChromaDB) variants implemented.
|
||||
|
||||
**Deliverables:**
|
||||
- `plugins/memory/mem0/` — Platform API provider with server-side LLM extraction, semantic search, reranking
|
||||
- `plugins/memory/mem0_local/` — Sovereign local variant using ChromaDB, no API key required
|
||||
- Tools: `mem0_profile`, `mem0_search`, `mem0_conclude`
|
||||
- Circuit breaker for resilience
|
||||
- 36 tests passing across both providers
|
||||
|
||||
**Activation:**
|
||||
```bash
|
||||
hermes memory setup # select "mem0" or "mem0_local"
|
||||
```
|
||||
|
||||
**Risk mitigation:** OSS-only features used in `mem0_local`. Cloud version uses freemium API but has circuit-breaker fallback.
|
||||
|
||||
---
|
||||
|
||||
### P2 — LightRAG (Retrieval/RAG) 🔴 NOT STARTED
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| GitHub | [HKUDS/LightRAG](https://github.com/HKUDS/LightRAG) |
|
||||
| Stars | 33.1k ⭐ |
|
||||
| Integration Effort | 3/5 |
|
||||
| Impact | 4/5 |
|
||||
|
||||
**Proposed integration:**
|
||||
- Local knowledge base for skill references and codebase understanding
|
||||
- Index GENOME.md, README.md, and key architecture files
|
||||
- Query via tool call when agent needs contextual understanding (not just keyword search)
|
||||
- Complements `search_files` without replacing it
|
||||
|
||||
**Blocker:** Requires OpenAI-compatible embedding endpoint. Can use local Ollama via compatibility layer.
|
||||
|
||||
**Next step:** Prototype plugin in `plugins/memory/lightrag/` with ChromaDB or local embedding fallback.
|
||||
|
||||
---
|
||||
|
||||
### P3 — tensorzero (Inference Optimization / LLMOps) 🔴 NOT STARTED
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| GitHub | [tensorzero/tensorzero](https://github.com/tensorzero/tensorzero) |
|
||||
| Stars | 11.2k ⭐ |
|
||||
| Integration Effort | 3/5 |
|
||||
| Impact | 4/5 |
|
||||
|
||||
**Proposed integration:**
|
||||
- Replace custom provider routing, fallback chains, and token tracking
|
||||
- Intelligent routing across providers with cost/quality optimization
|
||||
- Automatic prompt optimization based on feedback
|
||||
- Evaluation metrics for A/B testing model/provider combinations
|
||||
|
||||
**Blocker:** Rust-based infrastructure. Requires careful migration of existing provider logic. Best done as gradual opt-in, not replacement.
|
||||
|
||||
**Next step:** Evaluate tensorzero gateway as optional `providers.tensorzero` backend.
|
||||
|
||||
---
|
||||
|
||||
### P4 — RAGFlow (Retrieval/RAG) 🔴 NOT STARTED
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| GitHub | [infiniflow/ragflow](https://github.com/infiniflow/ragflow) |
|
||||
| Stars | 77.9k ⭐ |
|
||||
| Integration Effort | 4/5 |
|
||||
| Impact | 4/5 |
|
||||
|
||||
**Proposed integration:**
|
||||
- Deploy as local Docker service for document understanding
|
||||
- Ingest technical docs, research papers, codebases
|
||||
- Query via HTTP API when agents need deep document comprehension
|
||||
|
||||
**Blocker:** Heavy deployment (multi-service Docker). Best suited for always-on infrastructure, not per-session.
|
||||
|
||||
**Next step:** Add RAGFlow API client tool in `tools/ragflow_tool.py` for document querying.
|
||||
|
||||
---
|
||||
|
||||
### P5 — n8n (Workflow Automation) 🔴 NOT STARTED
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| GitHub | [n8n-io/n8n](https://github.com/n8n-io/n8n) |
|
||||
| Stars | 183.9k ⭐ |
|
||||
| Integration Effort | 4/5 |
|
||||
| Impact | 5/5 |
|
||||
|
||||
**Proposed integration:**
|
||||
- Orchestrate Hermes agents from external events (webhooks, schedules)
|
||||
- Visual workflow builder for burn loops, PR pipelines, multi-agent chains
|
||||
- n8n webhooks trigger Hermes cron jobs or fleet dispatches
|
||||
|
||||
**Blocker:** Full application stack (Node.js, PostgreSQL, Redis). Deploy as standalone Docker service.
|
||||
|
||||
**Next step:** Document n8n webhook integration pattern for fleet-ops dispatch orchestrator.
|
||||
|
||||
---
|
||||
|
||||
## Honorable Mentions Already in Stack
|
||||
|
||||
| Tool | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| llama.cpp | ✅ Integrated | Via Ollama local inference |
|
||||
| mempalace | ✅ Integrated | Holographic memory system (44.8k ⭐) |
|
||||
|
||||
---
|
||||
|
||||
## Category Breakdown
|
||||
|
||||
### Memory/Context (9 tools evaluated)
|
||||
- Mem0 → **IMPLEMENTED** (cloud + local)
|
||||
- memvid, mempalace, nocturne_memory, rowboat, byterover-cli, letta-code, hindsight, agentic-context-engine → Evaluated, no action
|
||||
|
||||
### Inference Optimization (5 tools evaluated)
|
||||
- llama.cpp → **Already integrated**
|
||||
- vllm, tensorzero, mistral.rs, pruna → Evaluated, no action
|
||||
|
||||
### Retrieval/RAG (5 tools evaluated)
|
||||
- RAGFlow, LightRAG, PageIndex, WeKnora, RAG-Anything → Evaluated, no action
|
||||
|
||||
### Agent Orchestration (5 tools evaluated)
|
||||
- n8n, Langflow, agent-framework, deepagents, multica → Evaluated, no action
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Source repository: https://github.com/formatho/awesome-ai-tools
|
||||
- Total tools: 414 across 9 categories
|
||||
- Freshness distribution: 🟢 303 | 🟡 49 | 🟠 22 | 🔴 40
|
||||
- Hermes issue: [#842](https://forge.alexanderwhitestone.com/Timmy_Foundation/hermes-agent/issues/842)
|
||||
@@ -198,14 +198,14 @@ class TestMemoryManager:
|
||||
def test_prefetch_skips_empty(self):
|
||||
mgr = MemoryManager()
|
||||
p1 = FakeMemoryProvider("builtin")
|
||||
p1._prefetch_result = "This provider has meaningful memories with enough length"
|
||||
p1._prefetch_result = "Has memories"
|
||||
p2 = FakeMemoryProvider("external")
|
||||
p2._prefetch_result = ""
|
||||
mgr.add_provider(p1)
|
||||
mgr.add_provider(p2)
|
||||
|
||||
result = mgr.prefetch_all("query")
|
||||
assert result == "This provider has meaningful memories with enough length"
|
||||
assert result == "Has memories"
|
||||
|
||||
def test_queue_prefetch_all(self):
|
||||
mgr = MemoryManager()
|
||||
@@ -695,92 +695,3 @@ class TestMemoryContextFencing:
|
||||
fence_end = combined.index("</memory-context>")
|
||||
assert "Alice" in combined[fence_start:fence_end]
|
||||
assert combined.index("weather") < fence_start
|
||||
|
||||
|
||||
class TestPrefetchFiltering:
|
||||
"""Tests for _filter_prefetch_lines and related helpers."""
|
||||
|
||||
def test_deduplicates_exact_lines(self):
|
||||
from agent.memory_manager import _filter_prefetch_lines
|
||||
raw = "- This is line one with enough characters\n- This is line two with enough characters\n- This is line one with enough characters\n- This is line three with enough characters"
|
||||
result = _filter_prefetch_lines(raw)
|
||||
lines = [l for l in result.splitlines() if l.strip()]
|
||||
assert len(lines) == 3
|
||||
assert "- This is line one with enough characters" in result
|
||||
assert "- This is line two with enough characters" in result
|
||||
assert "- This is line three with enough characters" in result
|
||||
|
||||
def test_removes_meta_instruction_debris(self):
|
||||
from agent.memory_manager import _filter_prefetch_lines
|
||||
raw = (
|
||||
"## Fleet Memories\n"
|
||||
"- > Focus on: was a non-trivial approach used\n"
|
||||
"- > Focus on: was a non-trivial approach used\n"
|
||||
"- Actual memory content about fleet ops\n"
|
||||
"- Note: this is just a note\n"
|
||||
)
|
||||
result = _filter_prefetch_lines(raw)
|
||||
assert "Focus on" not in result
|
||||
assert "Note:" not in result
|
||||
assert "Actual memory content about fleet ops" in result
|
||||
assert "Fleet Memories" in result
|
||||
|
||||
def test_removes_low_signal_short_lines(self):
|
||||
from agent.memory_manager import _filter_prefetch_lines
|
||||
raw = (
|
||||
"- \n"
|
||||
"- x\n"
|
||||
"- This is a meaningful memory entry with enough length\n"
|
||||
)
|
||||
result = _filter_prefetch_lines(raw)
|
||||
assert "- x" not in result
|
||||
assert "meaningful memory entry" in result
|
||||
|
||||
def test_preserves_structured_facts(self):
|
||||
from agent.memory_manager import _filter_prefetch_lines
|
||||
raw = (
|
||||
"## Local Facts (Hologram)\n"
|
||||
"- ALEXANDER: Prefers Gitea for reports and deliverables.\n"
|
||||
"- Telegram home channel is Timmy Time.\n"
|
||||
)
|
||||
result = _filter_prefetch_lines(raw)
|
||||
assert "ALEXANDER" in result
|
||||
assert "Gitea" in result
|
||||
assert "Telegram" in result
|
||||
|
||||
def test_is_meta_instruction_line(self):
|
||||
from agent.memory_manager import _is_meta_instruction_line
|
||||
assert _is_meta_instruction_line("- > Focus on: something") is True
|
||||
assert _is_meta_instruction_line("- Focus on: something") is True
|
||||
assert _is_meta_instruction_line("* Focus on: something") is True
|
||||
assert _is_meta_instruction_line("- Actual user memory content") is False
|
||||
assert _is_meta_instruction_line("ALEXANDER: Prefers Gitea") is False
|
||||
|
||||
def test_is_low_signal_line(self):
|
||||
from agent.memory_manager import _is_low_signal_line
|
||||
assert _is_low_signal_line("- ") is True
|
||||
assert _is_low_signal_line("*") is True
|
||||
assert _is_low_signal_line("- x") is True
|
||||
assert _is_low_signal_line("- Short line") is True
|
||||
assert _is_low_signal_line("- This is a long meaningful memory entry") is False
|
||||
|
||||
def test_prefetch_all_applies_filtering(self):
|
||||
from agent.memory_manager import MemoryManager
|
||||
mgr = MemoryManager()
|
||||
fake = FakeMemoryProvider(name="test")
|
||||
fake._prefetch_result = (
|
||||
"- > Focus on: was a non-trivial approach\n"
|
||||
"- > Focus on: was a non-trivial approach\n"
|
||||
"- Real memory fact\n"
|
||||
)
|
||||
mgr.add_provider(fake)
|
||||
result = mgr.prefetch_all("query")
|
||||
assert "Focus on" not in result
|
||||
assert "Real memory fact" in result
|
||||
assert result.count("Real memory fact") == 1
|
||||
|
||||
def test_empty_prefetch_returns_empty(self):
|
||||
from agent.memory_manager import _filter_prefetch_lines
|
||||
assert _filter_prefetch_lines("") == ""
|
||||
assert _filter_prefetch_lines(" ") == ""
|
||||
assert _filter_prefetch_lines("\n\n") == ""
|
||||
|
||||
Reference in New Issue
Block a user