Skip to content

fix(deep_research): resolve DeepResearchAgent returning None (fixes #1770)#2487

Open
aviraldua93 wants to merge 2 commits intoag2ai:mainfrom
aviraldua93:fix/deep-research-agent-returns-none
Open

fix(deep_research): resolve DeepResearchAgent returning None (fixes #1770)#2487
aviraldua93 wants to merge 2 commits intoag2ai:mainfrom
aviraldua93:fix/deep-research-agent-returns-none

Conversation

@aviraldua93
Copy link
Copy Markdown

Fix DeepResearchAgent returning None

Fixes #1770

Problem

DeepResearchAgent returns None instead of the researched answer. The root cause is in DeepResearchTool, which uses three nested initiate_chat() calls that terminate via tool execution (confirm_summary, generate_subquestions, confirm_answer).

When a chat terminates via tool call, the default _last_msg_as_summary method extracts content from the last sender→recipient message — but that message is a tool_calls message with content=None. This causes result.summary to return "" for all three inner chats, propagating up as None.

Root Cause Trace

  1. delegate_research_task()critic_agent.initiate_chat(summarizer_agent, ...) — terminates when confirm_summary tool is called
  2. _last_msg_as_summary() (conversable_agent.py L2159) → recipient.last_message(sender)["content"]None (tool_call message)
  3. result.summary"" → returned up the chain → DeepResearchAgent returns None

Same pattern affects all 3 inner chats: confirm_summary, generate_subquestions, and confirm_answer.

Fix

Added _extract_last_result_with_prefix() static method to DeepResearchTool that:

  1. Walks chat_result.chat_history in reverse
  2. Finds the first message whose content starts with the expected prefix (e.g., "Answer confirmed:", "Subquestions answered:", "Subquestions generated:")
  3. Falls back to result.summary if no match is found

Replaced all 3 bare return result.summary calls with this helper, passing the appropriate prefix for each chat stage.

Tests

Added 5 unit tests in TestExtractLastResultWithPrefix:

  • Extracts answer from tool result message in chat history
  • Returns last match when multiple prefixed messages exist
  • Falls back to summary when no prefix match found
  • Handles None content gracefully (no crash)
  • Handles empty chat history

All tests pass without requiring API keys or optional dependencies.

Changes

  • autogen/tools/experimental/deep_research/deep_research.py — Added helper method + replaced 3 return statements
  • test/tools/experimental/deep_research/test_deep_research.py — Added 5 regression tests

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 16, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@aviraldua93 aviraldua93 force-pushed the fix/deep-research-agent-returns-none branch 3 times, most recently from d18c2e2 to 59e07f0 Compare March 16, 2026 23:52
Copy link
Copy Markdown
Contributor

@amabito amabito left a comment

Choose a reason for hiding this comment

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

deep_research.py:83-88 — list-type content silently skipped

isinstance(content, str) skips non-string content without a trace. Multimodal content would be a quiet no-op here — maybe a logger.debug on the else branch?

deep_research.py:135-142 — silent_override=True not explained

Four silent_override=True additions aren't in the PR description. Suppressing intermediate tool output? Curious how this connects to the None fix — or is it a separate cleanup?

When DeepResearchTool's inner initiate_chat() calls terminate via tool
execution (confirm_summary, generate_subquestions, confirm_answer), the
default _last_msg_as_summary extracts content from the last
sender->recipient message, which is a tool_call with content=None.
This causes result.summary to return an empty string, making the
DeepResearchAgent return None to the user.

Add _extract_last_result_with_prefix() static method that walks
chat_result.chat_history in reverse to find the actual answer message
by its expected prefix, falling back to result.summary when no match
is found. Replace all 3 bare return result.summary calls with this
helper.

Changes:
- Add _extract_last_result_with_prefix() helper with logger.debug for
  list-type content (multimodal messages)
- Harden fallback with 'or empty string' to match str return type
- Restore original register_for_llm/register_for_execution calls
  (no silent_override changes)

Includes 6 unit tests covering: prefix extraction, multiple matches,
fallback to summary, None content handling, empty history, and None
summary fallback.

Fixes ag2ai#1770

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aviraldua93 aviraldua93 force-pushed the fix/deep-research-agent-returns-none branch from 59e07f0 to 29c563c Compare March 24, 2026 22:14
@aviraldua93
Copy link
Copy Markdown
Author

deep_research.py:83-88 — list-type content silently skipped

isinstance(content, str) skips non-string content without a trace. Multimodal content would be a quiet no-op here — maybe a logger.debug on the else branch?

deep_research.py:135-142 — silent_override=True not explained

Four silent_override=True additions aren't in the PR description. Suppressing intermediate tool output? Curious how this connects to the None fix — or is it a separate cleanup?

Thanks @amabito Thanks for the careful review — both points are valid.

silent_override=True: You're right to call this out — it was unrelated to the None fix and shouldn't have been in this PR. Removed all 4 instances; the
register calls now match the original code.

List-type content: The three tool functions (confirm_summary, confirm_answer, generate_subquestions) all explicitly return str, so list content won't
appear in practice here. That said, defensive logging is cheap — I've added a logger.debug on the elif isinstance(content, list) branch so it's not a
silent no-op. Also hardened the fallback to chat_result.summary or "" to match the -> str return type annotation.

Updated in 29c563c. Thanks again for the feedback!

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.

[Bug]: DeepResearchAgent not working

3 participants