-
Notifications
You must be signed in to change notification settings - Fork 46
ai-response-according-to-user-preference #316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release
Are you sure you want to change the base?
ai-response-according-to-user-preference #316
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe PR makes system-prompt personalization asynchronous, adds a mem0-backed personalized prompt creator that can use user_email to fetch memory context, updates call sites to await the new async APIs, and adds a mem0 memory retrieval method with circuit-breaker and fallback handling. Changes
Sequence DiagramsequenceDiagram
participant Agent as run_normal_mode
participant PromptFn as get_system_prompt
participant Personalize as create_personalized_prompt
participant Mem0 as Mem0Service
participant Fallback as append_user_info
Agent->>+PromptFn: await get_system_prompt(user_name, tts_provider, shop_id, user_email)
PromptFn->>+Personalize: await create_personalized_prompt(user_name, user_email)
alt MEM0 enabled & keys present
Personalize->>+Mem0: get_all_user_context(user_email)
alt success
Mem0-->>Personalize: {context, memory_count}
Note right of Personalize: build personalization using memory
else failure
Mem0-->>Personalize: error
Personalize->>Fallback: append_user_info(user_name)
end
else mem0 disabled or no keys
Personalize->>Fallback: append_user_info(user_name)
end
Fallback-->>Personalize: personalized_text
Personalize-->>-PromptFn: personalized_prompt
PromptFn-->>-Agent: final_system_prompt
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
d3b8f44 to
c92a69b
Compare
There was a problem hiding this comment.
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 (4)
app/agents/voice/automatic/prompts/system/personalization.py (3)
1-1: Use explicit type annotation for optional parameter.Following PEP 484, use
str | Noneinstead of implicitOptional.Apply this diff:
-def append_user_info(user_name: str, user_context: str = None) -> str: +def append_user_info(user_name: str, user_context: str | None = None) -> str:
71-71: Use explicit type annotation for optional parameter.Following PEP 484, use
str | Noneinstead of implicitOptional.Apply this diff:
-async def create_personalized_prompt(user_name: str, user_email: str = None) -> str: +async def create_personalized_prompt(user_name: str, user_email: str | None = None) -> str:
85-89: Move imports to module level Inline import of ImprovedMem0MemoryService is no longer needed—no circular dependency detected. Move the imports forImprovedMem0MemoryServiceandconfigto the top ofapp/agents/voice/automatic/prompts/system/personalization.pyand remove the workaround comment.app/agents/voice/automatic/services/mem0/memory.py (1)
150-151: Use explicit type annotation for optional parameter.Following PEP 484, use
str | Noneinstead of implicitOptional.Apply this diff:
- async def get_all_user_context( - self, user_id: Optional[str] = None - ) -> Dict[str, Any]: + async def get_all_user_context( + self, user_id: str | None = None + ) -> Dict[str, Any]:
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/agents/voice/automatic/__init__.py(1 hunks)app/agents/voice/automatic/prompts/__init__.py(3 hunks)app/agents/voice/automatic/prompts/system/personalization.py(2 hunks)app/agents/voice/automatic/services/mem0/memory.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/agents/voice/automatic/prompts/system/personalization.py (1)
app/agents/voice/automatic/services/mem0/memory.py (2)
ImprovedMem0MemoryService(28-587)get_all_user_context(150-205)
app/agents/voice/automatic/__init__.py (1)
app/agents/voice/automatic/prompts/__init__.py (1)
get_system_prompt(28-66)
app/agents/voice/automatic/prompts/__init__.py (2)
app/agents/voice/automatic/prompts/system/personalization.py (1)
create_personalized_prompt(71-124)app/agents/voice/automatic/types/models.py (1)
TTSProvider(8-10)
🪛 Ruff (0.14.0)
app/agents/voice/automatic/prompts/system/personalization.py
1-1: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
71-71: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
120-120: Do not catch blind exception: Exception
(BLE001)
app/agents/voice/automatic/services/mem0/memory.py
197-197: Do not catch blind exception: Exception
(BLE001)
202-202: Use explicit conversion flag
Replace with conversion flag
(RUF010)
🔇 Additional comments (8)
app/agents/voice/automatic/__init__.py (1)
283-286: LGTM! Correct async integration.The async call to
get_system_promptis properly awaited and passes all required parameters includinguser_emailfor memory-based personalization.app/agents/voice/automatic/services/mem0/memory.py (3)
156-164: LGTM! Proper validation and circuit breaker integration.The validation logic correctly checks for user_id presence and respects the circuit breaker state before attempting memory operations, ensuring graceful degradation when the service is unavailable.
168-186: LGTM! Robust memory extraction with defensive fallbacks.The memory extraction logic properly handles multiple field names (
memory,text,content) and validates each item, ensuring resilient operation even with varying response formats. The bullet-point formatting provides clear, readable context for LLM personalization.
197-205: Broad exception handling is acceptable for fallback behavior.While catching
Exceptionis flagged by static analysis, this is appropriate here as it ensures the system continues with degraded functionality rather than failing completely. The error is logged and tracked by the circuit breaker.app/agents/voice/automatic/prompts/__init__.py (3)
8-10: LGTM! Correct import update.The import correctly switches from
append_user_infotocreate_personalized_promptto support memory-based personalization.
28-37: LGTM! Proper async signature and documentation.The function signature is correctly updated to async with the new
user_emailparameter, and the docstring clearly documents the memory service integration.
63-64: LGTM! Correct async integration.The call to
create_personalized_promptis properly awaited and passes bothuser_nameanduser_emailfor memory-based context retrieval.app/agents/voice/automatic/prompts/system/personalization.py (1)
39-39: Fix typo in comment."troubleshooting" is misspelled as "troubleshooting".
Apply this diff:
- - Reference prior successful resolutions or troubleshooting steps they responded well to. + - Reference prior successful resolutions or troubleshooting steps they responded well to.Likely an incorrect or invalid review comment.
| except Exception as e: | ||
| print(f"Error retrieving user context: {e}") | ||
| return append_user_info(user_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Replace print() with logger for consistent error handling.
The codebase uses logger throughout for error messages. Using print() here is inconsistent and may not be captured in logs.
Apply this diff:
- except Exception as e:
- print(f"Error retrieving user context: {e}")
- return append_user_info(user_name)
+ except Exception as e:
+ logger.error(f"Error retrieving user context: {e}")
+ return append_user_info(user_name)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| except Exception as e: | |
| print(f"Error retrieving user context: {e}") | |
| return append_user_info(user_name) | |
| except Exception as e: | |
| logger.error(f"Error retrieving user context: {e}") | |
| return append_user_info(user_name) |
🧰 Tools
🪛 Ruff (0.14.0)
120-120: Do not catch blind exception: Exception
(BLE001)
🤖 Prompt for AI Agents
In app/agents/voice/automatic/prompts/system/personalization.py around lines
120-122, replace the print() call used in the exception handler with the module
logger: call logger.exception(...) or logger.error(..., exc_info=True) to record
the error consistently and include stacktrace; ensure the logger is
imported/available in this module and return append_user_info(user_name)
afterwards as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the current state of the file and verify logger import
cat app/agents/voice/automatic/prompts/system/personalization.py | head -20
Length of output: 1119
🏁 Script executed:
#!/bin/bash
# Check the specific exception handler section
cat app/agents/voice/automatic/prompts/system/personalization.py | grep -A 3 "except Exception as e:"
Length of output: 151
🏁 Script executed:
#!/bin/bash
# Check for logger import in the entire file
grep -n "import.*logger\|from.*logger" app/agents/voice/automatic/prompts/system/personalization.py
Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check the complete imports section at the top of the file
head -5 app/agents/voice/automatic/prompts/system/personalization.py
Length of output: 157
🏁 Script executed:
#!/bin/bash
# Check how logger is imported in similar files in the prompts module
fd -e py . app/agents/voice/automatic/prompts/ --exec head -10 {} \; | grep -A 2 -B 2 "logger"
Length of output: 0
🏁 Script executed:
#!/bin/bash
# Check the parent __init__.py file for logger import pattern
head -20 app/agents/voice/automatic/prompts/__init__.py | grep -A 1 -B 1 "import"
Length of output: 819
🏁 Script executed:
#!/bin/bash
# Search for logger import patterns across the codebase
rg -n "^from.*import.*logger|^import.*logger" app/agents/voice/automatic/ -A 1 | head -20
Length of output: 1057
🏁 Script executed:
#!/bin:bash
# Check a specific service file to see logger import pattern
head -30 app/agents/voice/automatic/services/mem0/memory.py | grep -A 1 -B 1 "logger"
Length of output: 268
@sharifajahanshaik, great work updating the print() to logger.error()! However, I noticed the logger import is missing from the file, which will cause a NameError at runtime when an exception occurs.
You need to add this import at the top of the file:
from app.core.logger import loggerThe file currently starts directly with the function definition. After adding the import, the beginning of the file should look like:
from app.core.logger import logger
def append_user_info(user_name: str, user_context: str = None) -> str:
"""
Appends user personalization instructions to the system prompt.
...This import pattern is consistent with how logger is used throughout the codebase (e.g., in app/agents/voice/automatic/services/mem0/memory.py and other files).
🧬 Code Graph Analysis Results
[filename: app/agents/voice/automatic/prompts/system/personalization.py, lines: 1-60]
def append_user_info(user_name: str, user_context: str = None) -> str:
"""
Appends user personalization instructions to the system prompt.
Args:
user_name: The user's name for personalization
user_context: Optional memory-based context about the user's preferences and history
"""
base_instructions = f"""
USER PERSONALIZATION
The user's name is {user_name}. Use it only when it adds genuine value to the conversation.
Include the name:
- At the **start of the very first message** in a session (e.g., “Hey {user_name}, whatsup? How can I help you today?”)
- In **emotionally significant moments**, such as celebrating a win, expressing empathy, or addressing a concern directly.
Avoid using the name in closing lines, suggestions, or tool-generated follow-ups unless absolutely necessary. Never repeat the name within the same message. Prioritize a warm, natural tone — use the name only when it feels truly warranted in spoken conversation.
GREETING GUIDELINES:
- Keep initial greetings simple and natural
- Don't overwhelm users with multiple options or questions at the start
"""
# Add general personalization instructions regardless of whether we have specific user context
personalization_instructions = """
PERSONALIZATION INSTRUCTIONS:
This conversation may include user context from previous interactions. When available, you MUST:
1. TOOL PARAMETER PERSONALIZATION
- When filling or suggesting tool parameters, prioritize previously used or preferred values.
- If the user has configured or used specific settings before, default to those unless they explicitly override them.
- Maintain consistency with the user's preferred formats, units, or naming conventions (e.g., currency, date format, region).
- Reference successful tool usage patterns from their history when proposing configurations.
- When no relevant memory is found, use safe, explainable defaults and clearly state that these can be customized.
2. SOLUTION PRIORITIZATION
- When multiple valid solutions exist, prioritize approaches that worked for this user in the past.
- Reference prior successful resolutions or troubleshooting steps they responded well to.
- Avoid methods the user has previously rejected, struggled with, or shown disinterest in.
- Build upon their existing knowledge level — neither over-explain nor skip crucial context.
- When introducing new concepts, connect them to something familiar from their past interactions.
3. PROACTIVE & CONTEXT-AWARE ASSISTANCE
- Anticipate next steps based on user patterns — e.g., follow-up actions they usually take.
- Address likely concerns early, before the user asks (e.g., known blockers, compatibility issues).
- Recommend optimizations or shortcuts that align with their prior workflow.
- Warn about issues they've encountered before or suggest preventive checks.
- When appropriate, remind the user why a suggestion matches their past behavior ("Since you usually prefer X, I've set Y accordingly.")
4. TOOL USAGE GUIDANCE
- Always check the conversation context and memory data before applying defaults.
- Respect the user's configuration history, even across sessions or devices.
- Keep data format consistency (JSON vs YAML, metric vs imperial, etc.) unless instructed otherwise.
- Adapt your explanations and verbosity to their known preference — concise vs detailed.
- Clearly log or communicate assumptions when inferring parameters from memory.
"""
if user_context:
memory_section = f"""
CURRENT USER CONTEXT:
{user_context}
"""
return base_instructions + memory_section + personalization_instructions
return base_instructions
[filename: app/agents/voice/automatic/prompts/system/personalization.py, lines: 61-200]
async def create_personalized_prompt(user_name: str, user_email: str = None) -> str:
"""
Create a comprehensive personalized prompt by retrieving user context from memory.
This function checks mem0 configuration internally and creates its own memory service
to retrieve user context if available.
Args:
user_name: The user's name
user_email: User's email for memory service (optional)
Returns:
Complete personalized prompt string with user context
"""
# Import here to avoid circular imports
from app.agents.voice.automatic.services.mem0.memory import (
ImprovedMem0MemoryService,
)
from app.core import config
# Check if mem0 is enabled and configured
if (
config.MEM0_ENABLED
and user_email
and user_email.strip()
and config.MEM0_API_KEY
and config.MEM0_API_KEY.strip()
):
try:
# Create memory service instance internally
memory_params = ImprovedMem0MemoryService.InputParams()
memory_service = ImprovedMem0MemoryService(
api_key=config.MEM0_API_KEY,
user_id=user_email,
params=memory_params,
)
user_context_data = await memory_service.get_all_user_context()
if user_context_data.get("error"):
return append_user_info(user_name)
user_context = user_context_data.get("context", "")
if user_context:
return append_user_info(user_name, user_context)
else:
return append_user_info(user_name)
except Exception as e:
logger.error(f"Error retrieving user context: {e}")
return append_user_info(user_name)
else:
return append_user_info(user_name)
[filename: app/agents/voice/automatic/prompts/system/personalization.py, lines: 150-205]
async def get_all_user_context(
self, user_id: Optional[str] = None
) -> Dict[str, Any]:
"""
Retrieve all user context from mem0 for LLM personalization.
"""
target_user_id = user_id or getattr(self, "user_id", None)
if not target_user_id:
return {"error": "No user ID available", "context": ""}
# Check circuit breaker
if not self._check_memory_health():
logger.info("User context retrieval skipped - circuit breaker OPEN")
return {"error": "Memory service unavailable", "context": ""}
try:
# Get ALL memories for the user
memories_result = self.memory_client.get_all(user_id=target_user_id)
# Extract memory text
memories = []
if isinstance(memories_result, list):
for item in memories_result:
if isinstance(item, dict):
memory_text = (
item.get("memory")
or item.get("text")
or item.get("content")
or str(item)
)
if memory_text and memory_text.strip():
memories.append(memory_text.strip())
formatted_context = (
"\n".join(f"- {memory}" for memory in memories) if memories else ""
)
# Handle successful retrieval
self._handle_memory_success("context_retrieval")
return {
"user_id": target_user_id,
"context": formatted_context,
"memory_count": len(memories),
}
except Exception as e:
# Handle memory failure
self._handle_memory_failure("context_retrieval", e)
return {
"error": f"Context retrieval failed: {str(e)}",
"context": "",
"user_id": target_user_id,
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import added check once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the current state of the personalization.py file, focusing on imports and the exception handler
echo "=== Checking logger import at the top of the file ==="
head -10 app/agents/voice/automatic/prompts/system/personalization.py
echo -e "\n=== Checking the exception handler section ==="
grep -A 2 "except Exception as e:" app/agents/voice/automatic/prompts/system/personalization.py
Length of output: 586
@sharifajahanshaik, perfect! ✅ I've verified the changes and everything looks great:
- ✅ The logger import is correctly added at the top:
from app.core.logger import logger - ✅ The exception handler properly uses:
logger.error(f"Error retrieving user context: {e}")
The code now follows the codebase's logging conventions and will properly capture errors in the logs when memory retrieval fails. Great work! 🎉
/\_/\
( o.o )
> ^ <
/| |\
(_| |_)
Pawsome!
🧬 Code Graph Analysis Results
[app/agents/voice/automatic/services/mem0/memory.py, 28-587]
Docstring-style summary:
-
Class: ImprovedMem0MemoryService
- Purpose: Enhanced Mem0MemoryService with reliability/performance improvements.
- Key features:
- Incremental message tracking to reduce API calls
- Circuit breaker pattern for fault tolerance
- Async/non-blocking storage
- Comprehensive error handling and logging
- Session management and automatic recovery
- Environment-variable-driven configuration (MEM0_MAX_FAILURES, MEM0_RETRY_INTERVAL, MEM0_SESSION_TIMEOUT, MEM0_MIN_MESSAGE_LENGTH)
- Primary usage pattern:
- Construct with optional keyword args (e.g., max_failures, retry_interval, session_timeout, min_message_length)
- get_all_user_context(user_id=None) -> dict
- Retrieves all user memories for personalization
- Respects circuit-breaker state; returns error context if unavailable
- Normal return shape: {
"user_id": ,
"context": "<formatted memories or ''>",
"memory_count":
} - On exception: logs error, updates circuit-breaker state, and returns an error context
- Method: get_all_user_context
- Parameters: user_id (Optional[str])
- Returns: Dict[str, Any] containing user_id, context, memory_count or an error key
- Exceptions: Catches exceptions; updates circuit breaker via _handle_memory_failure; returns error object
- Important implementation notes:
- Memory retrieval proceeds only if circuit breaker allows (_check_memory_health)
- Memory entries are normalized from various possible shapes (memory/text/content, or stringified object)
- Successful retrieval triggers _handle_memory_success to reset failure counter
- On failure, _handle_memory_failure is invoked and an error response is returned
-
Method: get_all_user_context (detailed behavior)
- Signature: async def get_all_user_context(self, user_id: Optional[str] = None) -> Dict[str, Any]
- Behavior:
- Determines target_user_id from parameter or self.user_id
- If no user_id: return {"error": "No user ID available", "context": ""}
- If circuit breaker open: return {"error": "Memory service unavailable", "context": ""}
- Attempts to fetch memories via self.memory_client.get_all(user_id=target_user_id)
- Normalizes memories into a list of strings; builds formatted_context as a bullet list
- On success: returns {"user_id": target_user_id, "context": formatted_context, "memory_count": len(memories)}
- On failure: logs, updates circuit-breaker via _handle_memory_failure("context_retrieval", e), and returns an error response:
{"error": f"Context retrieval failed: {str(e)}", "context": "", "user_id": target_user_id}
- Exceptions: Any encountered exception leads to circuit-breaker handling and error return
Reason this is relevant:
- The file personalization.py conditionally imports ImprovedMem0MemoryService and uses MEM0_ENABLED, MEM0_API_KEY, MEM0_API_KEY, MEM0 memory service, and get_all_user_context() to assemble a user_context. Understanding the memory service’s behavior, circuit-breaker logic, and how get_all_user_context returns data is essential to implementing or debugging the “Import added check once” scenario described in the user comment.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
3e612df to
734c8bf
Compare
| @@ -1,8 +1,15 @@ | |||
| def append_user_info(user_name: str) -> str: | |||
| from app.core.logger import logger | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation is off.
Follow below steps:
- Check lang-fuse currently and see how Mem0 Adds past memory to the current conversation dynamically
- There should be minimal changes in Core system prompt, and most details should come from Mem0 dynamically and they should be added, while maintaing the same functionality and naturalness.
734c8bf to
335707d
Compare
335707d to
73c428e
Compare
Dev Proof:
Before

After

Summary by CodeRabbit