Source code for tooluniverse.fda_label_tool

# fda_label_tool.py
"""
FDA Drug Label tool for ToolUniverse.

Queries the openFDA drug label API to retrieve official FDA-approved
prescribing information including indications, dosing, contraindications,
warnings, drug interactions, and pharmacology.

API: https://open.fda.gov/apis/drug/label/
No authentication required. Optional API key raises rate limits.
"""

import requests
from typing import Any

from .base_tool import BaseTool
from .tool_registry import register_tool

FDA_LABEL_URL = "https://api.fda.gov/drug/label.json"


def _extract_label(result: dict) -> dict:
    """Extract key clinical sections from a raw openFDA label record."""
    openfda = result.get("openfda", {})
    brand = openfda.get("brand_name", [])
    generic = openfda.get("generic_name", [])
    mfr = openfda.get("manufacturer_name", [])
    route = openfda.get("route", [])
    pharm = openfda.get("pharm_class_epc", [])
    rxcui = openfda.get("rxcui", [])

    def first(lst, sep=" / "):
        return sep.join(lst[:2]) if lst else None

    def section(key):
        val = result.get(key, [])
        return " ".join(val)[:2000] if val else None

    return {
        "brand_name": first(brand),
        "generic_name": first(generic),
        "manufacturer": first(mfr),
        "route": first(route),
        "pharm_class": first(pharm),
        "rxcui": rxcui[:5] if rxcui else None,
        "boxed_warning": section("boxed_warning"),
        "indications_and_usage": section("indications_and_usage"),
        "dosage_and_administration": section("dosage_and_administration"),
        "dosage_forms_and_strengths": section("dosage_forms_and_strengths"),
        "contraindications": section("contraindications"),
        "warnings_and_precautions": section("warnings_and_precautions")
        or section("warnings_and_cautions"),
        "adverse_reactions": section("adverse_reactions"),
        "drug_interactions": section("drug_interactions"),
        "use_in_specific_populations": section("use_in_specific_populations"),
        "clinical_pharmacology": section("clinical_pharmacology"),
        "mechanism_of_action": section("mechanism_of_action"),
        "spl_id": result.get("id"),
    }


[docs] @register_tool("FDALabelTool") class FDALabelTool(BaseTool): """ Tool for querying FDA-approved drug label (prescribing information). Supports searching by drug name, indication, or listing drug classes. Returns official FDA clinical content: indications, dosing, contraindications, warnings, drug interactions, and adverse reactions. """
[docs] def __init__(self, tool_config: dict[str, Any]): super().__init__(tool_config) self.query_type = tool_config.get("fields", {}).get("query_type", "search")
[docs] def run(self, arguments: dict[str, Any]) -> Any: try: qt = self.query_type if qt == "search": return self._search(arguments) elif qt == "get": return self._get_label(arguments) elif qt == "list_classes": return self._list_classes(arguments) return {"error": f"Unknown query_type: {qt}"} except requests.exceptions.Timeout: return {"error": "openFDA request timed out"} except requests.exceptions.RequestException as e: return {"error": f"openFDA request failed: {e}"} except Exception as e: return {"error": f"Unexpected error: {e}"}
[docs] def _query_drug_fields(self, drug_name: str, limit: int) -> list[dict] | None: """Search generic_name then brand_name with quoted then unquoted fallback. Returns extracted label results on first match, or None if no results found. Quoted search finds exact matches; unquoted fallback catches salt forms (e.g., "tofacitinib" matching "TOFACITINIB CITRATE"). """ for field in ("openfda.generic_name", "openfda.brand_name"): for q in (f'{field}:"{drug_name}"', f"{field}:{drug_name}"): resp = requests.get( FDA_LABEL_URL, params={"search": q, "limit": limit}, timeout=20, ) if resp.status_code == 404: continue resp.raise_for_status() results = resp.json().get("results", []) if results: return [_extract_label(r) for r in results] return None
[docs] def _get_label(self, arguments: dict) -> Any: drug_name = arguments.get("drug_name", "") if not drug_name: return {"error": "drug_name is required"} results = self._query_drug_fields(drug_name, limit=10) if not results: return {"error": f"No FDA label found for '{drug_name}'"} dn_upper = drug_name.upper() def _match_score(r): brand = (r.get("brand_name") or "").upper() generic = (r.get("generic_name") or "").upper() if brand == dn_upper or generic == dn_upper: return 0 return len(brand) or 999 results.sort(key=_match_score) return results[0]
[docs] def _list_classes(self, arguments: dict) -> Any: limit = min(int(arguments.get("limit", 20)), 100) resp = requests.get( FDA_LABEL_URL, params={ "count": "openfda.pharm_class_epc.exact", "limit": limit, }, timeout=20, ) resp.raise_for_status() data = resp.json() results = data.get("results", []) return [{"drug_class": r["term"], "count": r["count"]} for r in results]