@@ -210,10 +210,12 @@ async def _run_consensus(
210210 proposer_override : str | None = None ,
211211 challengers_override : list [str ] | None = None ,
212212 web_search : bool = False ,
213- ) -> tuple [str , float , float , str | None , float , str | None ]:
213+ ) -> tuple [
214+ str , float , float , str | None , float , str | None , list [dict [str , str | None ]]
215+ ]:
214216 """Run the full consensus loop.
215217
216- Returns (decision, confidence, rigor, dissent, total_cost, overview).
218+ Returns (decision, confidence, rigor, dissent, total_cost, overview, citations ).
217219 """
218220 from duh .consensus .convergence import check_convergence
219221 from duh .consensus .handlers import (
@@ -332,13 +334,25 @@ async def _run_consensus(
332334 if display and ctx .tool_calls_log :
333335 display .show_tool_use (ctx .tool_calls_log )
334336
337+ # Collect all citations across rounds
338+ all_citations : list [dict [str , str | None ]] = []
339+ for rr in ctx .round_history :
340+ all_citations .extend (rr .proposal_citations )
341+ for ch in rr .challenges :
342+ all_citations .extend (ch .citations )
343+ # Include current round (may not be archived yet)
344+ all_citations .extend (ctx .proposal_citations )
345+ for ch in ctx .challenges :
346+ all_citations .extend (ch .citations )
347+
335348 return (
336349 ctx .decision or "" ,
337350 ctx .confidence ,
338351 ctx .rigor ,
339352 ctx .dissent ,
340353 pm .total_cost ,
341354 ctx .overview ,
355+ all_citations ,
342356 )
343357
344358
@@ -490,14 +504,15 @@ def ask(
490504 _error (str (e ))
491505 return # unreachable
492506
493- decision , confidence , rigor , dissent , cost , overview = result
507+ decision , confidence , rigor , dissent , cost , overview , citations = result
494508
495509 from duh .cli .display import ConsensusDisplay
496510
497511 display = ConsensusDisplay ()
498512 display .show_final_decision (
499513 decision , confidence , rigor , cost , dissent , overview = overview
500514 )
515+ display .show_citations (citations )
501516
502517
503518async def _refine_question (question : str , config : DuhConfig ) -> str :
@@ -532,7 +547,9 @@ async def _ask_async(
532547 panel : list [str ] | None = None ,
533548 proposer_override : str | None = None ,
534549 challengers_override : list [str ] | None = None ,
535- ) -> tuple [str , float , float , str | None , float , str | None ]:
550+ ) -> tuple [
551+ str , float , float , str | None , float , str | None , list [dict [str , str | None ]]
552+ ]:
536553 """Async implementation for the ask command."""
537554 from duh .cli .display import ConsensusDisplay
538555
@@ -641,12 +658,19 @@ async def _ask_auto_async(
641658
642659 display = ConsensusDisplay ()
643660 display .start ()
644- decision , confidence , rigor , dissent , cost , overview = await _run_consensus (
645- question , config , pm , display = display
646- )
661+ (
662+ decision ,
663+ confidence ,
664+ rigor ,
665+ dissent ,
666+ cost ,
667+ overview ,
668+ citations ,
669+ ) = await _run_consensus (question , config , pm , display = display )
647670 display .show_final_decision (
648671 decision , confidence , rigor , cost , dissent , overview = overview
649672 )
673+ display .show_citations (citations )
650674
651675
652676async def _ask_decompose_async (
@@ -719,10 +743,11 @@ async def _ask_decompose_async(
719743 # Single-subtask optimization: skip synthesis
720744 if len (subtask_specs ) == 1 :
721745 result = await _run_consensus (question , config , pm , display = display )
722- decision , confidence , rigor , dissent , cost , overview = result
746+ decision , confidence , rigor , dissent , cost , overview , citations = result
723747 display .show_final_decision (
724748 decision , confidence , rigor , cost , dissent , overview = overview
725749 )
750+ display .show_citations (citations )
726751 await engine .dispose ()
727752 return
728753
@@ -2371,6 +2396,7 @@ async def _batch_async(
23712396 _dissent ,
23722397 _cost ,
23732398 _overview ,
2399+ _citations ,
23742400 ) = await _run_consensus (question , config , pm )
23752401
23762402 q_cost = pm .total_cost - cost_before
0 commit comments