Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]

### Added
- `Gad7AnxietyScorer` (`src/medagent/safety/gad7_anxiety_scorer.py`): research-only advisory score (SAFETY #243). Gap vs MDCalc / USPSTF GAD-7 anxiety severity screen. Distinct from `Phq9DepressionScorer` / `EpworthSleepinessScorer`. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2 for narrative only. See `docs/guides/GAD7ANXIETYSCORER_GUIDE.md`.
- `MorseFallScorer` (`src/medagent/safety/morse_fall_scorer.py`): research-only advisory score (SAFETY #241). Gap vs MDCalc / AHRQ Morse Fall Scale screen. Distinct from `News2EarlyWarningScorer` / `PewsEarlyWarningScorer`. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2 for narrative only. See `docs/guides/MORSEFALLSCORER_GUIDE.md`.
- `Phq9DepressionScorer` (`src/medagent/safety/phq9_depression_scorer.py`): research-only advisory score (SAFETY #240). Gap vs MDCalc / USPSTF PHQ-9 depression severity screen. Distinct from `EpworthSleepinessScorer` / `StopBangOsaScorer`. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2 for narrative only. See `docs/guides/PHQ9DEPRESSIONSCORER_GUIDE.md`.
- `BisapPancreatitisScorer` (`src/medagent/safety/bisap_pancreatitis_scorer.py`): research-only advisory score (SAFETY #239). Gap vs MDCalc / ACG BISAP pancreatitis severity screen. Distinct from `RansonPancreatitisScorer` / `MaddreyDiscriminantScorer`. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2 for narrative only. See `docs/guides/BISAPPANCREATITISSCORER_GUIDE.md`.
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ Research-only advisory scorer. Gap vs MDCalc / AASLD FIB-4 liver fibrosis screen

Research-only advisory scorer. Gap vs MDCalc / ACG BISAP pancreatitis severity screen. Optional narrative via GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2.

### Gad7AnxietyScorer

![Gad7AnxietyScorer](assets/gad7_anxiety_demo.gif)

Research-only advisory scorer. Gap vs MDCalc / USPSTF GAD-7 anxiety severity screen. Optional narrative via GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2.

### MorseFallScorer

![MorseFallScorer](assets/morse_fall_demo.gif)
Expand Down
6 changes: 6 additions & 0 deletions SAFETY.md
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,12 @@ yields a `MorseFallRisk` with score, band, positive factors, severity, and
rationale. RESEARCH USE ONLY — never modifies medications. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2
for narrative summaries only.

### 3.243 Gad7Anxiety Scorer
`Gad7AnxietyScorer` computes an advisory score (MDCalc / USPSTF GAD-7 anxiety severity screen). Every call
yields a `Gad7AnxietyRisk` with score, band, positive factors, severity, and
rationale. RESEARCH USE ONLY — never modifies medications. Prefer GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2
for narrative summaries only.

## 4. Escalation Policy

When the agent enters `ESCALATE` state:
Expand Down
Binary file added assets/gad7_anxiety_demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions docs/guides/GAD7ANXIETYSCORER_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Gad7AnxietyScorer Guide

![Gad7AnxietyScorer](../../assets/gad7_anxiety_demo.gif)

Research-only advisory scorer. Gap vs MDCalc / USPSTF GAD-7 anxiety severity screen. Distinct from `Phq9DepressionScorer` / `EpworthSleepinessScorer`.

Optional narrative via **GPT-5.5 / Claude Sonnet 4.6 / Gemini 3.x / Kimi K2**.

## Usage

```python
from medagent.safety.gad7_anxiety_scorer import (
Gad7AnxietyFactors,
Gad7AnxietyScorer,
)

findings = Gad7AnxietyScorer().check(Gad7AnxietyFactors())
print(findings[0].band)
```

## Safety

RESEARCH USE ONLY. Never modifies medications. See `SAFETY.md` #243.
17 changes: 17 additions & 0 deletions src/medagent/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5183,3 +5183,20 @@ class MorseFallRisk(BaseModel, frozen=True):
)
severity: Severity
rationale: str


class Gad7AnxietyRisk(BaseModel, frozen=True):
"""Gad7AnxietyScorer finding.

RESEARCH USE ONLY — advisory clinical score. Distinct from
Phq9DepressionScorer / EpworthSleepinessScorer.
Prefer. Never modifies medications.
"""

score: int = Field(description="Score total")
band: str = Field(description="Risk band")
positive_factors: list[str] = Field(
default_factory=list, description="Factor names that contributed"
)
severity: Severity
rationale: str
2 changes: 2 additions & 0 deletions src/medagent/safety/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
FluoroquinoloneWarfarinChecker,
)
from medagent.safety.four_score_scorer import FourScoreScorer
from medagent.safety.gad7_anxiety_scorer import Gad7AnxietyScorer
from medagent.safety.gcs_neurologic_status_scorer import GcsNeurologicStatusScorer
from medagent.safety.gentamicin_level_trend_bridge import GentamicinLevelTrendBridge
from medagent.safety.gentamicin_vancomycin_checker import GentamicinVancomycinChecker
Expand Down Expand Up @@ -309,6 +310,7 @@
"FluoroquinoloneNsaidChecker",
"FluoroquinoloneWarfarinChecker",
"FourScoreScorer",
"Gad7AnxietyScorer",
"GcsNeurologicStatusScorer",
"GentamicinLevelTrendBridge",
"GentamicinVancomycinChecker",
Expand Down
82 changes: 82 additions & 0 deletions src/medagent/safety/gad7_anxiety_scorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Gad7AnxietyScorer (research-only clinical score).

Advisory scorer closing the MDCalc / USPSTF GAD-7 anxiety severity screen gap for
offline medical-ward agent pipelines.
Distinct from `Phq9DepressionScorer` / `EpworthSleepinessScorer`. Prefer
frontier LLMs for narrative summaries.
Never modifies medications and never performs network I/O.

Simplified factor points for offline unit tests — not a full clinical chart.
"""

from __future__ import annotations

from dataclasses import dataclass

from medagent.logging_config import get_logger
from medagent.models import Gad7AnxietyRisk, Severity

logger = get_logger(__name__)


@dataclass(frozen=True, slots=True)
class Gad7AnxietyFactors:
"""Simplified Gad7AnxietyScorer factors."""

nervous_ok: int = 0
control_worry_ok: int = 0
worry_ok: int = 0
relax_ok: int = 0
restless_ok: int = 0
irritable_ok: int = 0
afraid_ok: int = 0


class Gad7AnxietyScorer:
"""Compute advisory Gad7AnxietyRisk findings."""

def check(self, factors: Gad7AnxietyFactors) -> list[Gad7AnxietyRisk]:
"""Return one advisory finding."""

binaries = {
"nervous_ok": factors.nervous_ok,
"control_worry_ok": factors.control_worry_ok,
"worry_ok": factors.worry_ok,
"relax_ok": factors.relax_ok,
"restless_ok": factors.restless_ok,
"irritable_ok": factors.irritable_ok,
"afraid_ok": factors.afraid_ok,
}

for name, points in binaries.items():
if points not in {0, 1}:
raise ValueError(f"{name} must be 0 or 1")

score = sum(binaries.values())
positive = [k for k, v in binaries.items() if v > 0]

if score <= 1:
band = "low"
severity = Severity.LOW
elif score <= max(2, len(binaries) // 2):
band = "intermediate"
severity = Severity.MODERATE
else:
band = "high"
severity = Severity.HIGH

rationale = (
"RESEARCH USE ONLY: Gad7AnxietyScorer total "
f"{score} ({band}) from factors {positive}. "
"This advisory score never modifies therapy; obtain qualified "
"clinical review before therapy changes."
)
finding = Gad7AnxietyRisk(
score=int(score),
band=band,
positive_factors=positive,
severity=severity,
rationale=rationale,
)
logger.info("gad7_anxiety_scorer_scored", score=score, band=band)
return [finding]
43 changes: 43 additions & 0 deletions tests/unit/safety/test_gad7_anxiety_scorer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for Gad7AnxietyScorer."""

from __future__ import annotations

import pytest

from medagent.safety.gad7_anxiety_scorer import (
Gad7AnxietyFactors,
Gad7AnxietyScorer,
)


def test_low() -> None:
"""Low band."""

findings = Gad7AnxietyScorer().check(Gad7AnxietyFactors())
assert len(findings) == 1
assert findings[0].band == "low"
assert findings[0].rationale


def test_high() -> None:
"""High band."""

findings = Gad7AnxietyScorer().check(
Gad7AnxietyFactors(
nervous_ok=1,
control_worry_ok=1,
worry_ok=1,
relax_ok=1,
restless_ok=1,
irritable_ok=1,
afraid_ok=1,
)
)
assert findings[0].band == "high"


def test_invalid() -> None:
"""Invalid factor raises."""

with pytest.raises(ValueError):
Gad7AnxietyScorer().check(Gad7AnxietyFactors(nervous_ok=2))
Loading