mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-16 17:55:26 -04:00
Two problems made deep research report "No information could be gathered" even after it had extracted findings, on slow local models (reporter served a 20B via LM Studio): - _synthesize hard-capped its LLM call at timeout=60, while extraction uses the user's extraction_timeout (300s here) and the final report uses 180s. The slow model needed >60s to synthesize the round's findings, so synthesis timed out after 3 attempts. Raised it to 180s to match the final-report call. - When synthesis produced no report (it returns the unchanged, still-empty report on failure during round 1), the run hit `if not report: return "No information could be gathered…"` and discarded the findings it had already gathered. Now it falls back to a compiled report built from those findings (_fallback_report) so the user keeps the gathered material. Tests stub the LLM (no live model/DB), pin the synthesis timeout >= 180, that the fallback surfaces the findings rather than the give-up message, and that a failed synthesis preserves the previous report. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+30
-1
@@ -344,6 +344,16 @@ class DeepResearcher:
|
||||
self._emit(phase="writing", total_sources=len(self.urls_fetched),
|
||||
total_findings=len(findings))
|
||||
if not report:
|
||||
# Synthesis can fail (e.g. the LLM timed out) even though the search
|
||||
# rounds did gather findings. Don't throw that work away — return the
|
||||
# gathered findings as a basic compiled report instead of claiming
|
||||
# nothing was found (#1551).
|
||||
if findings:
|
||||
logger.warning(
|
||||
"Synthesis produced no report; returning %d gathered "
|
||||
"finding(s) as a fallback", len(findings)
|
||||
)
|
||||
return self._fallback_report(question, findings)
|
||||
return "No information could be gathered for this question."
|
||||
|
||||
self.evolving_report = report # preserve pre-synthesis report
|
||||
@@ -662,7 +672,11 @@ class DeepResearcher:
|
||||
[{"role": "user", "content": prompt}],
|
||||
temperature=0.3,
|
||||
max_tokens=self.max_report_tokens,
|
||||
timeout=60,
|
||||
# Synthesis is a heavy generation call like the final report
|
||||
# (which gets 180s); a slow local model (e.g. a 20B served from
|
||||
# LM Studio) routinely needs >60s for it. The old 60s cap timed
|
||||
# out mid-stream and discarded the round's findings (#1551).
|
||||
timeout=180,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Synthesis failed: {e}")
|
||||
@@ -841,6 +855,21 @@ class DeepResearcher:
|
||||
parts.append(f"**Finding {i}** — [{title}]({url})\n{content}")
|
||||
return "\n\n".join(parts)
|
||||
|
||||
def _fallback_report(self, question: str, findings: List[Dict]) -> str:
|
||||
"""Compile gathered findings into a basic report.
|
||||
|
||||
Used when the LLM synthesis step produced no report (e.g. it timed out)
|
||||
but the search rounds did collect findings — so the user still gets the
|
||||
material that was gathered instead of "No information could be gathered"
|
||||
(#1551).
|
||||
"""
|
||||
return (
|
||||
f"# {question}\n\n"
|
||||
"_Automatic synthesis did not complete, so this report lists the "
|
||||
f"{len(findings)} finding(s) gathered during research._\n\n"
|
||||
f"{self._format_findings(findings)}"
|
||||
)
|
||||
|
||||
def get_stats(self) -> Dict:
|
||||
"""Return research statistics."""
|
||||
elapsed = time.time() - self._start_time if self._start_time else 0
|
||||
|
||||
Reference in New Issue
Block a user