Skip to content

Conversation

@smokeyScraper
Copy link
Contributor

@smokeyScraper smokeyScraper commented Jun 12, 2025

Refers to a few issues of #70

Attached Interactions

Screenshot 2025-06-12 215959

Screenshot 2025-06-12 220022

Screenshot 2025-06-12 220048

Screenshot 2025-06-12 220102

Screenshot 2025-06-12 220121

Screenshot 2025-06-12 220134

Summary by CodeRabbit

  • New Features

    • Introduced conversation summarization and memory management for improved long-term context and session handling.
    • Added the ability to reset both chat threads and conversation memory directly from the Discord bot.
    • Enhanced prompts for clearer, more personalized, and context-rich responses.
  • Improvements

    • Responses now reference both recent conversation and long-term summaries for greater continuity.
    • Enhanced onboarding, FAQ, technical support, and web search experiences with more structured outputs.
    • User profiles and key topics are now tracked for more tailored assistance.
    • Added detailed session and interaction tracking to improve memory persistence and timeout handling.
    • Enabled state recovery and persistence keyed by conversation threads for seamless user experience.
    • Updated prompt structure to better separate conversation summary, recent messages, and user context.
    • Improved logging and diagnostics for conversation state and memory management.
  • Bug Fixes

    • Improved error handling and session recovery to ensure smoother user interactions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 12, 2025

Walkthrough

This update introduces comprehensive conversation summarization and memory management to the DevRel agent system. It adds summarization nodes, state persistence keyed by thread ID, and memory clearing logic. Node return values are standardized to dictionaries, and the agent state model is extended for session tracking. Discord integration now supports explicit memory resets.

Changes

File(s) Change Summary
backend/app/agents/devrel/agent.py Enhanced DevRelAgent with summarization, memory management, in-memory checkpointing, and new methods for summarization and memory.
backend/app/agents/devrel/nodes/gather_context_node.py Refactored to return a new dictionary with message, context, and task info; added timestamping.
backend/app/agents/devrel/nodes/generate_response_node.py Improved LLM response formatting, summary fallback, changed to return dict, added logging.
backend/app/agents/devrel/nodes/handle_faq_node.py,
.../handle_web_search_node.py,
.../handle_onboarding_node.py,
.../handle_technical_support_node.py
All refactored to return plain dictionaries instead of mutating AgentState objects.
backend/app/agents/devrel/nodes/summarization_node.py New module: async summarization logic, key topic extraction, and summary persistence stubs.
backend/app/agents/devrel/prompts/base_prompt.py Reworked prompt template for clearer, segmented context and instructions.
backend/app/agents/devrel/prompts/summarization_prompt.py Added new summarization prompt template for conversation summaries.
backend/app/agents/shared/base_agent.py Added thread_id-based state persistence and recovery for run and stream_run methods, with enhanced logging.
backend/app/agents/shared/state.py Extended AgentState with session, summary, topics, and custom merge logic for new fields.
backend/app/core/orchestration/agent_coordinator.py Added memory clearing handler, integrated memory management into DevRel request handling.
backend/bots/discord/discord_bot.py Linked memory to user ID, enabled manual memory reset, updated help text and user feedback.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DiscordBot
    participant AgentCoordinator
    participant DevRelAgent
    participant InMemorySaver
    participant LLM

    User->>DiscordBot: Sends message or !reset
    DiscordBot->>AgentCoordinator: Sends devrel request (with memory_thread_id) or clear_thread_memory
    AgentCoordinator->>DevRelAgent: run(initial_state, thread_id)
    DevRelAgent->>InMemorySaver: Retrieve or save state by thread_id
    DevRelAgent->>LLM: Generate response / Summarize conversation (if needed)
    DevRelAgent-->>AgentCoordinator: Returns updated state
    AgentCoordinator->>InMemorySaver: Clear memory if timeout or manual reset
    AgentCoordinator->>DiscordBot: Returns response
    DiscordBot->>User: Sends final response or reset confirmation
Loading

Possibly related PRs

  • AOSSIE-Org/Devr.AI#69: Introduces the initial DevRelAgent class and workflow, which this PR extends with summarization and memory features.

Suggested labels

enhancement

Poem

In the warren of memory, threads intertwine,
Now a bunny can summarize and keep things in line.
With prompts reimagined and context so neat,
Conversations remembered, no detail to delete.
Reset with a hop, clear with a dash—
This rabbit’s new memory is truly top-class!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@smokeyScraper smokeyScraper self-assigned this Jun 12, 2025
@gemini-code-assist
Copy link

Warning

Gemini encountered an error creating the summary. You can try again by commenting /gemini summary.

@smokeyScraper
Copy link
Contributor Author

/gemini summary

@gemini-code-assist
Copy link

Summary of Changes

This pull request significantly enhances the DevRel agent's ability to maintain context across multiple interactions by introducing state persistence using LangGraph's InMemorySaver and implementing a conversation summarization mechanism. The agent now periodically summarizes long conversations and includes this summary in the LLM prompt, allowing for more coherent and context-aware responses over time. It also adds functionality to manage and clear this persistent memory.

Highlights

  • State Persistence: Introduced InMemorySaver from langgraph.checkpoint.memory to persist agent state across interactions for a given thread/user.
  • Conversation Summarization: Added a new summarization node (summarization_node.py) and logic to periodically summarize the conversation history using an LLM. This summary is stored in the agent state.
  • Summarization Trigger: Implemented logic (check_summarization_needed) to trigger summarization based on interaction count (threshold of 5) or a session timeout (1 hour).
  • Context Handling in Prompts: Updated the main LLM response prompt (GENERAL_LLM_RESPONSE_PROMPT) to include the conversation summary and recent messages, providing better long-term and short-term context to the LLM.
  • Agent State Updates: Refactored agent nodes to return dictionaries of state updates instead of modifying the state object directly, aligning with LangGraph's recommended state management pattern. The AgentState model was updated with new fields and reducers (Annotated, add, custom replace_summary, replace_topics) to handle these updates correctly.
  • Memory Management & Reset: Added methods to the DevRel agent (get_thread_state, clear_thread_memory) and integrated them into the AgentCoordinator to allow retrieving and clearing thread memory. A Discord command (!reset) was added to trigger memory clearing for a user.
  • Database Storage Placeholder: Included a placeholder function (store_summary_to_database) to save the final conversation summary to a database when memory is cleared due to timeout or manual reset.
Changelog
  • backend/app/agents/devrel/agent.py
    • Imported InMemorySaver, datetime, timedelta.
    • Instantiated InMemorySaver as self.checkpointer.
    • Added check_summarization, summarize_conversation nodes to the graph.
    • Modified graph edges: generate_response now goes to check_summarization, which conditionally routes to summarize_conversation or END. summarize_conversation routes to END.
    • Compiled the graph with checkpointer=self.checkpointer.
    • Added _should_summarize method to determine routing based on summarization_needed state.
    • Added get_thread_state and clear_thread_memory methods for memory management.
  • backend/app/agents/devrel/nodes/gather_context_node.py
    • Imported datetime.
    • Modified the node to return a dictionary of state updates, adding the new user message to messages and updating context and current_task.
  • backend/app/agents/devrel/nodes/generate_response_node.py
    • Imported HumanMessage.
    • Updated _create_llm_response to include conversation_summary, interaction_count, session_duration, and key_topics in the prompt context.
    • Adjusted conversation history formatting and limited recent messages to 10.
    • Modified generate_response_node to return a dictionary of state updates.
  • backend/app/agents/devrel/nodes/handle_faq_node.py
    • Modified handle_faq_node to return a dictionary of state updates.
  • backend/app/agents/devrel/nodes/handle_onboarding_node.py
    • Modified handle_onboarding_node to return a dictionary of state updates.
  • backend/app/agents/devrel/nodes/handle_technical_support_node.py
    • Modified handle_technical_support_node to return a dictionary of state updates.
  • backend/app/agents/devrel/nodes/handle_web_search_node.py
    • Modified handle_web_search_node to return a dictionary of state updates.
  • backend/app/agents/devrel/nodes/summarization_node.py
    • Added new file summarization_node.py.
    • Implemented check_summarization_needed node to check interaction count and timeout for summarization.
    • Implemented summarize_conversation_node to generate conversation summaries using an LLM.
    • Implemented _extract_key_topics helper to extract topics from the summary.
    • Added store_summary_to_database placeholder function.
    • Defined SUMMARIZATION_THRESHOLD (5) and THREAD_TIMEOUT_HOURS (1) constants.
  • backend/app/agents/devrel/prompts/base_prompt.py
    • Modified GENERAL_LLM_RESPONSE_PROMPT to include a section for CONVERSATION SUMMARY and updated formatting for other context elements.
    • Added instructions for the LLM on using the summary and recent history.
  • backend/app/agents/devrel/prompts/summarization_prompt.py
    • Added new file summarization_prompt.py.
    • Defined CONVERSATION_SUMMARY_PROMPT for the summarization LLM call.
  • backend/app/agents/shared/base_agent.py
    • Modified run and stream_run methods to accept thread_id and use it in the LangGraph config for state persistence.
    • Added logging to indicate state recovery or fresh start.
  • backend/app/agents/shared/state.py
    • Imported Annotated, datetime, operator.add.
    • Defined replace_summary and replace_topics reducer functions.
    • Added new fields to AgentState for persistent memory and session management: user_profile, conversation_summary (with replace_summary), key_topics (with replace_topics), session_start_time, last_interaction_time, interaction_count (with add), summarization_needed, and memory_timeout_reached.
    • Changed messages field to use the add reducer.
    • Removed conversation_history field.
  • backend/app/core/orchestration/agent_coordinator.py
    • Imported datetime and store_summary_to_database.
    • Registered _handle_clear_memory_request handler.
    • Modified _handle_devrel_request to extract memory_thread_id and pass it to the agent run.
    • Added logic to check for memory_timeout_reached after the agent run and trigger _handle_memory_timeout.
    • Implemented _handle_clear_memory_request to handle manual memory clear requests.
    • Implemented _handle_memory_timeout to store summary and clear memory on timeout.
  • backend/bots/discord/discord_bot.py
    • Added memory_thread_id (set to user_id) to the message data sent to the queue for DevRel requests.
    • Modified the reset_thread command (!reset) to enqueue a clear_thread_memory message to the coordinator.
    • Updated the help message for the !reset command.
Activity
  • coderabbitai[bot] initiated processing of the changes.
  • gemini-code-assist[bot] reported an error attempting to create a summary.
  • smokeyScraper manually triggered the gemini summary command.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🔭 Outside diff range comments (3)
backend/app/agents/devrel/nodes/handle_technical_support_node.py (1)

6-17: ⚠️ Potential issue

Return-type annotation is now wrong – update to dict

The body now returns a plain dictionary, but the signature still advertises -> AgentState. This will confuse static analysers, IDEs, and anyone consuming the function.

-async def handle_technical_support_node(state: AgentState) -> AgentState:
+async def handle_technical_support_node(state: AgentState) -> dict:

(Optionally refine the doc-string to mention the dictionary contract.)

backend/app/agents/devrel/nodes/handle_onboarding_node.py (1)

6-17: ⚠️ Potential issue

Mismatch between declared and actual return type

Same issue as in the technical-support node – function returns a dict while the annotation says AgentState.

-async def handle_onboarding_node(state: AgentState) -> AgentState:
+async def handle_onboarding_node(state: AgentState) -> dict:

Aligning signatures avoids mypy / pyright errors and keeps the codebase consistent.

backend/app/agents/devrel/nodes/gather_context_node.py (1)

8-9: ⚠️ Potential issue

Return-type annotation is now incorrect – update to reflect dict result

gather_context_node was refactored to return a raw dictionary, yet the signature still advertises -> AgentState.
Any downstream static analysis or type-checking will flag this as an error and IDEs will offer the wrong completions.

-async def gather_context_node(state: AgentState) -> AgentState:
+async def gather_context_node(state: AgentState) -> dict:

Remember to adjust doc-strings and any callers that relied on the old contract.

🧹 Nitpick comments (6)
backend/app/agents/devrel/nodes/handle_faq_node.py (1)

6-26: Add minimal typing + clarify faq_tool expectations

faq_tool is untyped, so editors can’t surface async/attr mistakes. Consider a lightweight Protocol:

from typing import Protocol, runtime_checkable

@runtime_checkable
class FAQTool(Protocol):
    async def get_response(self, query: str) -> str: ...

and change the signature:

-async def handle_faq_node(state: AgentState, faq_tool) -> dict:
+async def handle_faq_node(state: AgentState, faq_tool: FAQTool) -> dict:

Nice to have, but it will improve correctness and discoverability.

backend/app/agents/devrel/nodes/gather_context_node.py (1)

32-35: Consider appending to existing state.messages instead of starting a new list

Returning {"messages": [new_message], ...} discards the prior history held in state.messages.
If the caller simply merges dicts (state |= output pattern), you’ll lose the existing messages array.
Safer option:

-        "messages": [new_message],
+        "messages": state.messages + [new_message],

…unless the orchestration layer intentionally rebuilds history elsewhere.

backend/bots/discord/discord_bot.py (1)

242-243: Minor: help text still says “chat thread and memory” – maybe mention the !reset delay

Users might appreciate a hint that the next message will spawn a new thread automatically (mirrors the confirmation you send).
Totally optional.

backend/app/agents/devrel/nodes/generate_response_node.py (1)

50-63: Potential zero/negative session-duration & naive-datetime issue

state.last_interaction_time and state.session_start_time are naive datetime.now() instances.
If the orchestrator later switches to timezone-aware stamps this subtraction will raise.
Also, first interaction yields 0.0 minutes, which may not read nicely to end-users.

-        f"Session duration: {(state.last_interaction_time - state.session_start_time).total_seconds() / 60:.1f} minutes"
+        f"Session duration: {max(1, int((state.last_interaction_time - state.session_start_time).total_seconds() // 60))} min"

Or simply omit on first message.

backend/app/core/orchestration/agent_coordinator.py (1)

4-4: Remove unused datetime import (Ruff F401)

The module no longer references datetime; keeping the import will fail the linter.

-from datetime import datetime
🧰 Tools
🪛 Ruff (0.11.9)

4-4: datetime.datetime imported but unused

Remove unused import: datetime.datetime

(F401)

backend/app/agents/devrel/nodes/summarization_node.py (1)

131-136: Placeholder function needs implementation.

The TODO indicates this function needs to store summaries to PostgreSQL. This is important for persistent memory across sessions.

Would you like me to help implement the database storage logic or create an issue to track this task?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4dd80b8 and a7d4122.

📒 Files selected for processing (14)
  • backend/app/agents/devrel/agent.py (6 hunks)
  • backend/app/agents/devrel/nodes/gather_context_node.py (2 hunks)
  • backend/app/agents/devrel/nodes/generate_response_node.py (1 hunks)
  • backend/app/agents/devrel/nodes/handle_faq_node.py (2 hunks)
  • backend/app/agents/devrel/nodes/handle_onboarding_node.py (1 hunks)
  • backend/app/agents/devrel/nodes/handle_technical_support_node.py (1 hunks)
  • backend/app/agents/devrel/nodes/handle_web_search_node.py (2 hunks)
  • backend/app/agents/devrel/nodes/summarization_node.py (1 hunks)
  • backend/app/agents/devrel/prompts/base_prompt.py (1 hunks)
  • backend/app/agents/devrel/prompts/summarization_prompt.py (1 hunks)
  • backend/app/agents/shared/base_agent.py (2 hunks)
  • backend/app/agents/shared/state.py (2 hunks)
  • backend/app/core/orchestration/agent_coordinator.py (5 hunks)
  • backend/bots/discord/discord_bot.py (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
backend/app/agents/devrel/nodes/handle_faq_node.py (1)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
backend/bots/discord/discord_bot.py (1)
backend/app/core/orchestration/queue_manager.py (2)
  • enqueue (48-65)
  • QueuePriority (9-12)
backend/app/agents/shared/base_agent.py (1)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
backend/app/agents/devrel/nodes/summarization_node.py (1)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
backend/app/agents/devrel/nodes/handle_web_search_node.py (1)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
backend/app/agents/devrel/nodes/generate_response_node.py (1)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
backend/app/agents/devrel/agent.py (2)
backend/app/agents/devrel/nodes/summarization_node.py (3)
  • check_summarization_needed (13-45)
  • summarize_conversation_node (47-108)
  • store_summary_to_database (131-135)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
🪛 Ruff (0.11.9)
backend/app/core/orchestration/agent_coordinator.py

4-4: datetime.datetime imported but unused

Remove unused import: datetime.datetime

(F401)

backend/app/agents/devrel/agent.py

4-4: datetime.datetime imported but unused

Remove unused import

(F401)


4-4: datetime.timedelta imported but unused

Remove unused import

(F401)

🪛 Pylint (3.3.7)
backend/app/agents/devrel/agent.py

[refactor] 149-164: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it

(R1705)

🔇 Additional comments (16)
backend/app/agents/devrel/prompts/summarization_prompt.py (1)

1-18: Prompt addition looks solid

The template is clear, well-structured, and follows existing constant-naming conventions. No issues spotted.

backend/app/agents/devrel/nodes/handle_web_search_node.py (1)

31-43: 🛠️ Refactor suggestion

Wrap external call in try/except to avoid node hard-failure

search_tool.search is an external dependency and may raise (network timeouts, quota, etc.). A guarded call keeps the graph alive and allows graceful fallback.

-    search_results = await search_tool.search(search_query)
+    try:
+        search_results = await search_tool.search(search_query)
+    except Exception as exc:
+        logger.error("Search tool failed: %s", exc)
+        search_results = []

Returning an empty list lets downstream nodes decide how to respond without crashing the run.

⛔ Skipped due to learnings
Learnt from: smokeyScraper
PR: AOSSIE-Org/Devr.AI#72
File: backend/app/agents/devrel/nodes/handle_web_search_node.py:31-42
Timestamp: 2025-06-08T13:31:11.572Z
Learning: In backend/app/agents/devrel/tools/search_tool.py, the TavilySearchTool.search() method already includes comprehensive error handling that catches all exceptions and returns an empty list instead of raising them, so calling functions don't need additional try-catch blocks.
backend/bots/discord/discord_bot.py (2)

87-88: Verify that memory_thread_id = user_id won’t leak context across guilds

A single Discord user can participate in multiple servers.
Using plain user_id as the memory key means conversations from different guilds (and even DMs) share one long-term memory blob.
If that is not desirable, consider namespacing:

memory_thread_id = f"{message.guild.id}:{user_id}" if message.guild else f"dm:{user_id}"

193-201: Nice touch – explicit high-priority memory-clear message looks solid
The enqueue call includes a clear, high-priority payload; coordinator side already registers the handler.
LGTM.

backend/app/agents/devrel/prompts/base_prompt.py (1)

5-27: Prompt restructuring looks clean and self-explanatory
The new sections should help the model leverage both short- and long-term context.
No issues spotted.

backend/app/agents/devrel/nodes/generate_response_node.py (1)

96-99: final_response is not written back to AgentState

Down-stream logic (e.g. summarisation, coordinator) still inspects state.final_response.
Currently you return a dict with that key, but the original AgentState instance remains unchanged.
Ensure the orchestrator merges this dict into the state or, easier, also set the field:

-    return {
-        "final_response": final_response,
-        "current_task": "response_generated"
-    }
+    state.final_response = final_response
+    state.current_task = "response_generated"
+    return {"final_response": final_response, "current_task": state.current_task}

Confirm whichever merging strategy you adopted picks this up.

backend/app/core/orchestration/agent_coordinator.py (2)

38-40: Empty memory_thread_id fallback path can disable persistence

If user_id is missing (edge integrations) you may pass an empty string to the agent’s saver, creating orphaned checkpoints.
Better to guard:

memory_thread_id = message_data.get("memory_thread_id") or message_data.get("user_id")
if not memory_thread_id:
    memory_thread_id = f"anon_{uuid.uuid4()}"

71-101: Robust & well-logged memory-clear workflow

The handler stores a final summary before wiping the saver – exactly what we want to avoid data loss.
Good defensive logging.

backend/app/agents/shared/base_agent.py (2)

22-44: Well-implemented thread-based state persistence!

The state recovery logic with comprehensive logging provides excellent visibility into the agent's memory lifecycle. The implementation correctly handles both existing and new thread states.


56-76: Consistent implementation of thread persistence for streaming mode.

The streaming method properly mirrors the state recovery pattern from the run method, with added step counting for debugging streaming workflows.

backend/app/agents/devrel/nodes/summarization_node.py (2)

98-98: Clever use of negative count to reset interaction counter!

Using -current_count with the additive merge semantics effectively resets the counter to 0. This is a nice pattern for state updates.


110-129: Well-structured topic extraction with appropriate limits.

The function properly extracts topics with error handling and a sensible limit of 5 topics to prevent unbounded growth.

backend/app/agents/devrel/agent.py (2)

35-93: Well-integrated summarization workflow!

The summarization nodes and conditional routing are properly integrated into the agent's workflow graph. The use of InMemorySaver for checkpointing enables the thread-based state persistence.


122-137: Clean helper methods for state management.

Both _should_summarize and get_thread_state are well-implemented with appropriate error handling.

backend/app/agents/shared/state.py (2)

6-16: Well-designed custom merge functions!

The replace_summary and replace_topics functions provide appropriate merge semantics for the summarization feature, ensuring newer values replace older ones.


29-45: Comprehensive state model extensions for memory management.

The new fields effectively support conversation summarization and session management. The use of appropriate type annotations with custom merge semantics (additive for interaction_count, replace for conversation_summary and key_topics) is well thought out.

@smokeyScraper
Copy link
Contributor Author

resolving issues...

@smokeyScraper
Copy link
Contributor Author

smokeyScraper commented Jun 12, 2025

Refers #73 (can be closed once I implement persistent memory in a separate PR)
@chandansgowda, this seems good to go. could you please review and merge?
Currently, only an in-memory saver with timeouts is implemented.
planning to store the summarized context to DB when a thread archives for later retrieval in gather_context_node.

Will scope out DB issues soon :)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
backend/app/agents/devrel/agent.py (1)

138-170: ⚠️ Potential issue

clear_thread_memory is still outside the class – causes NameError: name 'self' is not defined

The function is defined at module level but references self, so the first call will explode.
Indent it so it becomes a method of DevRelAgent:

-async def clear_thread_memory(self, thread_id: str, force_clear: bool = False) -> bool:
+    async def clear_thread_memory(self, thread_id: str, force_clear: bool = False) -> bool:
         """Clear memory for a specific thread using memory_timeout_reached flag"""
         ...

(Indent the entire body by 4 spaces.)

Follow-ups:

  1. Verify langgraph.checkpoint.memory.InMemorySaver exposes a delete_thread() (or equivalent) method; if not, implement a wrapper or use del self.checkpointer[thread_id].
  2. Consider the Pylint hint: after return True, the else: at 161-163 is redundant.
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 148-163: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it

(R1705)

🧹 Nitpick comments (2)
backend/app/agents/devrel/agent.py (2)

34-34: InMemorySaver() instance is local to each agent – consider sharing or injecting

Creating a new InMemorySaver() per DevRelAgent instance isolates checkpoints between concurrent agent instances or workers.
If your deployment spins up multiple agents (e.g., per HTTP request), conversation continuity will break because each agent keeps a private store.

Prefer one of:

-        self.checkpointer = InMemorySaver()
+        # Re-use a global/singleton checkpointer so all agent instances share the same store.
+        self.checkpointer = shared_checkpointer or InMemorySaver()

or accept a checkpointer in __init__ and default to the singleton.
This keeps thread memory consistent across processes.


158-163: Redundant else block after early return

Lines 158-160 already return True; the subsequent else: (161-163) can be safely de-indented to reduce nesting, satisfying R1705.

-                logger.info(f"Successfully cleared memory for thread {thread_id}")
-                return True
-            else:
-                logger.info(f"Thread {thread_id} has not timed out, memory preserved")
-                return False
+                logger.info(f"Successfully cleared memory for thread {thread_id}")
+                return True
+            logger.info(f"Thread {thread_id} has not timed out, memory preserved")
+            return False
🧰 Tools
🪛 Pylint (3.3.7)

[refactor] 148-163: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it

(R1705)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7d4122 and ebb0154.

📒 Files selected for processing (2)
  • backend/app/agents/devrel/agent.py (6 hunks)
  • backend/app/agents/devrel/nodes/summarization_node.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/app/agents/devrel/nodes/summarization_node.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/agents/devrel/agent.py (2)
backend/app/agents/devrel/nodes/summarization_node.py (3)
  • check_summarization_needed (14-46)
  • summarize_conversation_node (48-109)
  • store_summary_to_database (132-136)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
🪛 Pylint (3.3.7)
backend/app/agents/devrel/agent.py

[refactor] 148-163: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it

(R1705)

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

♻️ Duplicate comments (1)
backend/app/agents/devrel/agent.py (1)

161-166: 🛠️ Refactor suggestion

Remove redundant else branches after return

Pylint is right: lines 161-166 are dead code paths nested under unnecessary else clauses.
Flattening them improves readability and eliminates the R1705 warning:

-                else:
-                    logger.info(f"Thread {thread_id} has not timed out, memory preserved")
-                    return False
-            else:
-                logger.info(f"No state found for thread {thread_id}, nothing to clear")
-                return True
+                logger.info(f"Thread {thread_id} has not timed out, memory preserved")
+                return False
+
+            logger.info(f"No state found for thread {thread_id}, nothing to clear")
+            return True
🧹 Nitpick comments (1)
backend/app/agents/devrel/agent.py (1)

128-136: Consider returning an immutable snapshot from get_thread_state

state.values is passed by reference; callers mutating this dict will silently bypass LangGraph’s merge logic and may corrupt the checkpoint.
Protect against accidental mutation by returning a shallow copy:

-            return state.values if state else {}
+            return dict(state.values) if state else {}

This is a low-overhead safety net.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 897b5fb and 2952ac8.

📒 Files selected for processing (1)
  • backend/app/agents/devrel/agent.py (6 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/app/agents/devrel/agent.py (2)
backend/app/agents/devrel/nodes/summarization_node.py (3)
  • check_summarization_needed (14-46)
  • summarize_conversation_node (48-109)
  • store_summary_to_database (132-136)
backend/app/agents/shared/state.py (1)
  • AgentState (18-73)
🪛 Pylint (3.3.7)
backend/app/agents/devrel/agent.py

[refactor] 148-163: Unnecessary "else" after "return", remove the "else" and de-indent the code inside it

(R1705)

Comment on lines +34 to 35
self.checkpointer = InMemorySaver()
super().__init__("DevRelAgent", self.config)
Copy link
Contributor

@coderabbitai coderabbitai bot Jun 13, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Share a single InMemorySaver instead of instantiating per-agent

self.checkpointer = InMemorySaver() creates a brand-new store for every DevRelAgent instance.
If the application spins up a fresh agent per request (very common in serverless / web frameworks), each request will operate on an isolated store and no memory carry-over will occur, defeating the whole purpose of the saver.

Create one saver at module level (or inject it from the orchestrator) and reuse it across agents:

-        self.checkpointer = InMemorySaver()
+# backend/app/agents/devrel/agent.py
+CHECKPOINTER = InMemorySaver()   # shared singleton
+
+        self.checkpointer = CHECKPOINTER

No other code changes are required because workflow.compile(checkpointer=…) already accepts the instance.
This minor refactor preserves true cross-session memory and avoids silent data loss.

Also applies to: 91-92

🤖 Prompt for AI Agents
In backend/app/agents/devrel/agent.py around lines 34 to 35, the code creates a
new InMemorySaver instance for each DevRelAgent, causing isolated memory stores
per agent. To fix this, move the InMemorySaver instantiation to the module level
so that a single shared instance is reused across all DevRelAgent instances.
This change preserves memory across sessions without modifying other code since
the saver instance is already accepted by workflow.compile. Apply the same
refactor to lines 91-92 as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not a problem as only one instance lives for the entire application lifetime with thread and InMemorySaver() based system to remember user conversations throughout.

Copy link
Contributor

Choose a reason for hiding this comment

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

@smokeyScraper, thank you for the clarification! That makes perfect sense - with a singleton DevRelAgent instance living for the entire application lifetime, the InMemorySaver created in the constructor will indeed be shared across all conversations through the thread-based system. This architecture effectively achieves memory persistence without the isolation concerns I raised. I appreciate you explaining the application's design pattern.


✏️ Learnings added
Learnt from: smokeyScraper
PR: AOSSIE-Org/Devr.AI#75
File: backend/app/agents/devrel/agent.py:34-35
Timestamp: 2025-06-13T21:56:19.160Z
Learning: In the Devr.AI backend, the DevRelAgent follows a singleton pattern where only one instance exists for the entire application lifetime, using InMemorySaver with thread-based conversation management to persist user conversations across sessions.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants