Skip to main content

Embedded Agents Overview

Embedded agents are autonomous, AI-powered processes that manage memory operations within memharness. They handle complex tasks like entity extraction, summarization, consolidation, and context assembly — operations that require semantic understanding beyond simple heuristics.

What Are Memory Agents?

Memory Agents = Small, specialized LLM-powered processes embedded INSIDE your memory infrastructure that autonomously perform memory management tasks.

They're called "embedded" because they live within the memharness system itself, not in your application code. Think of them as automated janitors, librarians, and curators working behind the scenes.

The 5 Embedded Agents

memharness provides 5 specialized agents:

AgentPurposeModeExample
SummarizerCompress old conversationsHeuristic + LLM30 messages → 1 paragraph
Entity ExtractorExtract people, places, orgsRegex + LLM"Dr. Chen works at MIT" → 2 entities
ConsolidatorMerge duplicate memoriesSemantic + LLM3 "Dr. Chen" entries → 1 merged entity
Garbage CollectorClean expired memoriesPolicy-basedDelete memories older than 365d
Context AssemblerBuild optimal LLM contextRetrieval + rankingAssemble top-K from each memory type

Dual-Mode Design

All agents follow a dual-mode design pattern:

  1. Without LLM — Uses heuristics, regex, or policy rules. Works immediately, no setup required.
  2. With LLM — Uses LangChain for intelligent operations. Better quality, requires LLM configuration.
from memharness import MemoryHarness
from memharness.agents import EntityExtractorAgent
from langchain.chat_models import init_chat_model

# Mode 1: Without LLM (heuristic)
harness = MemoryHarness("sqlite:///memory.db")
agent = EntityExtractorAgent(harness) # No LLM
entities = await agent.extract_entities("Dr. Chen works at MIT")
# Uses regex: capitalized words, @mentions, email addresses

# Mode 2: With LLM (intelligent)
llm = init_chat_model("gpt-4o")
agent = EntityExtractorAgent(harness, llm=llm)
entities = await agent.extract_entities("Dr. Chen works at MIT")
# Uses LangChain structured output for accurate NER

Agent Lifecycle: Triggers

Agents can be triggered in different ways:

Trigger TypeWhen It FiresExample
ON_WRITEWhen new memory is addedEntity extraction on every message
ON_READWhen memory is retrievedContext assembly before LLM call
PRE_LLMBefore sending context to LLMContext optimization
POST_LLMAfter receiving LLM responseExtract entities from response
SCHEDULEDTime-based periodic executionDaily consolidation at 3 AM
POLICYTriggered by policy rulesGC when storage > 90%
ON_DEMANDManual invocationUser calls agent.run()

The BaseMemoryAgent Protocol

All agents implement the same interface:

from memharness.agents.base import BaseMemoryAgent

class MyAgent(BaseMemoryAgent):
def __init__(self, harness: MemoryHarness, llm: BaseChatModel | None = None):
self.harness = harness
self.llm = llm

async def run(self, **kwargs) -> dict[str, Any]:
"""Execute the agent's main logic."""
if not self.llm:
return await self._heuristic_mode(**kwargs)
return await self._llm_mode(**kwargs)

This consistent interface makes agents composable, testable, and framework-agnostic.

BEFORE / INSIDE / AFTER the Loop

Agents operate at different points in the agent execution lifecycle:

Why Embedded Agents?

Without AgentsWith Agents
Manual memory managementAutomated memory operations
Write extraction logic in your appAgents handle it internally
Context assembly is your problemContext Assembler does it for you
No deduplication → messy memoryConsolidator keeps it clean
Memory grows forever → DB bloatGC agent cleans expired memories
Inconsistent behavior across projectsStandardized, battle-tested agents

Configuration

Agents can be configured via YAML:

agents:
entity_extractor:
enabled: true
trigger: on_write
llm: gpt-4o-mini

summarizer:
enabled: true
triggers:
- condition: "age > 7d"
- condition: "message_count > 50"
llm: gpt-4o-mini

consolidator:
enabled: true
schedule: "0 3 * * *" # Daily at 3 AM
similarity_threshold: 0.9
llm: gpt-4o

gc:
enabled: true
schedule: "0 4 * * 0" # Weekly Sunday 4 AM
archive_after: 90d
delete_after: 365d

Next Steps