|
|
"""LangGraph state definitions for the research workflow.""" |
|
|
|
|
|
import operator |
|
|
from typing import Annotated, Literal, TypedDict |
|
|
|
|
|
from langchain_core.messages import BaseMessage |
|
|
from pydantic import BaseModel, Field |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Hypothesis(BaseModel): |
|
|
"""A research hypothesis with evidence tracking.""" |
|
|
|
|
|
id: str = Field(description="Unique identifier for the hypothesis") |
|
|
statement: str = Field(description="The hypothesis statement") |
|
|
status: Literal["proposed", "validating", "confirmed", "refuted"] = Field( |
|
|
default="proposed", description="Current validation status" |
|
|
) |
|
|
confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Confidence score (0.0-1.0)") |
|
|
supporting_evidence_ids: list[str] = Field(default_factory=list) |
|
|
contradicting_evidence_ids: list[str] = Field(default_factory=list) |
|
|
reasoning: str | None = Field(default=None, description="Reasoning for current status") |
|
|
|
|
|
|
|
|
class Conflict(BaseModel): |
|
|
"""A detected contradiction between sources.""" |
|
|
|
|
|
id: str = Field(description="Unique identifier for the conflict") |
|
|
description: str = Field(description="Description of the contradiction") |
|
|
source_a_id: str = Field(description="ID of the first conflicting source") |
|
|
source_b_id: str = Field(description="ID of the second conflicting source") |
|
|
status: Literal["open", "resolved"] = Field(default="open") |
|
|
resolution: str | None = Field(default=None, description="Resolution explanation if resolved") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ResearchState(TypedDict): |
|
|
"""The cognitive state shared across all graph nodes. |
|
|
|
|
|
Fields with 'Annotated[..., operator.add]' are reducers: |
|
|
returning a dict with these keys from a node will APPEND to the list |
|
|
instead of overwriting it. |
|
|
""" |
|
|
|
|
|
|
|
|
query: str |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hypotheses: Annotated[list[Hypothesis], operator.add] |
|
|
conflicts: Annotated[list[Conflict], operator.add] |
|
|
|
|
|
|
|
|
evidence_ids: Annotated[list[str], operator.add] |
|
|
|
|
|
|
|
|
messages: Annotated[list[BaseMessage], operator.add] |
|
|
|
|
|
|
|
|
next_step: Literal["search", "judge", "resolve", "synthesize", "finish"] |
|
|
iteration_count: int |
|
|
max_iterations: int |
|
|
|