Skip to content

Commit 61fafca

Browse files
committed
feat: Add context injection modes to Mem0Memory
chore: Export ContextInjectionMode enum fix: tests fix: format chore: remove mem0 deps to fix tests fix: patch of memory client fix: check we are dealing with a FunctionCall before accessing attributes fix: use public constructor fix: add empty line at end of file
1 parent e26bb1c commit 61fafca

File tree

4 files changed

+288
-31
lines changed

4 files changed

+288
-31
lines changed

python/docs/src/user-guide/agentchat-user-guide/memory.ipynb

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,9 @@
542542
"source": [
543543
"## Mem0Memory Example\n",
544544
"\n",
545-
"`autogen_ext.memory.mem0.Mem0Memory` provides integration with `Mem0.ai`'s memory system. It supports both cloud-based and local backends, offering advanced memory capabilities for agents. The implementation handles proper retrieval and context updating, making it suitable for production environments.\n",
545+
"`autogen_ext.memory.mem0.Mem0Memory` provides integration with `Mem0.ai`'s memory system. It supports both cloud-based and local backends, offering advanced memory capabilities for agents. The implementation handles proper retrieval and context updating with configurable injection modes, making it suitable for production environments.\n",
546546
"\n",
547-
"In the following example, we'll demonstrate how to use `Mem0Memory` to maintain persistent memories across conversations:"
547+
"In the following example, we'll demonstrate how to use `Mem0Memory` to maintain persistent memories across conversations:"
548548
]
549549
},
550550
{
@@ -556,14 +556,15 @@
556556
"from autogen_agentchat.agents import AssistantAgent\n",
557557
"from autogen_agentchat.ui import Console\n",
558558
"from autogen_core.memory import MemoryContent, MemoryMimeType\n",
559-
"from autogen_ext.memory.mem0 import Mem0Memory\n",
559+
"from autogen_ext.memory.mem0 import Mem0Memory, ContextInjectionMode\n",
560560
"from autogen_ext.models.openai import OpenAIChatCompletionClient\n",
561561
"\n",
562562
"# Initialize Mem0 cloud memory (requires API key)\n",
563563
"# For local deployment, use is_cloud=False with appropriate config\n",
564564
"mem0_memory = Mem0Memory(\n",
565565
" is_cloud=True,\n",
566566
" limit=5, # Maximum number of memories to retrieve\n",
567+
" context_injection_mode=ContextInjectionMode.SYSTEM_MESSAGE, # Default mode\n",
567568
")\n",
568569
"\n",
569570
"# Add user preferences to memory\n",
@@ -595,12 +596,12 @@
595596
"\n",
596597
"# Ask about the weather\n",
597598
"stream = assistant_agent.run_stream(task=\"What are my dietary preferences?\")\n",
598-
"await Console(stream)"
599+
"await Console(stream)\n"
599600
]
600601
},
601602
{
602-
"cell_type": "markdown",
603603
"metadata": {},
604+
"cell_type": "markdown",
604605
"source": [
605606
"The example above demonstrates how Mem0Memory can be used with an assistant agent. The memory integration ensures that:\n",
606607
"\n",
@@ -618,20 +619,70 @@
618619
]
619620
},
620621
{
621-
"cell_type": "code",
622-
"execution_count": null,
623622
"metadata": {},
623+
"cell_type": "code",
624624
"outputs": [],
625+
"execution_count": null,
625626
"source": [
626627
"# Serialize the memory configuration\n",
627628
"config_json = mem0_memory.dump_component().model_dump_json()\n",
628629
"print(f\"Memory config JSON: {config_json[:100]}...\")"
629630
]
630631
},
631632
{
633+
"metadata": {},
634+
"cell_type": "markdown",
635+
"source": [
636+
"### Context Injection Modes\n",
637+
"\n",
638+
"Mem0Memory supports two different modes for injecting retrieved memories into the model context:"
639+
]
640+
},
641+
{
642+
"metadata": {},
643+
"cell_type": "markdown",
644+
"source": [
645+
"#### System Message Mode (Default)\n",
646+
"\n",
647+
"This is the traditional approach where memories are added as system messages:"
648+
]
649+
},
650+
{
651+
"metadata": {},
652+
"cell_type": "code",
653+
"outputs": [],
654+
"execution_count": null,
655+
"source": [
656+
"# Default behavior - memories added as system messages\n",
657+
"mem0_memory = Mem0Memory(\n",
658+
" is_cloud=False,\n",
659+
" config={\"path\": \":memory:\"},\n",
660+
" context_injection_mode=ContextInjectionMode.SYSTEM_MESSAGE, # Default\n",
661+
")"
662+
]
663+
},
664+
{
665+
"metadata": {},
632666
"cell_type": "markdown",
667+
"source": [
668+
"#### Function Call Mode\n",
669+
"\n",
670+
"This mode injects memories as function call results, this is suitable for models that do not support multiple system messages:"
671+
]
672+
},
673+
{
633674
"metadata": {},
634-
"source": []
675+
"cell_type": "code",
676+
"outputs": [],
677+
"execution_count": null,
678+
"source": [
679+
"# Function call mode - memories added as function execution results\n",
680+
"mem0_memory = Mem0Memory(\n",
681+
" is_cloud=False,\n",
682+
" config={\"path\": \":memory:\"},\n",
683+
" context_injection_mode=ContextInjectionMode.FUNCTION_CALL,\n",
684+
")"
685+
]
635686
}
636687
],
637688
"metadata": {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from ._mem0 import Mem0Memory, Mem0MemoryConfig
1+
from ._mem0 import ContextInjectionMode, Mem0Memory, Mem0MemoryConfig
22

33
__all__ = [
44
"Mem0Memory",
55
"Mem0MemoryConfig",
6+
"ContextInjectionMode",
67
]

python/packages/autogen-ext/src/autogen_ext/memory/mem0/_mem0.py

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import uuid
44
from contextlib import redirect_stderr, redirect_stdout
55
from datetime import datetime
6+
from enum import Enum
67
from typing import Any, Dict, List, Optional, TypedDict, cast
78

8-
from autogen_core import CancellationToken, Component, ComponentBase
9+
from autogen_core import CancellationToken, Component, ComponentBase, FunctionCall
910
from autogen_core.memory import Memory, MemoryContent, MemoryQueryResult, UpdateContextResult
1011
from autogen_core.model_context import ChatCompletionContext
11-
from autogen_core.models import SystemMessage
12+
from autogen_core.models import AssistantMessage, FunctionExecutionResult, FunctionExecutionResultMessage, SystemMessage
1213
from mem0 import Memory as Memory0
1314
from mem0 import MemoryClient
1415
from pydantic import BaseModel, Field
@@ -18,6 +19,13 @@
1819
logging.getLogger("chromadb").setLevel(logging.ERROR)
1920

2021

22+
class ContextInjectionMode(Enum):
23+
"""Enum for context injection modes."""
24+
25+
SYSTEM_MESSAGE = "system_message"
26+
FUNCTION_CALL = "function_call"
27+
28+
2129
class Mem0MemoryConfig(BaseModel):
2230
"""Configuration for Mem0Memory component."""
2331

@@ -32,6 +40,10 @@ class Mem0MemoryConfig(BaseModel):
3240
config: Optional[Dict[str, Any]] = Field(
3341
default=None, description="Configuration dictionary for local Mem0 client. Required if is_cloud=False."
3442
)
43+
context_injection_mode: ContextInjectionMode = Field(
44+
default=ContextInjectionMode.SYSTEM_MESSAGE,
45+
description="Mode for injecting memories into context: 'system_message' or 'function_call'.",
46+
)
3547

3648

3749
class MemoryResult(TypedDict, total=False):
@@ -68,15 +80,16 @@ class Mem0Memory(Memory, Component[Mem0MemoryConfig], ComponentBase[Mem0MemoryCo
6880
.. code-block:: python
6981
7082
import asyncio
71-
from autogen_ext.memory.mem0 import Mem0Memory
83+
from autogen_ext.memory.mem0 import Mem0Memory, ContextInjectionMode
7284
from autogen_core.memory import MemoryContent
7385
7486
7587
async def main() -> None:
76-
# Create a local Mem0Memory (no API key required)
88+
# Create a local Mem0Memory with function call injection mode
7789
memory = Mem0Memory(
7890
is_cloud=False,
7991
config={"path": ":memory:"}, # Use in-memory storage for testing
92+
context_injection_mode=ContextInjectionMode.FUNCTION_CALL,
8093
)
8194
print("Memory initialized successfully!")
8295
@@ -111,19 +124,20 @@ async def main() -> None:
111124
import asyncio
112125
from autogen_agentchat.agents import AssistantAgent
113126
from autogen_core.memory import MemoryContent
114-
from autogen_ext.memory.mem0 import Mem0Memory
127+
from autogen_ext.memory.mem0 import Mem0Memory, ContextInjectionMode
115128
from autogen_ext.models.openai import OpenAIChatCompletionClient
116129
117130
118131
async def main() -> None:
119132
# Create a model client
120133
model_client = OpenAIChatCompletionClient(model="gpt-4.1")
121134
122-
# Create a Mem0 memory instance
135+
# Create a Mem0 memory instance with system message injection (default)
123136
memory = Mem0Memory(
124137
user_id="user123",
125138
is_cloud=False,
126139
config={"path": ":memory:"}, # Use in-memory storage for testing
140+
context_injection_mode=ContextInjectionMode.SYSTEM_MESSAGE,
127141
)
128142
129143
# Add something to memory
@@ -157,6 +171,7 @@ async def main() -> None:
157171
is_cloud: Whether to use cloud Mem0 client (True) or local client (False).
158172
api_key: API key for cloud Mem0 client. It will read from the environment MEM0_API_KEY if not provided.
159173
config: Configuration dictionary for local Mem0 client. Required if is_cloud=False.
174+
context_injection_mode: Mode for injecting memories into context ('system_message' or 'function_call').
160175
"""
161176

162177
component_type = "memory"
@@ -170,6 +185,7 @@ def __init__(
170185
is_cloud: bool = True,
171186
api_key: Optional[str] = None,
172187
config: Optional[Dict[str, Any]] = None,
188+
context_injection_mode: ContextInjectionMode = ContextInjectionMode.SYSTEM_MESSAGE,
173189
) -> None:
174190
# Validate parameters
175191
if not is_cloud and config is None:
@@ -181,6 +197,7 @@ def __init__(
181197
self._is_cloud = is_cloud
182198
self._api_key = api_key
183199
self._config = config
200+
self._context_injection_mode = context_injection_mode
184201

185202
# Initialize client
186203
if self._is_cloud:
@@ -210,6 +227,11 @@ def config(self) -> Optional[Dict[str, Any]]:
210227
"""Get the configuration for the Mem0 client."""
211228
return self._config
212229

230+
@property
231+
def context_injection_mode(self) -> ContextInjectionMode:
232+
"""Get the context injection mode."""
233+
return self._context_injection_mode
234+
213235
async def add(
214236
self,
215237
content: MemoryContent,
@@ -366,7 +388,8 @@ async def update_context(
366388
367389
This method retrieves the conversation history from the model context,
368390
uses the last message as a query to find relevant memories, and then
369-
adds those memories to the context as a system message.
391+
adds those memories to the context either as a system message or as
392+
function call messages based on the configured injection mode.
370393
371394
Args:
372395
model_context: The model context to update.
@@ -392,8 +415,40 @@ async def update_context(
392415
memory_strings = [f"{i}. {str(memory.content)}" for i, memory in enumerate(query_results.results, 1)]
393416
memory_context = "\nRelevant memories:\n" + "\n".join(memory_strings)
394417

395-
# Add as system message
396-
await model_context.add_message(SystemMessage(content=memory_context))
418+
if self._context_injection_mode == ContextInjectionMode.SYSTEM_MESSAGE:
419+
# Add as system message (original behavior)
420+
await model_context.add_message(SystemMessage(content=memory_context))
421+
422+
elif self._context_injection_mode == ContextInjectionMode.FUNCTION_CALL:
423+
# Add as function call result messages
424+
# Generate a unique call ID
425+
call_id = f"call_{uuid.uuid4().hex[:20]}"
426+
427+
# Create the function call
428+
function_call = FunctionCall(
429+
id=call_id,
430+
name="retrieve_mem0memory",
431+
arguments="{}", # No parameters as specified
432+
)
433+
434+
# Create AssistantMessage with the function call
435+
assistant_message = AssistantMessage(
436+
content=[function_call], source="memory_system", type="AssistantMessage"
437+
)
438+
439+
# Create the function execution result
440+
function_result = FunctionExecutionResult(
441+
content=memory_context, name="retrieve_mem0memory", call_id=call_id, is_error=False
442+
)
443+
444+
# Create FunctionExecutionResultMessage
445+
result_message = FunctionExecutionResultMessage(
446+
content=[function_result], type="FunctionExecutionResultMessage"
447+
)
448+
449+
# Add both messages to the context
450+
await model_context.add_message(assistant_message)
451+
await model_context.add_message(result_message)
397452

398453
return UpdateContextResult(memories=query_results)
399454

@@ -432,6 +487,7 @@ def _from_config(cls, config: Mem0MemoryConfig) -> Self:
432487
is_cloud=config.is_cloud,
433488
api_key=config.api_key,
434489
config=config.config,
490+
context_injection_mode=config.context_injection_mode,
435491
)
436492

437493
def _to_config(self) -> Mem0MemoryConfig:
@@ -446,4 +502,5 @@ def _to_config(self) -> Mem0MemoryConfig:
446502
is_cloud=self._is_cloud,
447503
api_key=self._api_key,
448504
config=self._config,
505+
context_injection_mode=self._context_injection_mode,
449506
)

0 commit comments

Comments
 (0)