File size: 3,942 Bytes
4732667
 
cfb473d
4732667
cfb473d
8625ded
cfb473d
 
 
4732667
cfb473d
4732667
cfb473d
4732667
cfb473d
 
 
4732667
 
 
 
 
 
 
cfb473d
4732667
8625ded
2f8ae1f
4732667
 
 
 
cd11dad
 
4732667
 
cfb473d
 
 
 
 
 
8625ded
cfb473d
 
 
 
 
 
 
 
 
4732667
cfb473d
4732667
 
cd11dad
 
 
 
cfb473d
 
 
 
 
 
 
 
 
 
 
4732667
 
0a480cb
cfb473d
4732667
cfb473d
 
0a480cb
4732667
cfb473d
8625ded
2f8ae1f
8625ded
cfb473d
4732667
 
 
 
 
 
cfb473d
4732667
 
cfb473d
4732667
 
cfb473d
4732667
 
 
 
 
cfb473d
 
 
 
8625ded
cfb473d
 
 
4732667
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
"""
Demo: DeepCritical Agent Loop (Search + Judge + Orchestrator).

This script demonstrates the REAL Phase 4 orchestration:
- REAL Iterative Search (PubMed + ClinicalTrials + bioRxiv)
- REAL Evidence Evaluation (LLM Judge)
- REAL Orchestration Loop
- REAL Final Synthesis

NO MOCKS. REAL API CALLS.

Usage:
    uv run python examples/orchestrator_demo/run_agent.py "metformin cancer"
    uv run python examples/orchestrator_demo/run_agent.py "sildenafil heart failure" --iterations 5

Requires: OPENAI_API_KEY or ANTHROPIC_API_KEY
"""

import argparse
import asyncio
import os
import sys

from src.agent_factory.judges import JudgeHandler
from src.orchestrator import Orchestrator
from src.tools.clinicaltrials import ClinicalTrialsTool
from src.tools.europepmc import EuropePMCTool
from src.tools.pubmed import PubMedTool
from src.tools.search_handler import SearchHandler
from src.utils.models import OrchestratorConfig

MAX_ITERATIONS = 10


async def main() -> None:
    """Run the REAL agent demo."""
    parser = argparse.ArgumentParser(
        description="DeepCritical Agent Demo - REAL, No Mocks",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
This demo runs the REAL search-judge-synthesize loop:
  1. REAL search: PubMed + ClinicalTrials + bioRxiv queries
  2. REAL judge: Actual LLM assessing evidence quality
  3. REAL loop: Actual iterative refinement based on LLM decisions
  4. REAL synthesis: Actual research summary generation

Examples:
    uv run python examples/orchestrator_demo/run_agent.py "metformin cancer"
    uv run python examples/orchestrator_demo/run_agent.py "aspirin alzheimer" --iterations 5
        """,
    )
    parser.add_argument("query", help="Research query (e.g., 'metformin cancer')")
    parser.add_argument("--iterations", type=int, default=3, help="Max iterations (default: 3)")
    args = parser.parse_args()

    if not 1 <= args.iterations <= MAX_ITERATIONS:
        print(f"Error: iterations must be between 1 and {MAX_ITERATIONS}")
        sys.exit(1)

    # Fail fast: require API key
    if not (os.getenv("OPENAI_API_KEY") or os.getenv("ANTHROPIC_API_KEY")):
        print("=" * 60)
        print("ERROR: This demo requires a real LLM.")
        print()
        print("Set one of the following in your .env file:")
        print("  OPENAI_API_KEY=sk-...")
        print("  ANTHROPIC_API_KEY=sk-ant-...")
        print()
        print("This is a REAL demo. No mocks. No fake data.")
        print("=" * 60)
        sys.exit(1)

    print(f"\n{'=' * 60}")
    print("DeepCritical Agent Demo (REAL)")
    print(f"Query: {args.query}")
    print(f"Max Iterations: {args.iterations}")
    print("Mode: REAL (All live API calls)")
    print(f"{'=' * 60}\n")

    # Setup REAL components
    search_handler = SearchHandler(
        tools=[PubMedTool(), ClinicalTrialsTool(), EuropePMCTool()], timeout=30.0
    )
    judge_handler = JudgeHandler()  # REAL LLM judge

    config = OrchestratorConfig(max_iterations=args.iterations)
    orchestrator = Orchestrator(
        search_handler=search_handler, judge_handler=judge_handler, config=config
    )

    # Run the REAL loop
    try:
        async for event in orchestrator.run(args.query):
            # Print event with icon (remove markdown bold for CLI)
            print(event.to_markdown().replace("**", ""))

            # Show search results count
            if event.type == "search_complete" and event.data:
                print(f"   -> Found {event.data.get('new_count', 0)} new items")

    except Exception as e:
        print(f"\n❌ Error: {e}")
        raise

    print("\n" + "=" * 60)
    print("Demo complete! Everything was REAL:")
    print("  - Real PubMed + ClinicalTrials + bioRxiv searches")
    print("  - Real LLM judge decisions")
    print("  - Real iterative refinement")
    print("=" * 60 + "\n")


if __name__ == "__main__":
    asyncio.run(main())