virtual-clinic
Python client for the Virtual Clinic REST API — multi-turn conversations with LLM-based simulated patient agents powered by Synthea-generated electronic health records.
Installation
pip install virtual-clinic
Or install from source (for development):
# From the repo root
cd packages/client
uv pip install -e .
Quick Start
from virtual_clinic import VirtualClinic
client = VirtualClinic(
base_url="https://virtual-clinic-api.vercel.app",
token="your-jwt-token", # provided by workshop organizers
)
# 1. List available patients (requires admin token)
patients = client.patients.list(page=1, limit=10)
for p in patients.data:
print(f"{p.first} {p.last} — {p.gender}, born {p.birth_date}")
print(f"Page {patients.pagination.page} of {patients.pagination.total_pages}")
# 2. Inspect a patient's full EHR
detail = client.patients.get(patients.data[0].id)
print(f"Active conditions: {detail.summary.active_conditions}")
print(f"Active medications: {detail.summary.active_medications}")
print(f"Allergies: {detail.summary.allergies}")
# 3. Start a diagnostic conversation
convo = client.conversations.create(
patient_id=patients.data[0].id,
task_type="diagnosis",
)
print(f"Conversation {convo.id} started with {convo.patient_name}")
# 4. Interview the simulated patient
reply = client.conversations.send_message(
convo.id,
content="Hello, what brings you in today?",
)
print(f"Patient: {reply.content}")
# Continue the conversation...
reply = client.conversations.send_message(
convo.id,
content="How long have you been experiencing these symptoms?",
)
print(f"Patient: {reply.content}")
# 5. Review the full conversation history
history = client.conversations.get(convo.id)
for msg in history.messages:
print(f"[{msg.role}] {msg.content[:80]}...")
# 6. Clean up
client.close()
Context Manager
The client supports the context manager protocol for automatic cleanup:
with VirtualClinic(base_url="...", token="...") as client:
health = client.health()
print(health.status, health.database)
API Reference
VirtualClinic(*, base_url, token, timeout=60.0)
The main client. All parameters are keyword-only.
| Parameter | Type | Default | Description |
|---|---|---|---|
base_url |
str |
"https://virtual-clinic-api.vercel.app" |
API base URL |
token |
str |
(required) | JWT bearer token |
timeout |
float |
60.0 |
Request timeout in seconds |
Health
client.health() -> HealthStatus
Check API health (public, no auth required).
Patients (admin token required)
client.patients.list(*, page=1, limit=20) -> PaginatedResponse[PatientSummary]
client.patients.get(patient_id: str) -> PatientDetail
Conversations
client.conversations.list(*, page=1, limit=20, patient_id=None, task_type=None) -> PaginatedResponse[ConversationSummary]
client.conversations.create(*, patient_id, task_type, metadata=None) -> CreatedConversation
client.conversations.get(conversation_id: str) -> ConversationWithMessages
client.conversations.send_message(conversation_id: str, *, content: str) -> AssistantMessage
Task Types
| Value | Description |
|---|---|
"diagnosis" |
Interview the patient to propose a diagnosis |
"treatment" |
Interview the patient to predict the treatment plan |
"event" |
Interview the patient to estimate probability of a clinical event |
Error Handling
All API errors raise typed exceptions:
from virtual_clinic import (
VirtualClinicError, # base class — catch-all
AuthenticationError, # 401 — invalid or missing token
ForbiddenError, # 403 — insufficient permissions
NotFoundError, # 404 — resource not found
ValidationError, # 400 — invalid request
ServerError, # 5xx — server error
ConnectionError, # network/DNS/timeout failure
)
try:
patient = client.patients.get("nonexistent-uuid")
except NotFoundError as e:
print(f"Patient not found: {e.message}")
except AuthenticationError:
print("Check your token!")
except VirtualClinicError as e:
print(f"Something went wrong: {e.message}")
API error exceptions expose these attributes:
| Attribute | Type | Description |
|---|---|---|
status_code |
int |
HTTP status code |
message |
str |
Error message from the API |
details |
dict | None |
Validation error details (if any) |
body |
dict | None |
Raw response body |
Models
All API responses are returned as Pydantic v2 models with full type hints. This gives you autocomplete in IDEs, runtime validation, and easy serialization:
# Convert to dict
patient_dict = patient.model_dump()
# Convert to JSON string
patient_json = patient.model_dump_json()
# Access fields with autocomplete
print(detail.summary.active_conditions)
print(detail.patient.first, detail.patient.last)
Requirements
- Python >= 3.10
httpx >= 0.27pydantic >= 2.0
Release files for virtual-clinic 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| virtual_clinic-0.2.0.tar.gz | 8.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| virtual_clinic-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.4 kB
Release files / virtual_clinic-0.2.0.tar.gz
| Download URL | virtual_clinic-0.2.0.tar.gz |
|---|---|
| Size | 8.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
140c2c2a3d5f45f5d537c31d9defc6f7a1ce2c85f357ebd9a73169b28b5461a3
|
|
BLAKE2b-256 checksum How to use checksums |
80bbc4cceda0c8a100b3d771032bdf196f73f4286dad8534927db882b6f70b72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 15, 2026.
Transparency logRelease files / virtual_clinic-0.2.0-py3-none-any.whl
| Download URL | virtual_clinic-0.2.0-py3-none-any.whl |
|---|---|
| Size | 11.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e4d3134bd021514c76bfe7ba9c9f222b0239de2a57e43128d4a1972d915b0a89
|
|
BLAKE2b-256 checksum How to use checksums |
6226bf404a3531a3b10793060ddf9608a02d9c9ca29a430ae91d3de23a1a0aa5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 15, 2026.
Transparency log