drugenv / server /simulator /latent_state.py
anugrahteesdollar's picture
initial: drugenv FastAPI + gradio demo
77e1e28 verified
"""Hidden ground-truth target state for the drug-target-validation POMDP.
The agent never directly observes any of these models; it must infer them
through investigation. The simulator uses ``FullLatentState`` to generate
all simulated outputs and to compute terminal rewards.
"""
from __future__ import annotations
from typing import List, Optional
from pydantic import BaseModel, Field
class TargetProfile(BaseModel):
"""Hidden ground-truth drug target properties."""
# Expression
expression_level: str = Field(
"moderate",
description=(
"One of 'high_specific', 'high_nonspecific', 'moderate', 'low'."
),
)
tissue_specificity: float = Field(0.5, ge=0.0, le=1.0)
disease_overexpression: float = Field(
1.0, description="Fold change vs. matched normal tissue."
)
# Druggability
druggability_score: float = Field(0.5, ge=0.0, le=1.0)
binding_pocket_quality: str = Field(
"good",
description=(
"One of 'excellent', 'good', 'poor', 'undruggable'."
),
)
has_known_ligands: bool = False
allosteric_site_available: bool = Field(
False,
description=(
"Whether a non-classical (allosteric) druggable site exists. "
"Only revealed by binding-site analyses with the appropriate "
"parameters."
),
)
# Selectivity
selectivity_ratio: float = Field(
5.0,
description="On-target vs off-target activity ratio.",
)
off_target_count: int = 0
off_target_genes: List[str] = Field(default_factory=list)
# Safety
toxicity_profile: str = Field(
"mild",
description="One of 'clean', 'mild', 'moderate', 'severe'.",
)
toxicity_tissues: List[str] = Field(default_factory=list)
# Clinical
clinical_precedent: str = Field(
"none",
description=(
"One of 'positive', 'mixed', 'negative', 'none'."
),
)
clinical_stage_reached: Optional[str] = Field(
None,
description=(
"Highest clinical stage previously reached: 'phase1' / 'phase2' "
"/ 'phase3' / None."
),
)
competitor_programs: List[str] = Field(default_factory=list)
# Patient stratification / biomarker context
requires_patient_stratification: bool = False
responder_biomarker: Optional[str] = None
# In-vitro / in-vivo expectations
in_vitro_ic50_nM: float = Field(
100.0, description="Expected on-target IC50 (nM)."
)
in_vivo_efficacy: str = Field(
"moderate",
description=(
"Expected pharmacological efficacy in disease-relevant models: "
"'strong', 'moderate', 'weak', 'none'."
),
)
crispr_essentiality: float = Field(
-0.3,
description=(
"DepMap-style essentiality score (more negative = more "
"essential)."
),
)
# Hidden truth used for terminal reward computation
true_viability_score: float = Field(0.5, ge=0.0, le=1.0)
correct_decision: str = Field(
"no_go", description="Either 'go' or 'no_go'."
)
misleading_signals: List[str] = Field(default_factory=list)
key_evidence_dimensions: List[str] = Field(
default_factory=list,
description=(
"Evidence categories the agent must touch to score well, e.g. "
"'expression', 'druggability', 'off_target', 'toxicity', "
"'clinical', 'literature', 'in_vitro', 'in_vivo', "
"'patient_stratification'."
),
)
class DataQualityState(BaseModel):
"""Technical noise parameters for simulated experimental outputs."""
noise_level: float = Field(0.1, ge=0.0, le=1.0)
false_positive_rate: float = Field(0.05, ge=0.0, le=1.0)
false_negative_rate: float = Field(0.05, ge=0.0, le=1.0)
database_coverage: float = Field(0.85, ge=0.0, le=1.0)
class CreditState(BaseModel):
"""Tracks the single unified experimental-credit budget."""
credits_total: int = 50
credits_used: int = 0
@property
def credits_remaining(self) -> int:
return max(0, self.credits_total - self.credits_used)
@property
def exhausted(self) -> bool:
return self.credits_used >= self.credits_total
class ValidationProgress(BaseModel):
"""Flags tracking which evidence dimensions have been investigated."""
expression_queried: bool = False
druggability_assessed: bool = False
selectivity_checked: bool = False
toxicity_assessed: bool = False
clinical_checked: bool = False
literature_reviewed: bool = False
in_vitro_done: bool = False
in_vivo_done: bool = False
patient_stratification_done: bool = False
pathway_analysed: bool = False
structure_resolved: bool = False
interactions_mapped: bool = False
crispr_done: bool = False
biomarker_correlated: bool = False
evidence_synthesised: bool = False
expert_reviewed: bool = False
report_submitted: bool = False
class FullLatentState(BaseModel):
"""Complete hidden state of the simulated drug-target world."""
target: TargetProfile = Field(default_factory=TargetProfile)
data_quality: DataQualityState = Field(default_factory=DataQualityState)
credits: CreditState = Field(default_factory=CreditState)
progress: ValidationProgress = Field(default_factory=ValidationProgress)
# Tracking which action types have been executed (used by rules / rewards)
action_call_counts: dict = Field(default_factory=dict)
rng_seed: int = 0