Inspiration Every clinician has read a note that mentions a condition no one ever added to the problem list. A statin started but never prescribed. An A1c of 9 with no follow-up Observation. The note says one thing, the chart says another. The next person to walk in has to catch the difference. We built something that catches it for them.
What it does The Reconciliation Agent reads a patient's clinical notes from FHIR DocumentReference resources and compares them against the structured record: conditions, medications, observations, care plans, goals. It returns a single JSON object listing every discrepancy with the verbatim note quote, the matching FHIR resource (or "absent"), a severity, and a suggested action. The output is JSON only. No prose, no markdown fences. A downstream UI can render it as a worklist.
How we built it TypeScript on Node.js. Google ADK as the agent runtime, A2A protocol for transport, Gemini 2.5 Flash for reasoning. A beforeModelCallback hook moves FHIR credentials from A2A message metadata into session state so the tools can authenticate to the workspace's FHIR server without exposing credentials to the model. An afterModelCallback strips stray markdown fences. The whole thing runs in a Docker container on Railway, behind a public HTTPS URL that Prompt Opinion connects to as an external A2A agent.
Challenges we ran into
Prompt Opinion uses gRPC-gateway JSON encoding with oneof payload wrapping, PascalCase RPC method names, and uppercase proto enum strings like TASK_STATE_COMPLETED and ROLE_USER. The @a2a-js/sdk we built on emits spec-form JSON. We wrote three Express middleware layers to translate: method aliasing on inbound, oneof wrapping and enum string conversion on outbound. The protocol mismatch wasn't documented anywhere. We found each rule by reading ngrok request dumps after PO rejected our responses. We also wrote a custom BaseLlm adapter for OpenAI-compatible endpoints when we tested swapping models, which meant converting Gemini's uppercase schema types to JSON Schema lowercase.
Accomplishments that we're proud of
It works end-to-end with a strict JSON output contract. Same shape every time. No markdown drift, no hallucinated fields. The model layer is hot-swappable between Gemini and any OpenAI-compatible endpoint without touching agent code. The protocol shim makes the agent reusable for any Prompt Opinion workspace. The agent runs in production on Railway with a stable HTTPS URL the workspace connects to anytime.
What we learned
A2A is a young protocol with two competing encodings in the wild, and the gap between what the spec says and what platforms accept is wide. ADK's callback architecture, separating credential extraction, model reasoning, and output post-processing into clean hooks, made enforcing the JSON contract straightforward. Uploading a FHIR DocumentReference without a subject.reference linking it to the patient leaves it floating in the workspace; the agent returns zero findings until the link is set.
What's next for FHIR Reconciliation Agent
Write-back so the agent can propose FHIR patches the clinician one-clicks into the record. Confidence scores per finding. Multi-note batch reconciliation across a patient's whole history, not just the most recent visit. Severity tuning calibrated to actual safety signals: missed cancer screening windows, drug-drug interaction context, contraindicated medication starts. An eval harness with synthetic patients seeded with known gaps so we can measure precision and recall.
Log in or sign up for Devpost to join the conversation.