feat: introduce MemoryPromptConfig for customizable memory prompts#5330
feat: introduce MemoryPromptConfig for customizable memory prompts#5330lorenzejay wants to merge 9 commits into
Conversation
* Added MemoryPromptConfig class to allow users to override default memory prompts for various operations (save, query, extract, consolidation). * Updated relevant functions and classes to utilize the new configuration, enabling more flexible and context-specific memory handling. * Enhanced tests to validate the functionality of the new prompt configuration and its integration within the memory processing flows.
* Removed the static method for online people research and replaced it with a constructor for MemoryPromptConfig that accepts custom strings for save, extract, and query systems. * Updated the corresponding test to validate the new configuration approach, ensuring flexibility in memory prompt handling.
…emory-prompt-influence
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds ChangesMemory Prompt Customization
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
docs/en/concepts/memory.mdx (1)
160-197: ⚡ Quick winAdd
memory_promptto the Configuration Reference table as well.The new section is clear, but users scanning the parameter table may miss this constructor field. Please add a
memory_promptrow there (and mirror it in the translated memory docs updated in this PR).Suggested table row
| `query_analysis_threshold` | `200` | Queries shorter than this (in characters) skip LLM analysis during deep recall. | +| `memory_prompt` | `None` | Optional `MemoryPromptConfig` to override save/query/extract/consolidation prompt templates; unset fields use bundled defaults. |🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/en/concepts/memory.mdx` around lines 160 - 197, Add a new row for the constructor field memory_prompt in the Configuration Reference table to document Memory(memory_prompt=...) and reference MemoryPromptConfig; mention it accepts a MemoryPromptConfig (partial fields optional) and that defaults come from translations/en.json under the memory key, and mirror the identical entry in the translated memory docs updated in this PR so the parameter shows up in all locale tables.lib/crewai/tests/memory/test_unified_memory.py (1)
669-702: ⚡ Quick winConsider one end-to-end test through
Memory.remember()for prompt override wiring.This test verifies direct
analyze_for_saveusage, but the PR also changes flow-level threading. Adding oneremember()-path assertion would guard against regressions inMemoryConfig -> EncodingFlow -> analyze_for_save.Example test shape
+def test_memory_prompt_override_used_by_remember_flow(tmp_path: Path) -> None: + from crewai.memory.types import MemoryPromptConfig + from crewai.memory.unified_memory import Memory + + custom_system = "CUSTOM_SAVE_SYSTEM_OVERRIDE" + llm = MagicMock() + llm.supports_function_calling.return_value = False + llm.call.return_value = ( + '{"suggested_scope": "/", "categories": [], "importance": 0.5, ' + '"extracted_metadata": {"entities": [], "dates": [], "topics": []}}' + ) + embedder = MagicMock(return_value=[[0.1] * 1536]) + + mem = Memory( + storage=str(tmp_path / "ov_db_e2e"), + llm=llm, + embedder=embedder, + memory_prompt=MemoryPromptConfig(save_system=custom_system), + ) + mem.remember("hello world") + messages = llm.call.call_args.args[0] + assert messages[0]["role"] == "system" + assert messages[0]["content"] == custom_system🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai/tests/memory/test_unified_memory.py` around lines 669 - 702, Add an end-to-end test that exercises the Memory.remember path (e.g., call Memory.remember with content and relevant args) instead of directly invoking analyze_for_save so the full flow from MemoryConfig -> EncodingFlow -> analyze_for_save is exercised; set up the same MagicMock llm and MemoryPromptConfig(save_system=custom_system) on a Memory instance, call mem.remember(...) with matching inputs (existing_scopes, categories, etc.), then inspect llm.call.call_args to assert the first message role is "system" and its content equals custom_system to ensure the override wiring is preserved through Memory.remember.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/crewai/src/crewai/memory/analyze.py`:
- Around line 178-180: The template strings returned by
_memory_prompt_line(memory_prompt, "...") are being .format(...) before entering
the guarded try blocks, so any bad placeholder will raise and bypass fallbacks;
move the .format call into the corresponding try/except (or replace with a
safe_render helper that catches KeyError/ValueError/IndexError and returns a
fallback) for each occurrence (the calls that produce user/assistant prompt
lines via _memory_prompt_line with keys like "extract_memories_user",
"extract_memories_assistant", etc.), i.e., change user =
_memory_prompt_line(...).format(content=...) to first get the template =
_memory_prompt_line(...), then inside the try do formatted =
safe_render(template, content=content) (or try: formatted = template.format(...)
except Exception: formatted = template or fallback) and use formatted downstream
so runtime formatting errors do not skip the existing fallback behavior.
---
Nitpick comments:
In `@docs/en/concepts/memory.mdx`:
- Around line 160-197: Add a new row for the constructor field memory_prompt in
the Configuration Reference table to document Memory(memory_prompt=...) and
reference MemoryPromptConfig; mention it accepts a MemoryPromptConfig (partial
fields optional) and that defaults come from translations/en.json under the
memory key, and mirror the identical entry in the translated memory docs updated
in this PR so the parameter shows up in all locale tables.
In `@lib/crewai/tests/memory/test_unified_memory.py`:
- Around line 669-702: Add an end-to-end test that exercises the Memory.remember
path (e.g., call Memory.remember with content and relevant args) instead of
directly invoking analyze_for_save so the full flow from MemoryConfig ->
EncodingFlow -> analyze_for_save is exercised; set up the same MagicMock llm and
MemoryPromptConfig(save_system=custom_system) on a Memory instance, call
mem.remember(...) with matching inputs (existing_scopes, categories, etc.), then
inspect llm.call.call_args to assert the first message role is "system" and its
content equals custom_system to ensure the override wiring is preserved through
Memory.remember.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 84c29117-b4ab-4baa-900d-426f7cc6cd1d
📒 Files selected for processing (14)
docs/ar/concepts/memory.mdxdocs/en/concepts/memory.mdxdocs/ko/concepts/memory.mdxdocs/pt-BR/concepts/memory.mdxlib/crewai/src/crewai/__init__.pylib/crewai/src/crewai/memory/analyze.pylib/crewai/src/crewai/memory/encoding_flow.pylib/crewai/src/crewai/memory/recall_flow.pylib/crewai/src/crewai/memory/types.pylib/crewai/src/crewai/memory/unified_memory.pylib/crewai/src/crewai/telemetry/telemetry.pylib/crewai/src/crewai/telemetry/utils.pylib/crewai/tests/memory/test_unified_memory.pylib/crewai/tests/telemetry/test_telemetry.py
| user = _memory_prompt_line(memory_prompt, "extract_memories_user").format( | ||
| content=content | ||
| ) |
There was a problem hiding this comment.
Uncaught template-format errors can break memory flows.
On Line 178, Line 234, Line 304, and Line 370, custom prompt templates are formatted before the guarded try blocks. A bad placeholder (e.g. {foo}) will raise and skip fallback behavior, causing runtime failures in remember/recall/extract paths.
Proposed fix (centralized safe rendering + fallback)
def _memory_prompt_line(
memory_prompt: MemoryPromptConfig | None,
key: str,
) -> str:
"""Resolve one memory prompt: override string or bundled translation."""
if memory_prompt is not None:
raw = getattr(memory_prompt, key, None)
if isinstance(raw, str) and raw.strip():
return raw
return I18N_DEFAULT.memory(key)
+
+
+def _render_memory_prompt(
+ memory_prompt: MemoryPromptConfig | None,
+ key: str,
+ **kwargs: Any,
+) -> str:
+ template = _memory_prompt_line(memory_prompt, key)
+ try:
+ return template.format(**kwargs) if kwargs else template
+ except Exception as e:
+ _logger.warning(
+ "Invalid memory prompt template for '%s'; using default: %s",
+ key,
+ e,
+ exc_info=False,
+ )
+ fallback = I18N_DEFAULT.memory(key)
+ return fallback.format(**kwargs) if kwargs else fallback- user = _memory_prompt_line(memory_prompt, "extract_memories_user").format(
- content=content
- )
+ user = _render_memory_prompt(
+ memory_prompt, "extract_memories_user", content=content
+ )- user = _memory_prompt_line(memory_prompt, "query_user").format(
+ user = _render_memory_prompt(
+ memory_prompt,
+ "query_user",
query=query,
available_scopes=available_scopes or ["/"],
scope_desc=scope_desc,
)- user = _memory_prompt_line(memory_prompt, "save_user").format(
+ user = _render_memory_prompt(
+ memory_prompt,
+ "save_user",
content=content,
existing_scopes=existing_scopes or ["/"],
existing_categories=existing_categories or [],
)- user = _memory_prompt_line(memory_prompt, "consolidation_user").format(
+ user = _render_memory_prompt(
+ memory_prompt,
+ "consolidation_user",
new_content=new_content,
records_summary="\n\n".join(records_lines),
)Also applies to: 234-238, 304-308, 370-373
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/crewai/src/crewai/memory/analyze.py` around lines 178 - 180, The template
strings returned by _memory_prompt_line(memory_prompt, "...") are being
.format(...) before entering the guarded try blocks, so any bad placeholder will
raise and bypass fallbacks; move the .format call into the corresponding
try/except (or replace with a safe_render helper that catches
KeyError/ValueError/IndexError and returns a fallback) for each occurrence (the
calls that produce user/assistant prompt lines via _memory_prompt_line with keys
like "extract_memories_user", "extract_memories_assistant", etc.), i.e., change
user = _memory_prompt_line(...).format(content=...) to first get the template =
_memory_prompt_line(...), then inside the try do formatted =
safe_render(template, content=content) (or try: formatted = template.format(...)
except Exception: formatted = template or fallback) and use formatted downstream
so runtime formatting errors do not skip the existing fallback behavior.
Note
Medium Risk
Adds a new public config surface that changes how memory save/recall/extraction/consolidation prompts are generated and threaded through the encoding/recall flows; mistakes in custom templates (missing
str.formatplaceholders) can cause runtime failures.Overview
Adds
MemoryPromptConfigto let callers override the LLM prompt strings used in memory analysis (save, query analysis, memory extraction, and consolidation), while falling back to the bundled i18n defaults for unset fields.Threads
memory_promptthroughMemory,MemoryConfig, and thecrewai.memory.analyzehelpers, updatingEncodingFlow/RecallFlowto pass the config into each LLM call, and exposesMemoryPromptConfigviacrewai.__init__.Updates telemetry to serialize
Crew.memoryinto OTLP-safe primitives, adds tests for both prompt overrides and telemetry serialization, and documents the new prompt customization (EN/AR/KO/PT-BR).Reviewed by Cursor Bugbot for commit 48fcf92. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Documentation
Tests