Skip to content

feat: introduce MemoryPromptConfig for customizable memory prompts#5330

Open
lorenzejay wants to merge 9 commits into
mainfrom
lorenze/imp/memory-prompt-influence
Open

feat: introduce MemoryPromptConfig for customizable memory prompts#5330
lorenzejay wants to merge 9 commits into
mainfrom
lorenze/imp/memory-prompt-influence

Conversation

@lorenzejay

@lorenzejay lorenzejay commented Apr 8, 2026

Copy link
Copy Markdown
Collaborator
  • 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.

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.format placeholders) can cause runtime failures.

Overview
Adds MemoryPromptConfig to 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_prompt through Memory, MemoryConfig, and the crewai.memory.analyze helpers, updating EncodingFlow/RecallFlow to pass the config into each LLM call, and exposes MemoryPromptConfig via crewai.__init__.

Updates telemetry to serialize Crew.memory into 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

    • Introduced MemoryPromptConfig and memory_prompt support so memory operations can use custom LLM instruction templates and per-call overrides
    • MemoryPromptConfig is available as a top-level exported symbol for easy import
  • Documentation

    • Added multi-language guides showing how to configure prompt overrides and required template placeholders
  • Tests

    • Added tests validating custom prompt behavior and telemetry helper output

Review Change Stack

* 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.
@github-actions github-actions Bot added the size/L label Apr 8, 2026
Comment thread lib/crewai/src/crewai/__init__.py Fixed
* 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.
@github-actions github-actions Bot added the size/M label Apr 8, 2026
@github-actions github-actions Bot removed the size/L label Apr 16, 2026
Comment thread lib/crewai/src/crewai/__init__.py Dismissed
@github-actions github-actions Bot added size/L and removed size/M labels Apr 22, 2026
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d1322777-266d-4be4-860b-9a41bf363453

📥 Commits

Reviewing files that changed from the base of the PR and between 743703a and 48fcf92.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/__init__.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/src/crewai/init.py

📝 Walkthrough

Walkthrough

This PR adds MemoryPromptConfig to enable per-step LLM instruction customization during memory save, query analysis, extraction, and consolidation. Users can pass a MemoryPromptConfig to the Memory constructor or directly to analysis helper functions, with unspecified fields falling back to bundled defaults. Documentation, telemetry support, and tests are included.

Changes

Memory Prompt Customization

Layer / File(s) Summary
Type System & Schema
lib/crewai/src/crewai/memory/types.py
Introduces MemoryPromptConfig with optional system/user prompt fields for save, query, extract, and consolidation steps; adds ConfigDict import for strict model config. MemoryConfig extended with memory_prompt: MemoryPromptConfig | None.
Public API Export
lib/crewai/src/crewai/__init__.py
MemoryPromptConfig added to _LAZY_IMPORTS and __all__ for public package-level access.
Core Analysis Helpers
lib/crewai/src/crewai/memory/analyze.py
New _memory_prompt_line() helper resolves prompts from MemoryPromptConfig with fallback to i18n defaults. Function signatures updated: extract_memories_from_content(), analyze_query(), analyze_for_save(), analyze_for_consolidation() all now accept optional memory_prompt parameter and use dynamic prompt resolution.
Memory Class Interface
lib/crewai/src/crewai/memory/unified_memory.py
Adds memory_prompt field to Memory; docstring and import refactoring. model_post_init() propagates memory_prompt to internal MemoryConfig. extract_memories() helper passes configured overrides to extract_memories_from_content().
Flow Integration
lib/crewai/src/crewai/memory/encoding_flow.py, lib/crewai/src/crewai/memory/recall_flow.py
EncodingFlow.parallel_analyze() and RecallFlow.analyze_query_step() pass self._config.memory_prompt into respective analysis helper calls.
Telemetry Support
lib/crewai/src/crewai/telemetry/telemetry.py, lib/crewai/src/crewai/telemetry/utils.py
New crew_memory_span_attribute_value() helper serializes memory objects to OTLP-compatible span values. Telemetry crew-creation span uses this helper to record crew_memory.
Documentation
docs/ar/concepts/memory.mdx, docs/en/concepts/memory.mdx, docs/ko/concepts/memory.mdx, docs/pt-BR/concepts/memory.mdx
Four-language documentation covering MemoryPromptConfig usage with Memory, usage in crewai.memory.analyze helpers, tables mapping prompt fields to pipeline effects, and placeholder formatting rules.
Tests
lib/crewai/tests/memory/test_unified_memory.py, lib/crewai/tests/telemetry/test_telemetry.py
New tests verify MemoryPromptConfig field preservation and custom save_system propagation through analyze_for_save. Telemetry tests validate crew_memory_span_attribute_value() for primitive and Memory object inputs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 A rabbit hops through memory's hall,
Tucks prompts in pockets, big and small—
Save, query, extract, consolidate bright,
PromptConfig tunes each LLM's light. 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: introduce MemoryPromptConfig for customizable memory prompts' accurately and clearly describes the primary change—adding a new MemoryPromptConfig feature that enables users to customize memory prompts.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lorenze/imp/memory-prompt-influence

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/en/concepts/memory.mdx (1)

160-197: ⚡ Quick win

Add memory_prompt to 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_prompt row 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 win

Consider one end-to-end test through Memory.remember() for prompt override wiring.

This test verifies direct analyze_for_save usage, but the PR also changes flow-level threading. Adding one remember()-path assertion would guard against regressions in MemoryConfig -> 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

📥 Commits

Reviewing files that changed from the base of the PR and between 63a9e7e and 743703a.

📒 Files selected for processing (14)
  • docs/ar/concepts/memory.mdx
  • docs/en/concepts/memory.mdx
  • docs/ko/concepts/memory.mdx
  • docs/pt-BR/concepts/memory.mdx
  • lib/crewai/src/crewai/__init__.py
  • lib/crewai/src/crewai/memory/analyze.py
  • lib/crewai/src/crewai/memory/encoding_flow.py
  • lib/crewai/src/crewai/memory/recall_flow.py
  • lib/crewai/src/crewai/memory/types.py
  • lib/crewai/src/crewai/memory/unified_memory.py
  • lib/crewai/src/crewai/telemetry/telemetry.py
  • lib/crewai/src/crewai/telemetry/utils.py
  • lib/crewai/tests/memory/test_unified_memory.py
  • lib/crewai/tests/telemetry/test_telemetry.py

Comment on lines +178 to +180
user = _memory_prompt_line(memory_prompt, "extract_memories_user").format(
content=content
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants