# FHIR Agent Tools

LLM-agent-ready extraction functions for FHIR JSON resources. Parse FHIR API responses and extract structured data for use in AI agents.

## Installation

```bash
pip install fhir-agent-tools
```

## Quick Start

```python
from fhir_agent_tools import get_patient_summary, get_bundle_entries

# Parse a Patient resource
patient_json = '{"resourceType":"Patient","id":"123","name":[{"family":"Smith","given":["John"]}],"birthDate":"1990-01-15"}'
result = get_patient_summary(patient_json)
# result: {"success": True, "data": {"id": "123", "name": "Smith, John", "birthDate": "1990-01-15", ...}}

# Parse a Bundle (search results)
bundle_json = '{"resourceType":"Bundle","type":"searchset","entry":[{"resource":{...}}]}'
entries = get_bundle_entries(bundle_json)
# entries: {"success": True, "data": [<list of resources>]}
```

## Error Handling

All extractors return a structured result—they never raise by default:

```python
# Success
{"success": True, "data": {...}}

# Error (invalid JSON, wrong resource type, validation failure)
{"success": False, "error": {"type": "parse_error", "message": "...", "details": ...}}
```

For programmatic use with exceptions:

```python
from fhir_agent_tools import get_patient_summary, FhirExtractError

try:
    data = get_patient_summary(patient_json, raise_on_error=True)
except FhirExtractError as e:
    print(e.error)
```

## Agent Integration

### OpenAI Function Calling

```python
from openai import OpenAI
from fhir_agent_tools import get_tools, get_extractor_functions

client = OpenAI()

# Get tool definitions for the API
tools = get_tools()

# When the model calls a tool, execute it:
functions = {name: fn for name, fn in get_extractor_functions()}
# For extract_resources_by_type, the function expects (fhir_json, resource_type)
```

### LangChain

```python
from langchain.tools import StructuredTool
from fhir_agent_tools import get_tools, get_extractor_functions

# Convert to LangChain tools
lc_tools = []
for name, fn in get_extractor_functions():
    if name == "extract_resources_by_type":
        lc_tools.append(StructuredTool.from_function(
            func=lambda j, rt: fn(j, rt),
            name=name,
            description=next(t["function"]["description"] for t in get_tools() if t["function"]["name"] == name),
        ))
    else:
        lc_tools.append(StructuredTool.from_function(
            func=fn,
            name=name,
            description=next(t["function"]["description"] for t in get_tools() if t["function"]["name"] == name),
        ))
```

## Supported Resources

| Resource | Extractors |
|----------|------------|
| Bundle | `get_bundle_entries`, `get_resources_by_type`, `get_bundle_total` |
| Patient | `get_patient_summary`, `get_patient_name`, `get_patient_identifiers`, `get_patient_telecom`, `get_patient_address` |
| Practitioner | `get_practitioner_summary`, `get_practitioner_name`, `get_practitioner_identifiers` |
| Observation | `get_observation_summary`, `get_observation_value`, `get_observation_code`, `get_observation_effective` |
| Condition | `get_condition_summary`, `get_condition_code`, `get_condition_onset`, `get_condition_clinical_status` |
| MedicationRequest | `get_medication_request_summary`, `get_medication_request_medication`, `get_medication_request_dosage` |
| MedicationStatement | `get_medication_statement_summary`, `get_medication_statement_medication` |
| Encounter | `get_encounter_summary`, `get_encounter_type`, `get_encounter_period`, `get_encounter_status` |
| AllergyIntolerance | `get_allergy_summary`, `get_allergy_substance`, `get_allergy_reaction`, `get_allergy_criticality` |
| DiagnosticReport | `get_diagnostic_report_summary`, `get_diagnostic_report_code`, `get_diagnostic_report_conclusion` |
| Immunization | `get_immunization_summary`, `get_immunization_vaccine`, `get_immunization_date` |
| CarePlan | `get_care_plan_summary`, `get_care_plan_activities` |
| CareTeam | `get_care_team_summary`, `get_care_team_members` |
| Goal | `get_goal_summary`, `get_goal_description`, `get_goal_target` |
| Procedure | `get_procedure_summary`, `get_procedure_code`, `get_procedure_performed` |
| FamilyMemberHistory | `get_family_history_summary`, `get_family_history_conditions` |
| Coverage | `get_coverage_summary`, `get_coverage_payor`, `get_coverage_period` |
| Organization | `get_organization_summary`, `get_organization_name`, `get_organization_identifier` |
| Location | `get_location_summary`, `get_location_name`, `get_location_address` |

## FHIR Version

Uses FHIR R4B (4.3.0) via [fhir.resources](https://pypi.org/project/fhir.resources/). Compatible with R4.0.1 API responses.

## License

MIT
