File size: 3,072 Bytes
2a79143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ad651e3
2a79143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6a63556
 
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
from typing import TypedDict, Optional
from dataclasses import dataclass, field


# ---------------------------------------------------------------------------
# Dataclasses — typed objects passed through the graph
# ---------------------------------------------------------------------------

@dataclass
class Paper:
    title: str
    abstract: str
    year: int
    citation_count: int
    paper_id: str
    authors: list[str] = field(default_factory=list)
    references: list[str] = field(default_factory=list)  # list of paper_ids
    doi: str = ""
    hybrid_score: float = 0.0
    source: str = "semantic_scholar"  # or "web"


@dataclass
class WebResult:
    url: str
    snippet: str
    title: str
    inferred_year: Optional[int] = None
    hybrid_score: float = 0.0
    source: str = "web"


@dataclass
class Claim:
    text: str
    source_title: str
    source_year: int
    confidence: str          # "high" | "medium" | "low"
    flagged: bool = False    # True if contested or contradicted


@dataclass
class SessionContext:
    prior_positions: list[str] = field(default_factory=list)
    flagged_contradictions: list[str] = field(default_factory=list)
    prior_queries: list[str] = field(default_factory=list)


@dataclass
class SessionUpdate:
    position: str
    query: str
    claim_confidences: list[Claim] = field(default_factory=list)
    contradictions_found: list[str] = field(default_factory=list)


# ---------------------------------------------------------------------------
# Verdict constants — used by Critic agent
# ---------------------------------------------------------------------------

class Verdict:
    PASS = "PASS"
    STALE = "STALE"
    CONTRADICTED = "CONTRADICTED"
    INSUFFICIENT = "INSUFFICIENT"
    FORCED_PASS = "FORCED_PASS"


# ---------------------------------------------------------------------------
# LangGraph state — the single TypedDict shared across all agents
# ---------------------------------------------------------------------------

class ResearchState(TypedDict):
    # --- Input ---
    original_query: str
    session_id: str

    # --- Planner output ---
    session_context: Optional[SessionContext]
    sub_questions: list[str]

    # --- Retriever output ---
    retrieved_papers: list[Paper]
    citation_graph: dict                  # {paper_id: [cited_paper_ids]}
    web_results: list[WebResult]

    # --- Critic output ---
    critic_verdict: str                   # one of Verdict constants
    critic_notes: str
    rewritten_questions: list[str]
    retry_count: int

    # --- Synthesizer output ---
    synthesized_position: str
    claim_confidences: list[Claim]
    session_update: Optional[SessionUpdate]
    export_md: str                        # NEW v2 — full session as markdown

    # --- Eval / config ---
    decay_config: str                     # "none" | "linear" | "log"
    calibration_bin: str                  # filled by critic for eval aggregation
    latency_ms: float
    paper_reliability_scores: dict        # {paper_id: ReliabilityScore.__dict__}