HealthcareParse → Extract

Intake Form

Extracts patient demographics, symptoms, and cardiac medical history from health appraisals.

Ship it with Extend

Live pipeline

a real document, processed end to end · view only
Source documentpatient_intake__aggarwal_cardiology_new_patient_packet-8fJ1O5b6.pdf

Step-by-step

An intake form is a comprehensive health questionnaire completed by patients in care settings that documents demographics, chief complaints, symptom assessment, vital signs, medical history, surgical procedures, hospitalizations, and referral information to support clinical evaluation and diagnosis. This template takes in Intake Forms and outputs markdown (.md) capturing the form's full text and layout, and JSON (.json) with structured patient demographics, symptoms, medical history, surgeries, hospitalizations, and clinical details per the extraction schema by using Extend's Parse, Extract primitives.

Input
Intake Forms
Compatible document types (full list)
.pdf.docx.xlsx.png.jpg.jpeg.tiff.tif.svg.heic.heif.bmp.gif.webp.psd.xls.xltm.xltx.ods.doc.wpd.dotx.odt.pptx.ppt.ppm.csv.txt.html.xml.rtf.lis.md.eml.pcx
Step 1

Parse

Converts the document into clean, layout-aware markdown plus structured blocks with spatial metadata.

InputSource document — PDF, image, spreadsheet, presentation, or scan
Config
blockOptions.text.agentic.enabledtruechanged
chunkingStrategy.type"document"
engine"parse_performance"
OutputMarkdown chunked by page or section, plus typed blocks (text, table, figure) with bounding boxes

You can learn more about Parse configuration in Extend's Parse documentation.

Step 2

Extract

Pulls a defined set of fields from the document and returns them as structured JSON matching a schema.

InputOutput of the Parse step
Config
schemacustom schema — 17 fieldschanged
advancedOptions.advancedMultimodalEnabledtruechanged
advancedOptions.reviewAgent.enabledtruechanged
baseProcessor"extraction_performance"
OutputJSON shaped to the extraction schema, with per-field confidence scores and citations grounding each value to its source location

You can learn more about Extract configuration in Extend's Extract documentation.

Example code

{
  "name": "Intake Form Processing Pipeline",
  "steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [
        {
          "step": "parse1"
        }
      ]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {
            "text": {
              "agentic": {
                "enabled": true
              }
            }
          },
          "chunkingStrategy": {
            "type": "document"
          }
        }
      },
      "next": [
        {
          "step": "extraction2"
        }
      ]
    },
    {
      "name": "extraction2",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "required": [
              "age",
              "sex",
              "height",
              "weight",
              "symptoms",
              "form_date",
              "surgeries",
              "referred_by",
              "patient_name",
              "date_of_birth",
              "marital_status",
              "chief_complaint",
              "medical_history",
              "hospitalizations",
              "medical_record_number",
              "primary_medical_doctor",
              "history_of_present_illness"
            ],
            "properties": {
              "age": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."
              },
              "sex": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."
              },
              "height": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."
              },
              "weight": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."
              },
              "symptoms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "present",
                    "symptom_name",
                    "symptom_details"
                  ],
                  "properties": {
                    "present": {
                      "type": [
                        "boolean",
                        "null"
                      ],
                      "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."
                    },
                    "symptom_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."
                    },
                    "symptom_details": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
              },
              "form_date": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided.",
                "extend:type": "date"
              },
              "surgeries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "surgery_date",
                    "surgery_name"
                  ],
                  "properties": {
                    "surgery_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."
                    },
                    "surgery_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
              },
              "referred_by": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."
              },
              "patient_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."
              },
              "date_of_birth": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc.",
                "extend:type": "date"
              },
              "marital_status": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."
              },
              "chief_complaint": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."
              },
              "medical_history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "present",
                    "condition_name",
                    "diagnosis_date"
                  ],
                  "properties": {
                    "present": {
                      "type": [
                        "boolean",
                        "null"
                      ],
                      "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."
                    },
                    "condition_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."
                    },
                    "diagnosis_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
              },
              "hospitalizations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "hospitalization_date",
                    "hospitalization_reason"
                  ],
                  "properties": {
                    "hospitalization_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."
                    },
                    "hospitalization_reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
              },
              "medical_record_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."
              },
              "primary_medical_doctor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."
              },
              "history_of_present_illness": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."
              }
            },
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {
              "enabled": true
            },
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
}
# Cardiology Intake Form Processing — Extend AI Skill

## What this pipeline does

Converts a cardiology clinic intake form (PDF, scan, or handwritten) into structured patient data by first parsing it to markdown with agentic OCR, then extracting 17 core fields (demographics, vital signs, symptoms, medical history, hospitalizations, surgeries) into a validated JSON object. The pipeline uses performance-grade extraction with a multimodal review agent to handle complex layouts, handwriting, and checkbox-to-boolean conversions.

## When to use this

- **Multi-page clinic intake forms** with mixed digital and scanned sections, requiring high accuracy on handwriting and checkboxes
- **Cardiology-specific workflows** where symptom presence/absence, condition dates, and surgery history are critical for clinical decision support
- **Bulk onboarding** of new patients into an EHR system, where structured data export to HL7 or FHIR is downstream
- **Quality assurance** in telemedicine platforms, where intake data gates appointment eligibility and risk stratification
- **Research cohorts** requiring standardized extraction of demographics, comorbidities, and hospitalization events across hundreds of forms

## Processor pipeline

### Step 1: Parse (agentic OCR)
**Processor:** `parse_performance` with `agentic: true` text extraction  
**Purpose:** Convert form image/PDF → markdown with semantic chunking, preserving form structure and extracting text from handwritten fields.

**Config rationale:**
- `agentic: true` — handles handwriting, skewed text, and complex checkboxes better than light mode
- `chunkingStrategy: "document"` — keeps form sections intact (demographics, symptoms, history blocks) rather than naive paragraph splits
- Markdown output feeds cleanly into extraction schema

### Step 2: Extract (structured fields)
**Processor:** `extraction_performance` with `reviewAgent: enabled` and `advancedMultimodalEnabled: true`  
**Purpose:** Parse markdown into 17 fields: 5 primitives (age, sex, height, weight, MRN), 4 complex arrays (symptoms, medical_history, surgeries, hospitalizations), 8 text fields (names, dates, narrative).

**Config rationale:**
- `baseProcessor: "extraction_performance"` — slower than light mode but essential for nullable booleans (symptom presence), date parsing, and array disambiguation
- `reviewAgent: enabled` — catches extraction errors (e.g., confusing two dates, missing array items) before output
- `advancedMultimodalEnabled: true` — re-analyzes original form image alongside markdown to confirm extracted values, especially for handwritten fields
- Schema includes `additionalProperties: false` to reject unexpected fields and enforce strict cardiology template compliance

---

## TypeScript implementation



---

## CLI equivalent

```bash
# Step 1: Parse intake form to markdown
extend parse intake_form.pdf \
  --blockOptions '{"text":{"agentic":{"enabled":true}}}' \
  --chunkingStrategy '{"type":"document"}' \
  > parsed_output.md

# Step 2: Extract structured fields
extend extract intake_form.pdf \
  --schema schema.json \
  --baseProcessor extraction_performance \
  --advancedOptions '{
    "reviewAgent": {"enabled": true},
    "advancedMultimodalEnabled": true
  }' \
  > extracted_intake.json
```

**schema.json** (save the full Zod-equivalent JSON schema from the TypeScript code above):
```json
{
  "type": "object",
  "properties": {
    "patient_name": { "type": ["string", "null"] },
    "medical_record_number": { "type": ["string", "null"] },
    "date_of_birth": { "type": ["string", "null"], "extend:type": "date" },
    ...
  },
  "required": ["patient_name", "medical_record_number", ..., "surgeries"],
  "additionalProperties": false
}
```

---

## Schema

**Root structure:** Object with 17 required fields, no additional properties allowed. All primitives (string, integer, number, boolean) are nullable. Arrays and nested objects are NOT nullable.

### Primitives (7 fields)
| Field | Type | Notes |
|-------|------|-------|
| `patient_name` | `string \| null` | Full legal name; primary patient identifier. Critical for record matching. |
| `medical_record_number` | `string \| null` | Alphanumeric facility ID; gates access to EHR. Include all special characters. |
| `date_of_birth` | `string \| null` | ISO date (YYYY-MM-DD). If only age provided, set null—do NOT invent a DOB. |
| `age` | `integer \| null` | Years at form completion. If DOB provided, extract rather than trusting form-stated age (may be stale). |
| `sex` | `string \| null` | One of: "Male", "Female", "Other", "Declined", or exact form text. Keep as written. |
| `marital_status` | `string \| null` | Values like "Single", "Married", "Widowed", "Divorced", "Domestic Partnership". Exact form text. |
| `form_date` | `string \| null` | ISO date (YYYY-MM-DD). When form was filled, not when scanned. Critical for temporal alignment. |

### Text/Narrative (4 fields)
| Field | Type | Notes |
|-------|------|-------|
| `chief_complaint` | `string \| null` | 1–3 sentence reason for visit in patient's own words (e.g., "chest pain for 2 days"). Extracted directly from "CC" or "Chief Complaint" box. |
| `history_of_present_illness` | `string \| null` | Long-form narrative of symptom onset, duration, context, prior treatments. May span multiple form lines. Preserve chronology and detail. |
| `referred_by` | `string \| null` | Provider name or clinic name making the referral. Include title if present (e.g., "Dr. Jane Smith, Cardiology Associates"). |
| `primary_medical_doctor` | `string \| null` | Patient's ongoing primary care provider. Extract exactly as written (name, specialty if listed). Null if not named on form. |

### Vital & Anthropometric (2 fields)
| Field | Type | Notes |
|-------|------|-------|
| `height
import { ExtendClient, extendDate } from "extend-ai";
import { z } from "zod";
import fs from "fs";
import path from "path";

const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });

// Define extraction schema using Zod for full type safety
const intakeFormSchema = z.object({
  patient_name: z.string().nullable().describe(
    "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care."
  ),
  medical_record_number: z.string().nullable().describe(
    "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar."
  ),
  date_of_birth: extendDate().describe(
    "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."
  ),
  age: z.number().int().nullable().describe(
    "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."
  ),
  sex: z.string().nullable().describe(
    "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."
  ),
  marital_status: z.string().nullable().describe(
    "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."
  ),
  height: z.string().nullable().describe(
    "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."
  ),
  weight: z.number().nullable().describe(
    "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."
  ),
  form_date: extendDate().describe(
    "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."
  ),
  chief_complaint: z.string().nullable().describe(
    "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."
  ),
  history_of_present_illness: z.string().nullable().describe(
    "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."
  ),
  referred_by: z.string().nullable().describe(
    "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."
  ),
  primary_medical_doctor: z.string().nullable().describe(
    "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."
  ),
  symptoms: z.array(
    z.object({
      present: z.boolean().nullable().describe(
        "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."
      ),
      symptom_name: z.string().nullable().describe(
        "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."
      ),
      symptom_details: z.string().nullable().describe(
        "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."
      ),
    })
  ).describe(
    "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
  ),
  medical_history: z.array(
    z.object({
      present: z.boolean().nullable().describe(
        "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."
      ),
      condition_name: z.string().nullable().describe(
        "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."
      ),
      diagnosis_date: z.string().nullable().describe(
        "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."
      ),
    })
  ).describe(
    "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
  ),
  hospitalizations: z.array(
    z.object({
      hospitalization_date: z.string().nullable().describe(
        "The date, year, or time period of the hospitalization, if provided. May be partial or missing."
      ),
      hospitalization_reason: z.string().nullable().describe(
        "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."
      ),
    })
  ).describe(
    "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
  ),
  surgeries: z.array(
    z.object({
      surgery_date: z.string().nullable().describe(
        "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."
      ),
      surgery_name: z.string().nullable().describe(
        "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."
      ),
    })
  ).describe(
    "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
  ),
});

type IntakeFormData = z.infer<typeof intakeFormSchema>;

/**
 * Process a cardiology intake form through parse + extract pipeline.
 * Handles local files by converting to base64 data URL.
 */
async function processIntakeForm(filePath: string): Promise<IntakeFormData> {
  console.log(`Processing intake form: ${filePath}`);

  // Convert local file to base64 data URL for SDK compatibility
  const fileBuffer = fs.readFileSync(filePath);
  const base64Data = fileBuffer.toString("base64");
  const fileExt = path.extname(filePath).toLowerCase().slice(1);
  const mimeType = fileExt === "pdf" ? "application/pdf" : "image/jpeg";
  const dataUrl = `data:${mimeType};base64,${base64Data}`;

  // Step 1: Parse intake form to markdown with agentic OCR
  console.log("Step 1: Parsing form with agentic OCR...");
  const parseRun = await client.parseRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      blockOptions: {
        text: {
          agentic: {
            enabled: true,
          },
        },
      },
      chunkingStrategy: {
        type: "document",
      },
    },
  });

  if (parseRun.status !== "PROCESSED") {
    throw new Error(`Parse failed with status: ${parseRun.status}`);
  }

  // Collect parsed markdown for logging/debugging
  const parsedMarkdown = parseRun.output.chunks
    .map((chunk) => chunk.content)
    .join("\n\n");
  console.log(
    `Parsed markdown (first 500 chars): ${parsedMarkdown.substring(0, 500)}...`
  );

  // Step 2: Extract structured fields using performance processor + review agent
  console.log("Step 2: Extracting structured fields...");
  const extractRun = await client.extractRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      schema: intakeFormSchema,
      baseProcessor: "extraction_performance",
      advancedOptions: {
        reviewAgent: {
          enabled: true,
        },
        advancedMultimodalEnabled: true,
      },
    },
  });

  if (extractRun.status !== "PROCESSED") {
    throw new Error(`Extraction failed with status: ${extractRun.status}`);
  }

  const extracted = extractRun.output.value as IntakeFormData;

  console.log("✓ Extraction complete");
  console.log(`Patient: ${extracted.patient_name} (MRN: ${extracted.medical_record_number})`);
  console.log(`Age: ${extracted.age}, Sex: ${extracted.sex}`);
  console.log(`Chief Complaint: ${extracted.chief_complaint}`);
  console.log(`Symptoms found: ${extracted.symptoms.length}`);
  console.log(`Medical conditions: ${extracted.medical_history.length}`);
  console.log(`Hospitalizations: ${extracted.hospitalizations.length}`);
  console.log(`Surgeries: ${extracted.surgeries.length}`);

  return extracted;
}

// Main entry point for testing
async function main() {
  const testFilePath = process.argv[2] || "./intake_form.pdf";

  if (!fs.existsSync(testFilePath)) {
    console.error(`File not found: ${testFilePath}`);
    process.exit(1);
  }

  const result = await processIntakeForm(testFilePath);

  console.log("\nFull extracted data:");
  console.log(JSON.stringify(result, null, 2));
}

main().catch((err) => {
  console.error("Error:", err.message);
  process.exit(1);
});

export { processIntakeForm, intakeFormSchema, type IntakeFormData };
import os
import sys
import json
import base64
from pathlib import Path
from typing import TypedDict, Optional, List

from extend_ai import Extend


# Define extraction schema as a plain dict matching the JSON schema
intake_form_schema = {
    "type": "object",
    "properties": {
        "patient_name": {
            "type": ["string", "null"],
            "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care."
        },
        "medical_record_number": {
            "type": ["string", "null"],
            "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar."
        },
        "date_of_birth": {
            "type": ["string", "null"],
            "extend:type": "date",
            "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."
        },
        "age": {
            "type": ["integer", "null"],
            "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."
        },
        "sex": {
            "type": ["string", "null"],
            "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."
        },
        "marital_status": {
            "type": ["string", "null"],
            "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."
        },
        "height": {
            "type": ["string", "null"],
            "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."
        },
        "weight": {
            "type": ["number", "null"],
            "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."
        },
        "form_date": {
            "type": ["string", "null"],
            "extend:type": "date",
            "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."
        },
        "chief_complaint": {
            "type": ["string", "null"],
            "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."
        },
        "history_of_present_illness": {
            "type": ["string", "null"],
            "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."
        },
        "referred_by": {
            "type": ["string", "null"],
            "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."
        },
        "primary_medical_doctor": {
            "type": ["string", "null"],
            "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."
        },
        "symptoms": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "present": {
                        "type": ["boolean", "null"],
                        "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."
                    },
                    "symptom_name": {
                        "type": ["string", "null"],
                        "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."
                    },
                    "symptom_details": {
                        "type": ["string", "null"],
                        "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."
                    },
                },
                "additionalProperties": False,
                "required": ["present", "symptom_name", "symptom_details"]
            },
            "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
        },
        "medical_history": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "present": {
                        "type": ["boolean", "null"],
                        "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."
                    },
                    "condition_name": {
                        "type": ["string", "null"],
                        "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."
                    },
                    "diagnosis_date": {
                        "type": ["string", "null"],
                        "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."
                    },
                },
                "additionalProperties": False,
                "required": ["present", "condition_name", "diagnosis_date"]
            },
            "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
        },
        "hospitalizations": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "hospitalization_date": {
                        "type": ["string", "null"],
                        "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."
                    },
                    "hospitalization_reason": {
                        "type": ["string", "null"],
                        "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."
                    },
                },
                "additionalProperties": False,
                "required": ["hospitalization_date", "hospitalization_reason"]
            },
            "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
        },
        "surgeries": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "surgery_date": {
                        "type": ["string", "null"],
                        "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."
                    },
                    "surgery_name": {
                        "type": ["string", "null"],
                        "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."
                    },
                },
                "additionalProperties": False,
                "required": ["surgery_date", "surgery_name"]
            },
            "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
        },
    },
    "required": [
        "age", "sex", "height", "weight", "symptoms", "form_date", "surgeries",
        "referred_by", "patient_name", "date_of_birth", "marital_status",
        "chief_complaint", "medical_history", "hospitalizations",
        "medical_record_number", "primary_medical_doctor", "history_of_present_illness"
    ],
    "additionalProperties": False
}


def process_intake_form(file_path: str) -> dict:
    """
    Process a cardiology intake form through parse + extract pipeline.
    Handles local files by converting to base64 data URL.
    """
    print(f"Processing intake form: {file_path}")

    # Convert local file to base64 data URL for SDK compatibility
    file_buffer = Path(file_path).read_bytes()
    base64_data = base64.b64encode(file_buffer).decode("utf-8")
    file_ext = Path(file_path).suffix.lower().lstrip(".")
    mime_type = "application/pdf" if file_ext == "pdf" else "image/jpeg"
    data_url = f"data:{mime_type};base64,{base64_data}"

    client = Extend(token=os.environ["EXTEND_API_KEY"])

    # Step 1: Parse intake form to markdown with agentic OCR
    print("Step 1: Parsing form with agentic OCR...")
    parse_run = client.parse_runs.create_and_poll(
        file={"url": data_url},
        config={
            "blockOptions": {
                "text": {
                    "agentic": {
                        "enabled": True,
                    },
                },
            },
            "chunkingStrategy": {
                "type": "document",
            },
        },
        timeout_ms=0,
    )

    if parse_run.status != "PROCESSED":
        raise Exception(f"Parse failed with status: {parse_run.status}")

    # Collect parsed markdown for logging/debugging
    parsed_markdown = "\n\n".join(chunk.content for chunk in parse_run.output.chunks)
    print(f"Parsed markdown (first 500 chars): {parsed_markdown[:500]}...")

    # Step 2: Extract structured fields using performance processor + review agent
    print("Step 2: Extracting structured fields...")
    extract_run = client.extract_runs.create_and_poll(
        file={"url": data_url},
        config={
            "schema": intake_form_schema,
            "baseProcessor": "extraction_performance",
            "advancedOptions": {
                "reviewAgent": {
                    "enabled": True,
                },
                "advancedMultimodalEnabled": True,
            },
        },
        timeout_ms=0,
    )

    if extract_run.status != "PROCESSED":
        raise Exception(f"Extraction failed with status: {extract_run.status}")

    extracted = extract_run.output.value

    print("✓ Extraction complete")
    print(f"Patient: {extracted.get('patient_name')} (MRN: {extracted.get('medical_record_number')})")
    print(f"Age: {extracted.get('age')}, Sex: {extracted.get('sex')}")
    print(f"Chief Complaint: {extracted.get('chief_complaint')}")
    print(f"Symptoms found: {len(extracted.get('symptoms', []))}")
    print(f"Medical conditions: {len(extracted.get('medical_history', []))}")
    print(f"Hospitalizations: {len(extracted.get('hospitalizations', []))}")
    print(f"Surgeries: {len(extracted.get('surgeries', []))}")

    return extracted


def main():
    test_file_path = sys.argv[1] if len(sys.argv) > 1 else "./intake_form.pdf"

    if not Path(test_file_path).exists():
        print(f"File not found: {test_file_path}")
        sys.exit(1)

    result = process_intake_form(test_file_path)

    print("\nFull extracted data:")
    print(json.dumps(result, indent=2))


if __name__ == "__main__":
    main()
// Extend AI REST API client for intake form processing.
// Extend does NOT publish an official Java SDK; this code calls the REST API directly
// using only java.net.http.HttpClient (no third-party HTTP or JSON libraries).

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class IntakeFormProcessor {

  private static final String API_BASE_URL = "https://api.extend.ai";
  private static final String API_KEY = System.getenv("EXTEND_API_KEY");
  private final HttpClient httpClient;

  public IntakeFormProcessor() {
    this.httpClient = HttpClient.newHttpClient();
  }

  /**
   * Represents extracted intake form data matching the schema.
   */
  public static class IntakeFormData {
    public String patientName;
    public String medicalRecordNumber;
    public String dateOfBirth;
    public Integer age;
    public String sex;
    public String maritalStatus;
    public String height;
    public Double weight;
    public String formDate;
    public String chiefComplaint;
    public String historyOfPresentIllness;
    public String referredBy;
    public String primaryMedicalDoctor;
    public List<Symptom> symptoms;
    public List<MedicalCondition> medicalHistory;
    public List<Hospitalization> hospitalizations;
    public List<Surgery> surgeries;
  }

  public static class Symptom {
    public Boolean present;
    public String symptomName;
    public String symptomDetails;
  }

  public static class MedicalCondition {
    public Boolean present;
    public String conditionName;
    public String diagnosisDate;
  }

  public static class Hospitalization {
    public String hospitalizationDate;
    public String hospitalizationReason;
  }

  public static class Surgery {
    public String surgeryDate;
    public String surgeryName;
  }

  /**
   * Convert local file to base64 data URL.
   */
  private String fileToDataUrl(String filePath) throws IOException {
    byte[] fileBytes = Files.readAllBytes(Paths.get(filePath));
    String base64Data = Base64.getEncoder().encodeToString(fileBytes);
    String mimeType = filePath.toLowerCase().endsWith(".pdf") ? "application/pdf" : "image/jpeg";
    return "data:" + mimeType + ";base64," + base64Data;
  }

  /**
   * Create and poll a parse run for the intake form.
   */
  private String parseIntakeForm(String dataUrl) throws IOException, InterruptedException {
    System.out.println("Step 1: Parsing form with agentic OCR...");

    String parseRequestBody = buildParseRequestBody(dataUrl);
    String parseRunId = createParseRun(parseRequestBody);
    String parseStatus = pollParseRun(parseRunId);

    if (!"PROCESSED".equals(parseStatus)) {
      throw new RuntimeException("Parse failed with status: " + parseStatus);
    }

    String parsedMarkdown = getParseRunOutput(parseRunId);
    System.out.println("Parsed markdown (first 500 chars): "
        + parsedMarkdown.substring(0, Math.min(500, parsedMarkdown.length())) + "...");

    return parsedMarkdown;
  }

  /**
   * Create and poll an extract run for structured field extraction.
   */
  private IntakeFormData extractIntakeForm(String dataUrl) throws IOException, InterruptedException {
    System.out.println("Step 2: Extracting structured fields...");

    String extractRequestBody = buildExtractRequestBody(dataUrl);
    String extractRunId = createExtractRun(extractRequestBody);
    String extractStatus = pollExtractRun(extractRunId);

    if (!"PROCESSED".equals(extractStatus)) {
      throw new RuntimeException("Extraction failed with status: " + extractStatus);
    }

    IntakeFormData extracted = getExtractRunOutput(extractRunId);
    System.out.println("✓ Extraction complete");
    System.out.println("Patient: " + extracted.patientName + " (MRN: " + extracted.medicalRecordNumber + ")");
    System.out.println("Age: " + extracted.age + ", Sex: " + extracted.sex);
    System.out.println("Chief Complaint: " + extracted.chiefComplaint);
    System.out.println("Symptoms found: " + extracted.symptoms.size());
    System.out.println("Medical conditions: " + extracted.medicalHistory.size());
    System.out.println("Hospitalizations: " + extracted.hospitalizations.size());
    System.out.println("Surgeries: " + extracted.surgeries.size());

    return extracted;
  }

  /**
   * Process intake form through parse + extract pipeline.
   */
  public IntakeFormData processIntakeForm(String filePath) throws IOException, InterruptedException {
    System.out.println("Processing intake form: " + filePath);

    String dataUrl = fileToDataUrl(filePath);
    parseIntakeForm(dataUrl);
    return extractIntakeForm(dataUrl);
  }

  private String buildParseRequestBody(String dataUrl) {
    return "{"
        + "\"file\":{\"url\":\"" + escapeJson(dataUrl) + "\"},"
        + "\"config\":{"
        + "\"blockOptions\":{\"text\":{\"agentic\":{\"enabled\":true}}},"
        + "\"chunkingStrategy\":{\"type\":\"document\"}"
        + "}"
        + "}";
  }

  private String buildExtractRequestBody(String dataUrl) {
    return "{"
        + "\"file\":{\"url\":\"" + escapeJson(dataUrl) + "\"},"
        + "\"config\":{"
        + "\"schema\":" + getIntakeFormSchema() + ","
        + "\"baseProcessor\":\"extraction_performance\","
        + "\"advancedOptions\":{"
        + "\"reviewAgent\":{\"enabled\":true},"
        + "\"advancedMultimodalEnabled\":true"
        + "}"
        + "}"
        + "}";
  }

  private String getIntakeFormSchema() {
    return "{"
        + "\"type\":\"object\","
        + "\"properties\":{"
        + "\"patient_name\":{\"type\":[\"string\",\"null\"],\"description\":\"The full name of the patient completing or referenced in the intake form.\"},"
        + "\"medical_record_number\":{\"type\":[\"string\",\"null\"],\"description\":\"The unique identifier assigned to the patient by the healthcare provider or facility.\"},"
        + "\"date_of_birth\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\",\"description\":\"The patient's date of birth.\"},"
        + "\"age\":{\"type\":[\"integer\",\"null\"],\"description\":\"The patient's age in years at the time of form completion.\"},"
        + "\"sex\":{\"type\":[\"string\",\"null\"],\"description\":\"The patient's sex or gender as indicated on the form.\"},"
        + "\"marital_status\":{\"type\":[\"string\",\"null\"],\"description\":\"The patient's marital status as indicated on the form.\"},"
        + "\"height\":{\"type\":[\"string\",\"null\"],\"description\":\"The patient's height, typically in feet/inches or centimeters.\"},"
        + "\"weight\":{\"type\":[\"number\",\"null\"],\"description\":\"The patient's weight, typically in pounds or kilograms.\"},"
        + "\"form_date\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\",\"description\":\"The date the intake form was completed or reviewed.\"},"
        + "\"chief_complaint\":{\"type\":[\"string\",\"null\"],\"description\":\"The main reason for the patient's visit or referral.\"},"
        + "\"history_of_present_illness\":{\"type\":[\"string\",\"null\"],\"description\":\"A narrative description of the patient's current symptoms.\"},"
        + "\"referred_by\":{\"type\":[\"string\",\"null\"],\"description\":\"The name of the individual or provider who referred the patient.\"},"
        + "\"primary_medical_doctor\":{\"type\":[\"string\",\"null\"],\"description\":\"The name of the patient's primary care physician.\"},"
        + "\"symptoms\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"present\":{\"type\":[\"boolean\",\"null\"]},\"symptom_name\":{\"type\":[\"string\",\"null\"]},\"symptom_details\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"present\",\"symptom_name\",\"symptom_details\"]},\"description\":\"A list of symptoms the patient is currently experiencing.\"},"
        + "\"medical_history\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"present\":{\"type\":[\"boolean\",\"null\"]},\"condition_name\":{\"type\":[\"string\",\"null\"]},\"diagnosis_date\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"present\",\"condition_name\",\"diagnosis_date\"]},\"description\":\"A list of the patient's current and past medical conditions.\"},"
        + "\"hospitalizations\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"hospitalization_date\":{\"type\":[\"string\",\"null\"]},\"hospitalization_reason\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"hospitalization_date\",\"hospitalization_reason\"]},\"description\":\"A list of significant hospitalizations the patient has had.\"},"
        + "\"surgeries\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"surgery_date\":{\"type\":[\"string\",\"null\"]},\"surgery_name\":{\"type\":[\"string\",\"null\"]}},\"required\":[\"surgery_date\",\"surgery_name\"]},\"description\":\"A list of surgical procedures the patient has undergone.\"}"
        + "},"
        + "\"required\":[\"patient_name\",\"medical_record_number\",\"date_of_birth\",\"age\",\"sex\",\"marital_status\",\"height\",\"weight\",\"form_date\",\"chief_complaint\",\"history_of_present_illness\",\"referred_by\",\"primary_medical_doctor\",\"symptoms\",\"medical_history\",\"hospitalizations\",\"surgeries\"]"
        + "}";
  }

  private String createParseRun(String requestBody) throws IOException, InterruptedException {
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(API_BASE_URL + "/v1/parse_runs"))
        .header("Authorization", "Bearer " + API_KEY)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(requestBody))
        .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return extractFieldFromJson(response.body(), "id");
  }

  private String pollParseRun(String runId) throws IOException, InterruptedException {
    while (true) {
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create(API_BASE_URL + "/v1/parse_runs/" + runId))
          .header("Authorization", "Bearer " + API_KEY)
          .GET()
          .build();

      HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
      String status = extractFieldFromJson(response.body(), "status");

      if ("PROCESSED".equals(status) || "FAILED".equals(status)) {
        return status;
      }

      Thread.sleep(2000);
    }
  }

  private String getParseRunOutput(String runId) throws IOException, InterruptedException {
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(API_BASE_URL + "/v1/parse_runs/" + runId))
        .header("Authorization", "Bearer " + API_KEY)
        .GET()
        .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return extractChunksContent(response.body());
  }

  private String createExtractRun(String requestBody) throws IOException, InterruptedException {
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(API_BASE_URL + "/v1/extract_runs"))
        .header("Authorization", "Bearer " + API_KEY)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(requestBody))
        .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return extractFieldFromJson(response.body(), "id");
  }

  private String pollExtractRun(String runId) throws IOException, InterruptedException {
    while (true) {
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create(API_BASE_URL + "/v1/extract_runs/" + runId))
          .header("Authorization", "Bearer " + API_KEY)
          .GET()
          .build();

      HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
      String status = extractFieldFromJson(response.body(), "status");

      if ("PROCESSED".equals(status) || "FAILED".equals(status)) {
        return status;
      }

      Thread.sleep(2000);
    }
  }

  private IntakeFormData getExtractRunOutput(String runId) throws IOException, InterruptedException {
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(API_BASE_URL + "/v1/extract_runs/" + runId))
        .header("Authorization", "Bearer " + API_KEY)
        .GET()
        .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return parseExtractedData(response.body());
  }

  private String extractFieldFromJson(String json, String fieldName) {
    String searchKey = "\"" + fieldName + "\":\"";
    int startIdx = json.indexOf(searchKey);
    if (startIdx == -1) {
      return null;
    }
    startIdx += searchKey.length();
    int endIdx = json.indexOf("\"", startIdx);
    return json.substring(startIdx, endIdx);
  }

  private String extractChunksContent(String json) {
    StringBuilder content = new StringBuilder();
    int idx = 0;
    while ((idx = json.indexOf("\"content\":\"", idx)) != -1) {
      idx += 11;
      int endIdx = json.indexOf("\"", idx);
      content.append(json.substring(idx, endIdx)).append("\n\n");
      idx = endIdx;
    }
    return content.toString();
  }

  private IntakeFormData parseExtractedData(String json) {
    IntakeFormData data = new IntakeFormData();
    int outputIdx = json.indexOf("\"output\":{\"value\":{");
    if (outputIdx == -1) {
      return data;
    }

    String valueJson = json.substring(outputIdx + 19);
    valueJson = valueJson.substring(0, valueJson.lastIndexOf("}"));

    data.patientName = extractStringField(valueJson, "patient_name");
    data.medicalRecordNumber = extractStringField(valueJson, "medical_record_number");
    data.dateOfBirth = extractStringField(valueJson, "date_of_birth");
    data.age = extractIntField(valueJson, "age");
    data.sex = extractStringField(valueJson, "sex");
    data.maritalStatus = extractStringField(valueJson, "marital_status");
    data.height = extractStringField(valueJson, "height");
    data.weight = extractDoubleField(valueJson, "weight");
    data.formDate = extractStringField(valueJson, "form_date");
    data.chiefComplaint = extractStringField(valueJson, "chief_complaint");
    data.historyOfPresentIllness = extractStringField(valueJson, "history_of_present_illness");
    data.referredBy = extractStringField(valueJson, "referred_by");
    data.primaryMedicalDoctor = extractStringField(valueJson, "primary_medical_doctor");

    data.symptoms = parseSymptomArray(valueJson);
    data.medicalHistory = parseMedicalHistoryArray(valueJson);
    data.hospitalizations = parseHospitalizationArray(valueJson);
    data.surgeries = parseSurgeryArray(valueJson);

    return data;
  }

  private String extractStringField(String json, String fieldName) {
    String searchKey = "\"" + fieldName + "\":\"";
    int idx = json.indexOf(searchKey);
    if (idx == -1) {
      return null;
    }
    idx += searchKey.length();
    int endIdx = json.indexOf("\"", idx);
    if (endIdx == -1) {
      return null;
    }
    return json.substring(idx, endIdx);
  }

  private Integer extractIntField(String json, String fieldName) {
    String searchKey = "\"" + fieldName + "\":";
    int idx = json.indexOf(searchKey);
    if (idx == -1) {
      return null;
    }
    idx += searchKey.length();
    int endIdx = idx;
    while (endIdx < json.length() && Character.isDigit(json.charAt(endIdx))) {
      endIdx++;
    }
    if (endIdx == idx) {
      return null;
    }
    return Integer.parseInt(json.substring(idx, endIdx));
  }

  private Double extractDoubleField(String json, String fieldName) {
    String searchKey = "\"" + fieldName + "\":";
    int idx = json.indexOf(searchKey);
    if (idx == -1) {
      return null;
    }
    idx += searchKey.length();
    int endIdx = idx;
    while (endIdx < json.length() && (Character.isDigit(json.charAt(endIdx)) || json.charAt(endIdx) == '.')) {
      endIdx++;
    }
    if (endIdx == idx) {
      return null;
    }
    return Double.parseDouble(json.substring(idx, endIdx));
  }

  private List<Symptom> parseSymptomArray(String json) {
    List<Symptom> symptoms = new ArrayList<>();
    int idx = json.indexOf("\"symptoms\":[");
    if (idx == -1) {
      return symptoms;
    }
    idx += 12;
    int endIdx = json.indexOf("]", idx);
    String arrayContent = json.substring(idx, endIdx);

    int objStart = 0;
    while ((objStart = arrayContent.indexOf("{", objStart)) != -1) {
      int objEnd = arrayContent.indexOf("}", objStart);
      String objJson = arrayContent.substring(objStart, objEnd + 1);

      Symptom symptom = new Symptom();
      symptom.present = extractBooleanField(objJson, "present");
      symptom.symptomName = extractStringField(objJson, "symptom_name");
      symptom.symptomDetails = extractStringField(objJson, "symptom_details");
      symptoms.add(symptom);

      objStart = objEnd + 1;
    }

    return symptoms;
  }

  private List<MedicalCondition> parseMedicalHistoryArray(String json) {
    List<MedicalCondition> conditions = new ArrayList<>();
    int idx = json.indexOf("\"medical_history\":[");
    if (idx == -1) {
      return conditions;
    }
    idx += 20;
    int endIdx = json.indexOf("]", idx);
    String arrayContent = json.substring(idx, endIdx);

    int objStart = 0;
    while ((objStart = arrayContent.indexOf("{", objStart)) != -1) {
      int objEnd = arrayContent.indexOf("}", objStart);
      String objJson = arrayContent.substring(objStart, objEnd + 1);

      MedicalCondition condition = new MedicalCondition();
      condition.present = extractBooleanField(objJson, "present");
      condition.conditionName = extractStringField(objJson, "condition_name");
      condition.diagnosisDate = extractStringField(objJson, "diagnosis_date");
      conditions.add(condition);

      objStart = objEnd + 1;
    }

    return conditions;
  }

  private List<Hospitalization> parseHospitalizationArray(String json) {
    List<Hospitalization> hospitalizations = new ArrayList<>();
    int idx = json.indexOf("\"hospitalizations\":[");
    if (idx == -1) {
      return hospitalizations;
    }
    idx += 21;
    int endIdx = json.indexOf("]", idx);
    String arrayContent = json.substring(idx, endIdx);

    int objStart = 0;
    while ((objStart = arrayContent.indexOf("{", objStart)) != -1) {
      int objEnd = arrayContent.indexOf("}", objStart);
      String objJson = arrayContent.substring(objStart, objEnd + 1);

      Hospitalization hosp = new Hospitalization();
      hosp.hospitalizationDate = extractStringField(objJson, "hospitalization_date");
      hosp.hospitalizationReason = extractStringField(objJson, "hospitalization_reason");
      hospitalizations.add(hosp);

      objStart = objEnd + 1;
    }

    return hospitalizations;
  }

  private List<Surgery> parseSurgeryArray(String json) {
    List<Surgery> surgeries = new ArrayList<>();
    int idx = json.indexOf("\"surgeries\":[");
    if (idx == -1) {
      return surgeries;
    }
    idx += 13;
    int endIdx = json.indexOf("]", idx);
    String arrayContent = json.substring(idx, endIdx);

    int objStart = 0;
    while ((objStart = arrayContent.indexOf("{", objStart)) != -1) {
      int objEnd = arrayContent.indexOf("}", objStart);
      String objJson = arrayContent.substring(objStart, objEnd + 1);

      Surgery surgery = new Surgery();
      surgery.surgeryDate = extractStringField(objJson, "surgery_date");
      surgery.surgeryName = extractStringField(objJson, "surgery_name");
      surgeries.add(surgery);

      objStart = objEnd + 1;
    }

    return surgeries;
  }

  private Boolean extractBooleanField(String json, String fieldName) {
    String searchKey = "\"" + fieldName + "\":";
    int idx = json.indexOf(searchKey);
    if (idx == -1) {
      return null;
    }
    idx += searchKey.length();
    if (json.startsWith("true", idx)) {
      return true;
    } else if (json.startsWith("false", idx)) {
      return false;
    }
    return null;
  }

  private String escapeJson(String str) {
    return str.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r");
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    String testFilePath = args.length > 0 ? args[0] : "./intake_form.pdf";

    if (!Files.exists(Paths.get(testFilePath))) {
      System.err.println("File not found: " + testFilePath);
      System.exit(1);
    }

    IntakeFormProcessor processor = new IntakeFormProcessor();
    IntakeFormData result = processor.processIntakeForm(testFilePath);

    System.out.println("\nFull extracted data:");
    System.out.println("Patient: " + result.patientName);
    System.out.println("MRN: " + result.medicalRecordNumber);
    System.out.println("DOB: " + result.dateOfBirth);
    System.out.println("Age: " + result.age);
    System.out.println("Sex: " + result.sex);
    System.out.println("Marital Status: " + result.maritalStatus);
    System.out.println("Height: " + result.height);
    System.out.println("Weight: " + result.weight);
    System.out.println("Form Date: " + result.formDate);
    System.out.println("Chief Complaint: " + result.chiefComplaint);
    System.out.println("History of Present Illness: " + result.historyOfPresentIllness);
    System.out.println("Referred By: " + result.referredBy);
    System.out.println("Primary Medical Doctor: " + result.primaryMedicalDoctor);
    System.out.println("Symptoms: " + result.symptoms.size());
    System.out.println("Medical History: " + result.medicalHistory.size());
    System.out.println("Hospitalizations: " + result.hospitalizations.size());
    System.out.println("Surgeries: " + result.surgeries.size());
  }
}
// This code uses the Extend REST API directly because Extend has no official Go SDK yet.
// It calls https://api.extend.ai endpoints with standard net/http and encoding/json.

package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

const extendAPIBase = "https://api.extend.ai"

// Symptom represents a single symptom entry
type Symptom struct {
	Present        *bool   `json:"present"`
	SymptomName    *string `json:"symptom_name"`
	SymptomDetails *string `json:"symptom_details"`
}

// MedicalHistory represents a single medical condition entry
type MedicalHistory struct {
	Present       *bool   `json:"present"`
	ConditionName *string `json:"condition_name"`
	DiagnosisDate *string `json:"diagnosis_date"`
}

// Hospitalization represents a single hospitalization entry
type Hospitalization struct {
	HospitalizationDate   *string `json:"hospitalization_date"`
	HospitalizationReason *string `json:"hospitalization_reason"`
}

// Surgery represents a single surgery entry
type Surgery struct {
	SurgeryDate *string `json:"surgery_date"`
	SurgeryName *string `json:"surgery_name"`
}

// IntakeFormData represents the complete extracted intake form
type IntakeFormData struct {
	PatientName              *string            `json:"patient_name"`
	MedicalRecordNumber      *string            `json:"medical_record_number"`
	DateOfBirth              *string            `json:"date_of_birth"`
	Age                      *int               `json:"age"`
	Sex                      *string            `json:"sex"`
	MaritalStatus            *string            `json:"marital_status"`
	Height                   *string            `json:"height"`
	Weight                   *float64           `json:"weight"`
	FormDate                 *string            `json:"form_date"`
	ChiefComplaint           *string            `json:"chief_complaint"`
	HistoryOfPresentIllness  *string            `json:"history_of_present_illness"`
	ReferredBy               *string            `json:"referred_by"`
	PrimaryMedicalDoctor     *string            `json:"primary_medical_doctor"`
	Symptoms                 []Symptom          `json:"symptoms"`
	MedicalHistory           []MedicalHistory   `json:"medical_history"`
	Hospitalizations         []Hospitalization  `json:"hospitalizations"`
	Surgeries                []Surgery          `json:"surgeries"`
}

// ParseRunOutput represents the output from a parse run
type ParseRunOutput struct {
	Chunks []struct {
		Content string `json:"content"`
	} `json:"chunks"`
}

// ParseRun represents a parse run response
type ParseRun struct {
	Status string         `json:"status"`
	Output ParseRunOutput `json:"output"`
}

// ExtractRunOutput represents the output from an extract run
type ExtractRunOutput struct {
	Value json.RawMessage `json:"value"`
}

// ExtractRun represents an extract run response
type ExtractRun struct {
	Status string          `json:"status"`
	Output ExtractRunOutput `json:"output"`
}

// ExtendClient holds the API token and HTTP client
type ExtendClient struct {
	token      string
	httpClient *http.Client
}

// NewExtendClient creates a new Extend API client
func NewExtendClient(token string) *ExtendClient {
	return &ExtendClient{
		token: token,
		httpClient: &http.Client{
			Timeout: 5 * time.Minute,
		},
	}
}

// doRequest performs an HTTP request with authorization
func (c *ExtendClient) doRequest(method, path string, body interface{}) ([]byte, error) {
	url := extendAPIBase + path
	var reqBody io.Reader
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewReader(jsonBody)
	}

	req, err := http.NewRequest(method, url, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+c.token)
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, string(respBody))
	}

	return respBody, nil
}

// CreateAndPollParseRun creates a parse run and polls until completion
func (c *ExtendClient) CreateAndPollParseRun(fileURL string) (*ParseRun, error) {
	payload := map[string]interface{}{
		"file": map[string]string{
			"url": fileURL,
		},
		"config": map[string]interface{}{
			"blockOptions": map[string]interface{}{
				"text": map[string]interface{}{
					"agentic": map[string]bool{
						"enabled": true,
					},
				},
			},
			"chunkingStrategy": map[string]string{
				"type": "document",
			},
		},
	}

	respBody, err := c.doRequest("POST", "/v1/parse-runs", payload)
	if err != nil {
		return nil, err
	}

	var createResp struct {
		ID string `json:"id"`
	}
	if err := json.Unmarshal(respBody, &createResp); err != nil {
		return nil, err
	}

	// Poll for completion
	for {
		respBody, err := c.doRequest("GET", "/v1/parse-runs/"+createResp.ID, nil)
		if err != nil {
			return nil, err
		}

		var run ParseRun
		if err := json.Unmarshal(respBody, &run); err != nil {
			return nil, err
		}

		if run.Status == "PROCESSED" || run.Status == "FAILED" {
			return &run, nil
		}

		time.Sleep(2 * time.Second)
	}
}

// CreateAndPollExtractRun creates an extract run and polls until completion
func (c *ExtendClient) CreateAndPollExtractRun(fileURL string, schema map[string]interface{}) (*ExtractRun, error) {
	payload := map[string]interface{}{
		"file": map[string]string{
			"url": fileURL,
		},
		"config": map[string]interface{}{
			"schema": schema,
			"baseProcessor": "extraction_performance",
			"advancedOptions": map[string]interface{}{
				"reviewAgent": map[string]bool{
					"enabled": true,
				},
				"advancedMultimodalEnabled": true,
			},
		},
	}

	respBody, err := c.doRequest("POST", "/v1/extract-runs", payload)
	if err != nil {
		return nil, err
	}

	var createResp struct {
		ID string `json:"id"`
	}
	if err := json.Unmarshal(respBody, &createResp); err != nil {
		return nil, err
	}

	// Poll for completion
	for {
		respBody, err := c.doRequest("GET", "/v1/extract-runs/"+createResp.ID, nil)
		if err != nil {
			return nil, err
		}

		var run ExtractRun
		if err := json.Unmarshal(respBody, &run); err != nil {
			return nil, err
		}

		if run.Status == "PROCESSED" || run.Status == "FAILED" {
			return &run, nil
		}

		time.Sleep(2 * time.Second)
	}
}

// ProcessIntakeForm processes a cardiology intake form through parse + extract pipeline
func ProcessIntakeForm(filePath string) (*IntakeFormData, error) {
	fmt.Printf("Processing intake form: %s\n", filePath)

	// Convert local file to base64 data URL
	fileBuffer, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	base64Data := base64.StdEncoding.EncodeToString(fileBuffer)
	fileExt := filepath.Ext(filePath)
	if fileExt != "" {
		fileExt = fileExt[1:] // Remove leading dot
	}
	fileExt = filepath.Ext(filePath)
	if fileExt != "" {
		fileExt = fileExt[1:]
	}

	mimeType := "image/jpeg"
	if fileExt == "pdf" {
		mimeType = "application/pdf"
	}
	dataURL := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Data)

	apiKey := os.Getenv("EXTEND_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("EXTEND_API_KEY environment variable not set")
	}

	client := NewExtendClient(apiKey)

	// Step 1: Parse intake form with agentic OCR
	fmt.Println("Step 1: Parsing form with agentic OCR...")
	parseRun, err := client.CreateAndPollParseRun(dataURL)
	if err != nil {
		return nil, err
	}

	if parseRun.Status != "PROCESSED" {
		return nil, fmt.Errorf("parse failed with status: %s", parseRun.Status)
	}

	// Collect parsed markdown for logging
	var parsedMarkdown string
	for _, chunk := range parseRun.Output.Chunks {
		parsedMarkdown += chunk.Content + "\n\n"
	}
	if len(parsedMarkdown) > 500 {
		fmt.Printf("Parsed markdown (first 500 chars): %s...\n", parsedMarkdown[:500])
	} else {
		fmt.Printf("Parsed markdown: %s\n", parsedMarkdown)
	}

	// Step 2: Extract structured fields
	fmt.Println("Step 2: Extracting structured fields...")

	// Define the extraction schema
	schema := map[string]interface{}{
		"type": "object",
		"properties": map[string]interface{}{
			"patient_name": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The full name of the patient completing or referenced in the intake form.",
			},
			"medical_record_number": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The unique identifier assigned to the patient by the healthcare provider.",
			},
			"date_of_birth": map[string]interface{}{
				"type": []string{"string", "null"},
				"extend:type": "date",
				"description": "The patient's date of birth.",
			},
			"age": map[string]interface{}{
				"type": []string{"integer", "null"},
				"description": "The patient's age in years.",
			},
			"sex": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The patient's sex or gender.",
			},
			"marital_status": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The patient's marital status.",
			},
			"height": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The patient's height.",
			},
			"weight": map[string]interface{}{
				"type": []string{"number", "null"},
				"description": "The patient's weight.",
			},
			"form_date": map[string]interface{}{
				"type": []string{"string", "null"},
				"extend:type": "date",
				"description": "The date the intake form was completed.",
			},
			"chief_complaint": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The main reason for the patient's visit.",
			},
			"history_of_present_illness": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "A narrative description of the patient's current symptoms.",
			},
			"referred_by": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The name of the individual or provider who referred the patient.",
			},
			"primary_medical_doctor": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The name of the patient's primary care physician.",
			},
			"symptoms": map[string]interface{}{
				"type": "array",
				"items": map[string]interface{}{
					"type": "object",
					"properties": map[string]interface{}{
						"present": map[string]interface{}{
							"type": []string{"boolean", "null"},
						},
						"symptom_name": map[string]interface{}{
							"type": []string{"string", "null"},
						},
						"symptom_details": map[string]interface{}{
							"type": []string{"string", "null"},
						},
					},
				},
			},
			"medical_history": map[string]interface{}{
				"type": "array",
				"items": map[string]interface{}{
					"type": "object",
					"properties": map[string]interface{}{
						"present": map[string]interface{}{
							"type": []string{"boolean", "null"},
						},
						"condition_name": map[string]interface{}{
							"type": []string{"string", "null"},
						},
						"diagnosis_date": map[string]interface{}{
							"type": []string{"string", "null"},
						},
					},
				},
			},
			"hospitalizations": map[string]interface{}{
				"type": "array",
				"items": map[string]interface{}{
					"type": "object",
					"properties": map[string]interface{}{
						"hospitalization_date": map[string]interface{}{
							"type": []string{"string", "null"},
						},
						"hospitalization_reason": map[string]interface{}{
							"type": []string{"string", "null"},
						},
					},
				},
			},
			"surgeries": map[string]interface{}{
				"type": "array",
				"items": map[string]interface{}{
					"type": "object",
					"properties": map[string]interface{}{
						"surgery_date": map[string]interface{}{
							"type": []string{"string", "null"},
						},
						"surgery_name": map[string]interface{}{
							"type": []string{"string", "null"},
						},
					},
				},
			},
		},
	}

	extractRun, err := client.CreateAndPollExtractRun(dataURL, schema)
	if err != nil {
		return nil, err
	}

	if extractRun.Status != "PROCESSED" {
		return nil, fmt.Errorf("extraction failed with status: %s", extractRun.Status)
	}

	var extracted IntakeFormData
	if err := json.Unmarshal(extractRun.Output.Value, &extracted); err != nil {
		return nil, err
	}

	fmt.Println("✓ Extraction complete")
	if extracted.PatientName != nil {
		fmt.Printf("Patient: %s", *extracted.PatientName)
		if extracted.MedicalRecordNumber != nil {
			fmt.Printf(" (MRN: %s)", *extracted.MedicalRecordNumber)
		}
		fmt.Println()
	}
	if extracted.Age != nil && extracted.Sex != nil {
		fmt.Printf("Age: %d, Sex: %s\n", *extracted.Age, *extracted.Sex)
	}
	if extracted.ChiefComplaint != nil {
		fmt.Printf("Chief Complaint: %s\n", *extracted.ChiefComplaint)
	}
	fmt.Printf("Symptoms found: %d\n", len(extracted.Symptoms))
	fmt.Printf("Medical conditions: %d\n", len(extracted.MedicalHistory))
	fmt.Printf("Hospitalizations: %d\n", len(extracted.Hospitalizations))
	fmt.Printf("Surgeries: %d\n", len(extracted.Surgeries))

	return &extracted, nil
}

func main() {
	flag.Parse()
	args := flag.Args()

	testFilePath := "./intake_form.pdf"
	if len(args) > 0 {
		testFilePath = args[0]
	}

	if _, err := os.Stat(testFilePath); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "File not found: %s\n", testFilePath)
		os.Exit(1)
	}

	result, err := ProcessIntakeForm(testFilePath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	fmt.Println("\nFull extracted data:")
	jsonBytes, _ := json.MarshalIndent(result, "", "  ")
	fmt.Println(string(jsonBytes))
}
// Deploy the "Intake Form" pipeline to YOUR Extend account.
//
// The workflow below is fully self-contained — every EXTRACT/CLASSIFY/SPLIT
// step carries its extractor/classifier/splitter config INLINE, so this is a
// single API call. No processors to create or wire up beforehand.
// Idempotent: the created workflow id is cached in .extend/intake-form.json,
// so re-running updates the existing workflow instead of duplicating it.
//
// Usage:
//   export EXTEND_API_KEY=sk_...   (from https://dashboard.extend.ai → API Keys)
//   npx tsx provision.ts
//
// Generated by doc1 (template: intake-form).

import fs from "node:fs";
import path from "node:path";

const API = "https://api.extend.ai";
const VERSION = "2026-02-09";
const API_KEY = process.env.EXTEND_API_KEY;
if (!API_KEY) { console.error("Set EXTEND_API_KEY first."); process.exit(1); }

const STATE_DIR = path.join(process.cwd(), ".extend");
const STATE_FILE = path.join(STATE_DIR, "intake-form.json");

type State = { workflowId?: string };
const state: State = fs.existsSync(STATE_FILE)
  ? JSON.parse(fs.readFileSync(STATE_FILE, "utf8"))
  : {};
function saveState() {
  fs.mkdirSync(STATE_DIR, { recursive: true });
  fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
}

async function api(method: string, pathName: string, body?: unknown) {
  const res = await fetch(API + pathName, {
    method,
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "x-extend-api-version": VERSION,
      ...(body ? { "Content-Type": "application/json" } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(`${method} ${pathName} failed (${res.status}): ${JSON.stringify(data).slice(0, 300)}`);
  return data;
}

// ── Workflow definition — extractor/classifier/splitter configs inline ──────
const WORKFLOW = {
  "name": "Intake Form Processing Pipeline",
  "steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [
        {
          "step": "parse1"
        }
      ]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {
            "text": {
              "agentic": {
                "enabled": true
              }
            }
          },
          "chunkingStrategy": {
            "type": "document"
          }
        }
      },
      "next": [
        {
          "step": "extraction2"
        }
      ]
    },
    {
      "name": "extraction2",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "required": [
              "age",
              "sex",
              "height",
              "weight",
              "symptoms",
              "form_date",
              "surgeries",
              "referred_by",
              "patient_name",
              "date_of_birth",
              "marital_status",
              "chief_complaint",
              "medical_history",
              "hospitalizations",
              "medical_record_number",
              "primary_medical_doctor",
              "history_of_present_illness"
            ],
            "properties": {
              "age": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."
              },
              "sex": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."
              },
              "height": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."
              },
              "weight": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."
              },
              "symptoms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "present",
                    "symptom_name",
                    "symptom_details"
                  ],
                  "properties": {
                    "present": {
                      "type": [
                        "boolean",
                        "null"
                      ],
                      "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."
                    },
                    "symptom_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."
                    },
                    "symptom_details": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
              },
              "form_date": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided.",
                "extend:type": "date"
              },
              "surgeries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "surgery_date",
                    "surgery_name"
                  ],
                  "properties": {
                    "surgery_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."
                    },
                    "surgery_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
              },
              "referred_by": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."
              },
              "patient_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."
              },
              "date_of_birth": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc.",
                "extend:type": "date"
              },
              "marital_status": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."
              },
              "chief_complaint": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."
              },
              "medical_history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "present",
                    "condition_name",
                    "diagnosis_date"
                  ],
                  "properties": {
                    "present": {
                      "type": [
                        "boolean",
                        "null"
                      ],
                      "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."
                    },
                    "condition_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."
                    },
                    "diagnosis_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
              },
              "hospitalizations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "hospitalization_date",
                    "hospitalization_reason"
                  ],
                  "properties": {
                    "hospitalization_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."
                    },
                    "hospitalization_reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
              },
              "medical_record_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."
              },
              "primary_medical_doctor": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."
              },
              "history_of_present_illness": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."
              }
            },
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {
              "enabled": true
            },
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
};

async function main() {
  console.log(`Deploying "${WORKFLOW.name}"…`);

  if (state.workflowId) {
    console.log(`✓ workflow already provisioned (${state.workflowId}) — updating steps`);
    await api("POST", `/workflows/${state.workflowId}`, { steps: WORKFLOW.steps });
  } else {
    // Reuse an existing workflow with the same name if one exists (e.g. a
    // previous run's state file was lost) instead of creating a duplicate.
    try {
      const list = await api("GET", `/workflows?name=${encodeURIComponent(WORKFLOW.name)}`);
      const items = (list.data ?? list.items ?? []) as Array<{ name?: string; id?: string }>;
      const existing = items.find((x) => x.name === WORKFLOW.name);
      if (existing?.id) {
        state.workflowId = existing.id; saveState();
        console.log(`✓ workflow "${WORKFLOW.name}" found in your account (${existing.id}) — updating steps`);
        await api("POST", `/workflows/${existing.id}`, { steps: WORKFLOW.steps });
      }
    } catch { /* lookup is best-effort; fall through to create */ }

    if (!state.workflowId) {
      const created = await api("POST", "/workflows", WORKFLOW);
      const wfId = created.id ?? created.workflow?.id;
      if (!wfId) throw new Error("Could not read created workflow id from response");
      state.workflowId = wfId; saveState();
      console.log(`+ created workflow (${wfId})`);
    }
  }

  // Deploy the current draft as a new version so the workflow is runnable —
  // best-effort: some accounts/plans may not require this explicit step.
  await api("POST", `/workflows/${state.workflowId}/versions`, {}).catch(() => {});

  console.log("\nDone. Run documents through it with:");
  console.log(`  POST ${API}/workflow_runs  { workflow: { id: "${state.workflowId}" }, file: { url: "https://…" } }`);
  console.log("Or open the workflow in the Extend dashboard to review and deploy it.");
}

main().catch((e) => { console.error(e.message ?? e); process.exit(1); });
import os
import json
import sys
from pathlib import Path
from extend_ai import Extend

API_KEY = os.environ.get("EXTEND_API_KEY")
if not API_KEY:
    print("Set EXTEND_API_KEY first.", file=sys.stderr)
    sys.exit(1)

STATE_DIR = Path.cwd() / ".extend"
STATE_FILE = STATE_DIR / "intake-form.json"

state = {}
if STATE_FILE.exists():
    with open(STATE_FILE, "r") as f:
        state = json.load(f)

def save_state():
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    with open(STATE_FILE, "w") as f:
        json.dump(state, f, indent=2)

WORKFLOW = {
    "name": "Intake Form Processing Pipeline",
    "steps": [
        {
            "name": "startTrigger1",
            "type": "TRIGGER",
            "next": [
                {
                    "step": "parse1"
                }
            ]
        },
        {
            "name": "parse1",
            "type": "PARSE",
            "config": {
                "parseConfig": {
                    "blockOptions": {
                        "text": {
                            "agentic": {
                                "enabled": True
                            }
                        }
                    },
                    "chunkingStrategy": {
                        "type": "document"
                    }
                }
            },
            "next": [
                {
                    "step": "extraction2"
                }
            ]
        },
        {
            "name": "extraction2",
            "type": "EXTRACT",
            "config": {
                "extractorConfig": {
                    "schema": {
                        "type": "object",
                        "properties": {
                            "age": {
                                "type": [
                                    "integer",
                                    "null"
                                ],
                                "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."
                            },
                            "sex": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."
                            },
                            "height": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."
                            },
                            "weight": {
                                "type": [
                                    "number",
                                    "null"
                                ],
                                "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."
                            },
                            "symptoms": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "present": {
                                            "type": [
                                                "boolean",
                                                "null"
                                            ],
                                            "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."
                                        },
                                        "symptom_name": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."
                                        },
                                        "symptom_details": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."
                                        }
                                    },
                                    "additionalProperties": False,
                                    "required": [
                                        "present",
                                        "symptom_name",
                                        "symptom_details"
                                    ]
                                },
                                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
                            },
                            "form_date": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "extend:type": "date",
                                "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."
                            },
                            "surgeries": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "surgery_date": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."
                                        },
                                        "surgery_name": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."
                                        }
                                    },
                                    "additionalProperties": False,
                                    "required": [
                                        "surgery_date",
                                        "surgery_name"
                                    ]
                                },
                                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
                            },
                            "referred_by": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."
                            },
                            "patient_name": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."
                            },
                            "date_of_birth": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "extend:type": "date",
                                "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."
                            },
                            "marital_status": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."
                            },
                            "chief_complaint": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."
                            },
                            "medical_history": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "present": {
                                            "type": [
                                                "boolean",
                                                "null"
                                            ],
                                            "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."
                                        },
                                        "condition_name": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."
                                        },
                                        "diagnosis_date": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."
                                        }
                                    },
                                    "additionalProperties": False,
                                    "required": [
                                        "present",
                                        "condition_name",
                                        "diagnosis_date"
                                    ]
                                },
                                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
                            },
                            "hospitalizations": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "hospitalization_date": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."
                                        },
                                        "hospitalization_reason": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."
                                        }
                                    },
                                    "additionalProperties": False,
                                    "required": [
                                        "hospitalization_date",
                                        "hospitalization_reason"
                                    ]
                                },
                                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
                            },
                            "medical_record_number": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."
                            },
                            "primary_medical_doctor": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."
                            },
                            "history_of_present_illness": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."
                            }
                        },
                        "required": [
                            "age",
                            "sex",
                            "height",
                            "weight",
                            "symptoms",
                            "form_date",
                            "surgeries",
                            "referred_by",
                            "patient_name",
                            "date_of_birth",
                            "marital_status",
                            "chief_complaint",
                            "medical_history",
                            "hospitalizations",
                            "medical_record_number",
                            "primary_medical_doctor",
                            "history_of_present_illness"
                        ],
                        "additionalProperties": False
                    },
                    "baseProcessor": "extraction_performance",
                    "advancedOptions": {
                        "reviewAgent": {
                            "enabled": True
                        },
                        "advancedMultimodalEnabled": True
                    }
                }
            }
        }
    ]
}

def main():
    client = Extend(token=API_KEY)
    
    print(f'Deploying "{WORKFLOW["name"]}…"')
    
    if state.get("workflowId"):
        workflow_id = state["workflowId"]
        print(f"✓ workflow already provisioned ({workflow_id}) — updating steps")
        client.workflows.update(id=workflow_id, steps=WORKFLOW["steps"])
    else:
        # Try to find an existing workflow with the same name
        try:
            workflows_list = client.workflows.list(name=WORKFLOW["name"])
            items = workflows_list.data if hasattr(workflows_list, "data") else (workflows_list.items if hasattr(workflows_list, "items") else [])
            existing = next((x for x in items if x.name == WORKFLOW["name"]), None)
            if existing and existing.id:
                state["workflowId"] = existing.id
                save_state()
                print(f'✓ workflow "{WORKFLOW["name"]}" found in your account ({existing.id}) — updating steps')
                client.workflows.update(id=existing.id, steps=WORKFLOW["steps"])
        except Exception:
            pass
        
        if not state.get("workflowId"):
            created = client.workflows.create(**WORKFLOW)
            workflow_id = created.id if hasattr(created, "id") else (created.workflow.id if hasattr(created, "workflow") else None)
            if not workflow_id:
                raise Exception("Could not read created workflow id from response")
            state["workflowId"] = workflow_id
            save_state()
            print(f"+ created workflow ({workflow_id})")
    
    # Deploy the current draft as a new version
    try:
        client.workflows.create_version(id=state["workflowId"])
    except Exception:
        pass
    
    print("\nDone. Run documents through it with:")
    print(f'  POST https://api.extend.ai/workflow_runs  {{ "workflow": {{ "id": "{state["workflowId"]}" }}, "file": {{ "url": "https://…" }} }}')
    print("Or open the workflow in the Extend dashboard to review and deploy it.")

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(str(e), file=sys.stderr)
        sys.exit(1)
// This script uses the Extend REST API directly because Extend has no official Java SDK yet.
// Call the API with java.net.http.HttpClient and parse JSON manually.

import java.io.*;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public class ProvisionIntakeForm {
  private static final String API = "https://api.extend.ai";
  private static final String VERSION = "2026-02-09";
  private static final String API_KEY = System.getenv("EXTEND_API_KEY");
  private static final Path STATE_DIR = Paths.get(System.getProperty("user.dir"), ".extend");
  private static final Path STATE_FILE = STATE_DIR.resolve("intake-form.json");

  static {
    if (API_KEY == null || API_KEY.isEmpty()) {
      System.err.println("Set EXTEND_API_KEY first.");
      System.exit(1);
    }
  }

  static class State {
    String workflowId;
  }

  private static State state = new State();
  private static final HttpClient httpClient = HttpClient.newHttpClient();

  public static void main(String[] args) throws Exception {
    loadState();
    try {
      provision();
      System.out.println("\nDone. Run documents through it with:");
      System.out.println("  POST " + API + "/workflow_runs  { workflow: { id: \"" + state.workflowId + "\" }, file: { url: \"https://…\" } }");
      System.out.println("Or open the workflow in the Extend dashboard to review and deploy it.");
    } catch (Exception e) {
      System.err.println(e.getMessage() != null ? e.getMessage() : e);
      System.exit(1);
    }
  }

  private static void loadState() throws IOException {
    if (Files.exists(STATE_FILE)) {
      String json = Files.readString(STATE_FILE);
      state = parseStateJson(json);
    }
  }

  private static void saveState() throws IOException {
    Files.createDirectories(STATE_DIR);
    String json = toJson(state);
    Files.writeString(STATE_FILE, json);
  }

  private static String toJson(State s) {
    StringBuilder sb = new StringBuilder();
    sb.append("{\n");
    if (s.workflowId != null) {
      sb.append("  \"workflowId\": \"").append(escapeJson(s.workflowId)).append("\"\n");
    }
    sb.append("}");
    return sb.toString();
  }

  private static State parseStateJson(String json) {
    State s = new State();
    if (json.contains("\"workflowId\"")) {
      int start = json.indexOf("\"workflowId\"");
      int colonIdx = json.indexOf(":", start);
      int quoteStart = json.indexOf("\"", colonIdx);
      int quoteEnd = json.indexOf("\"", quoteStart + 1);
      s.workflowId = json.substring(quoteStart + 1, quoteEnd);
    }
    return s;
  }

  private static String escapeJson(String s) {
    return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r");
  }

  private static Map<String, Object> api(String method, String pathName, String body) throws Exception {
    HttpRequest.Builder builder = HttpRequest.newBuilder()
        .uri(URI.create(API + pathName))
        .method(method, body != null ? HttpRequest.BodyPublishers.ofString(body) : HttpRequest.BodyPublishers.noBody())
        .header("Authorization", "Bearer " + API_KEY)
        .header("x-extend-api-version", VERSION);

    if (body != null) {
      builder.header("Content-Type", "application/json");
    }

    HttpRequest request = builder.build();
    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

    Map<String, Object> data = new HashMap<>();
    if (!response.body().isEmpty()) {
      data = parseJson(response.body());
    }

    if (response.statusCode() < 200 || response.statusCode() >= 300) {
      String errorMsg = response.body().length() > 300 ? response.body().substring(0, 300) : response.body();
      throw new Exception(method + " " + pathName + " failed (" + response.statusCode() + "): " + errorMsg);
    }

    return data;
  }

  private static Map<String, Object> parseJson(String json) {
    Map<String, Object> result = new HashMap<>();
    json = json.trim();
    if (!json.startsWith("{")) return result;

    json = json.substring(1, json.length() - 1);
    int depth = 0;
    StringBuilder key = new StringBuilder();
    StringBuilder value = new StringBuilder();
    boolean inKey = true;
    boolean inString = false;
    boolean escaped = false;

    for (int i = 0; i < json.length(); i++) {
      char c = json.charAt(i);

      if (escaped) {
        if (inKey) key.append(c);
        else value.append(c);
        escaped = false;
        continue;
      }

      if (c == '\\') {
        escaped = true;
        if (inKey) key.append(c);
        else value.append(c);
        continue;
      }

      if (c == '"') {
        inString = !inString;
        if (inKey) key.append(c);
        else value.append(c);
        continue;
      }

      if (!inString) {
        if (c == '{' || c == '[') depth++;
        else if (c == '}' || c == ']') depth--;
        else if (c == ':' && depth == 0 && inKey) {
          inKey = false;
          continue;
        } else if (c == ',' && depth == 0 && !inKey) {
          String k = key.toString().trim();
          if (k.startsWith("\"")) k = k.substring(1, k.length() - 1);
          String v = value.toString().trim();
          result.put(k, v);
          key = new StringBuilder();
          value = new StringBuilder();
          inKey = true;
          continue;
        }
      }

      if (inKey) key.append(c);
      else value.append(c);
    }

    if (key.length() > 0) {
      String k = key.toString().trim();
      if (k.startsWith("\"")) k = k.substring(1, k.length() - 1);
      String v = value.toString().trim();
      result.put(k, v);
    }

    return result;
  }

  private static String getWorkflowJson() {
    return """
{
  "name": "Intake Form Processing Pipeline",
  "steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [{"step": "parse1"}]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {"text": {"agentic": {"enabled": true}}},
          "chunkingStrategy": {"type": "document"}
        }
      },
      "next": [{"step": "extraction2"}]
    },
    {
      "name": "extraction2",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "properties": {
              "age": {"type": ["integer", "null"], "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."},
              "sex": {"type": ["string", "null"], "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."},
              "height": {"type": ["string", "null"], "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."},
              "weight": {"type": ["number", "null"], "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."},
              "symptoms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."},
                    "symptom_name": {"type": ["string", "null"], "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."},
                    "symptom_details": {"type": ["string", "null"], "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "symptom_name", "symptom_details"]
                },
                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
              },
              "form_date": {"type": ["string", "null"], "extend:type": "date", "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."},
              "surgeries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "surgery_date": {"type": ["string", "null"], "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."},
                    "surgery_name": {"type": ["string", "null"], "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."}
                  },
                  "additionalProperties": false,
                  "required": ["surgery_date", "surgery_name"]
                },
                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
              },
              "referred_by": {"type": ["string", "null"], "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."},
              "patient_name": {"type": ["string", "null"], "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."},
              "date_of_birth": {"type": ["string", "null"], "extend:type": "date", "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."},
              "marital_status": {"type": ["string", "null"], "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."},
              "chief_complaint": {"type": ["string", "null"], "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."},
              "medical_history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."},
                    "condition_name": {"type": ["string", "null"], "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."},
                    "diagnosis_date": {"type": ["string", "null"], "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "condition_name", "diagnosis_date"]
                },
                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
              },
              "hospitalizations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hospitalization_date": {"type": ["string", "null"], "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."},
                    "hospitalization_reason": {"type": ["string", "null"], "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."}
                  },
                  "additionalProperties": false,
                  "required": ["hospitalization_date", "hospitalization_reason"]
                },
                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
              },
              "medical_record_number": {"type": ["string", "null"], "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."},
              "primary_medical_doctor": {"type": ["string", "null"], "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."},
              "history_of_present_illness": {"type": ["string", "null"], "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."}
            },
            "required": ["age", "sex", "height", "weight", "symptoms", "form_date", "surgeries", "referred_by", "patient_name", "date_of_birth", "marital_status", "chief_complaint", "medical_history", "hospitalizations", "medical_record_number", "primary_medical_doctor", "history_of_present_illness"],
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {"enabled": true},
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
}""";
  }

  private static void provision() throws Exception {
    System.out.println("Deploying \"Intake Form Processing Pipeline\"…");

    if (state.workflowId != null && !state.workflowId.isEmpty()) {
      System.out.println("✓ workflow already provisioned (" + state.workflowId + ") — updating steps");
      String stepsJson = """
{"steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [{"step": "parse1"}]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {"text": {"agentic": {"enabled": true}}},
          "chunkingStrategy": {"type": "document"}
        }
      },
      "next": [{"step": "extraction2"}]
    },
    {
      "name": "extraction2",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "properties": {
              "age": {"type": ["integer", "null"], "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."},
              "sex": {"type": ["string", "null"], "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."},
              "height": {"type": ["string", "null"], "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."},
              "weight": {"type": ["number", "null"], "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."},
              "symptoms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."},
                    "symptom_name": {"type": ["string", "null"], "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."},
                    "symptom_details": {"type": ["string", "null"], "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "symptom_name", "symptom_details"]
                },
                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
              },
              "form_date": {"type": ["string", "null"], "extend:type": "date", "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."},
              "surgeries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "surgery_date": {"type": ["string", "null"], "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."},
                    "surgery_name": {"type": ["string", "null"], "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."}
                  },
                  "additionalProperties": false,
                  "required": ["surgery_date", "surgery_name"]
                },
                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
              },
              "referred_by": {"type": ["string", "null"], "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."},
              "patient_name": {"type": ["string", "null"], "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."},
              "date_of_birth": {"type": ["string", "null"], "extend:type": "date", "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."},
              "marital_status": {"type": ["string", "null"], "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."},
              "chief_complaint": {"type": ["string", "null"], "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."},
              "medical_history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."},
                    "condition_name": {"type": ["string", "null"], "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."},
                    "diagnosis_date": {"type": ["string", "null"], "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "condition_name", "diagnosis_date"]
                },
                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
              },
              "hospitalizations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hospitalization_date": {"type": ["string", "null"], "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."},
                    "hospitalization_reason": {"type": ["string", "null"], "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."}
                  },
                  "additionalProperties": false,
                  "required": ["hospitalization_date", "hospitalization_reason"]
                },
                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
              },
              "medical_record_number": {"type": ["string", "null"], "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."},
              "primary_medical_doctor": {"type": ["string", "null"], "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."},
              "history_of_present_illness": {"type": ["string", "null"], "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."}
            },
            "required": ["age", "sex", "height", "weight", "symptoms", "form_date", "surgeries", "referred_by", "patient_name", "date_of_birth", "marital_status", "chief_complaint", "medical_history", "hospitalizations", "medical_record_number", "primary_medical_doctor", "history_of_present_illness"],
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {"enabled": true},
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
}""";
      api("POST", "/workflows/" + state.workflowId, stepsJson);
    } else {
      try {
        String encodedName = URLEncoder.encode("Intake Form Processing Pipeline", StandardCharsets.UTF_8);
        Map<String, Object> list = api("GET", "/workflows?name=" + encodedName, null);
        Object dataObj = list.get("data");
        List<Map<String, Object>> items = new ArrayList<>();

        if (dataObj instanceof String) {
          String dataStr = (String) dataObj;
          if (dataStr.startsWith("[")) {
            items = parseJsonArray(dataStr);
          }
        }

        for (Map<String, Object> item : items) {
          Object nameObj = item.get("name");
          Object idObj = item.get("id");
          if ("Intake Form Processing Pipeline".equals(nameObj) && idObj != null) {
            state.workflowId = idObj.toString();
            saveState();
            System.out.println("✓ workflow \"Intake Form Processing Pipeline\" found in your account (" + state.workflowId + ") — updating steps");
            String stepsJson = """
{"steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [{"step": "parse1"}]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {"text": {"agentic": {"enabled": true}}},
          "chunkingStrategy": {"type": "document"}
        }
      },
      "next": [{"step": "extraction2"}]
    },
    {
      "name": "extraction2",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "properties": {
              "age": {"type": ["integer", "null"], "description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth."},
              "sex": {"type": ["string", "null"], "description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations."},
              "height": {"type": ["string", "null"], "description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units."},
              "weight": {"type": ["number", "null"], "description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units."},
              "symptoms": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear)."},
                    "symptom_name": {"type": ["string", "null"], "description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations')."},
                    "symptom_details": {"type": ["string", "null"], "description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "symptom_name", "symptom_details"]
                },
                "description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context."
              },
              "form_date": {"type": ["string", "null"], "extend:type": "date", "description": "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided."},
              "surgeries": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "surgery_date": {"type": ["string", "null"], "description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing."},
                    "surgery_name": {"type": ["string", "null"], "description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy')."}
                  },
                  "additionalProperties": false,
                  "required": ["surgery_date", "surgery_name"]
                },
                "description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available."
              },
              "referred_by": {"type": ["string", "null"], "description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar."},
              "patient_name": {"type": ["string", "null"], "description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar."},
              "date_of_birth": {"type": ["string", "null"], "extend:type": "date", "description": "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc."},
              "marital_status": {"type": ["string", "null"], "description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar."},
              "chief_complaint": {"type": ["string", "null"], "description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar."},
              "medical_history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "present": {"type": ["boolean", "null"], "description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear)."},
                    "condition_name": {"type": ["string", "null"], "description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension')."},
                    "diagnosis_date": {"type": ["string", "null"], "description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing."}
                  },
                  "additionalProperties": false,
                  "required": ["present", "condition_name", "diagnosis_date"]
                },
                "description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status."
              },
              "hospitalizations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "hospitalization_date": {"type": ["string", "null"], "description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing."},
                    "hospitalization_reason": {"type": ["string", "null"], "description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation')."}
                  },
                  "additionalProperties": false,
                  "required": ["hospitalization_date", "hospitalization_reason"]
                },
                "description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period."
              },
              "medical_record_number": {"type": ["string", "null"], "description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters."},
              "primary_medical_doctor": {"type": ["string", "null"], "description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar."},
              "history_of_present_illness": {"type": ["string", "null"], "description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar."}
            },
            "required": ["age", "sex", "height", "weight", "symptoms", "form_date", "surgeries", "referred_by", "patient_name", "date_of_birth", "marital_status", "chief_complaint", "medical_history", "hospitalizations", "medical_record_number", "primary_medical_doctor", "history_of_present_illness"],
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {"enabled": true},
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
}""";
            api("POST", "/workflows/" + state.workflowId, stepsJson);
            return;
          }
        }
      } catch (Exception e) {
        // lookup is best-effort; fall through to create
      }

      if (state.workflowId == null || state.workflowId.isEmpty()) {
        Map<String, Object> created = api("POST", "/workflows", getWorkflowJson());
        String wfId = (String) created.get("id");
        if (wfId == null) {
          Object workflowObj = created.get("workflow");
          if (workflowObj instanceof Map) {
            wfId = (String) ((Map<String, Object>) workflowObj).get("id");
          }
        }
        if (wfId == null) {
          throw new Exception("Could not read created workflow id from response");
        }
        state.workflowId = wfId;
        saveState();
        System.out.println("+ created workflow (" + wfId + ")");
      }
    }

    try {
      api("POST", "/workflows/" + state.workflowId + "/versions", "{}");
    } catch (Exception e) {
      // best-effort: some accounts/plans may not require this explicit step
    }
  }

  private static List<Map<String, Object>> parseJsonArray(String json) {
    List<Map<String, Object>> result = new ArrayList<>();
    json = json.trim();
    if (!json.startsWith("[")) return result;

    json = json.substring(1, json.length() - 1);
    int depth = 0;
    StringBuilder current = new StringBuilder();
    boolean inString = false;
    boolean escaped = false;

    for (int i = 0; i < json.length(); i++) {
      char c = json.charAt(i);

      if (escaped) {
        current.append(c);
        escaped = false;
        continue;
      }

      if (c == '\\') {
        current.append(c);
        escaped = true;
        continue;
      }

      if (c == '"') {
        inString = !inString;
        current.append(c);
        continue;
      }

      if (!inString) {
        if (c == '{') {
          depth++;
        } else if (c == '}') {
          depth--;
          current.append(c);
          if (depth == 0) {
            String item = current.toString().trim();
            if (!item.isEmpty()) {
              result.add(parseJson(item));
            }
            current = new StringBuilder();
            continue;
          }
        } else if (c == ',' && depth == 0) {
          continue;
        }
      }

      current.append(c);
    }

    return result;
  }
}
// This code uses the Extend REST API directly because Extend has no official Go SDK yet.
// It deploys the "Intake Form" pipeline to your Extend account.
//
// Usage:
//   export EXTEND_API_KEY=sk_...   (from https://dashboard.extend.ai → API Keys)
//   go run provision.go
//
// Generated by doc1 (template: intake-form).

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
)

const (
	API     = "https://api.extend.ai"
	VERSION = "2026-02-09"
)

var (
	apiKey   string
	stateDir string
	stateFile string
)

type State struct {
	WorkflowID string `json:"workflowId,omitempty"`
}

var state State

func init() {
	apiKey = os.Getenv("EXTEND_API_KEY")
	if apiKey == "" {
		fmt.Fprintf(os.Stderr, "Set EXTEND_API_KEY first.\n")
		os.Exit(1)
	}

	cwd, err := os.Getwd()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get working directory: %v\n", err)
		os.Exit(1)
	}

	stateDir = filepath.Join(cwd, ".extend")
	stateFile = filepath.Join(stateDir, "intake-form.json")

	// Load existing state if it exists
	if data, err := os.ReadFile(stateFile); err == nil {
		json.Unmarshal(data, &state)
	}
}

func saveState() error {
	if err := os.MkdirAll(stateDir, 0755); err != nil {
		return err
	}
	data, err := json.MarshalIndent(state, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(stateFile, data, 0644)
}

func apiCall(method, pathName string, body interface{}) (map[string]interface{}, error) {
	var reqBody io.Reader
	if body != nil {
		data, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewReader(data)
	}

	req, err := http.NewRequest(method, API+pathName, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
	req.Header.Set("x-extend-api-version", VERSION)
	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respData := make(map[string]interface{})
	json.NewDecoder(resp.Body).Decode(&respData)

	if resp.StatusCode >= 400 {
		respBytes, _ := json.Marshal(respData)
		if len(respBytes) > 300 {
			respBytes = respBytes[:300]
		}
		return nil, fmt.Errorf("%s %s failed (%d): %s", method, pathName, resp.StatusCode, string(respBytes))
	}

	return respData, nil
}

var workflow = map[string]interface{}{
	"name": "Intake Form Processing Pipeline",
	"steps": []map[string]interface{}{
		{
			"name": "startTrigger1",
			"type": "TRIGGER",
			"next": []map[string]interface{}{
				{"step": "parse1"},
			},
		},
		{
			"name": "parse1",
			"type": "PARSE",
			"config": map[string]interface{}{
				"parseConfig": map[string]interface{}{
					"blockOptions": map[string]interface{}{
						"text": map[string]interface{}{
							"agentic": map[string]interface{}{
								"enabled": true,
							},
						},
					},
					"chunkingStrategy": map[string]interface{}{
						"type": "document",
					},
				},
			},
			"next": []map[string]interface{}{
				{"step": "extraction2"},
			},
		},
		{
			"name": "extraction2",
			"type": "EXTRACT",
			"config": map[string]interface{}{
				"extractorConfig": map[string]interface{}{
					"schema": map[string]interface{}{
						"type": "object",
						"properties": map[string]interface{}{
							"age": map[string]interface{}{
								"type":        []string{"integer", "null"},
								"description": "The patient's age in years at the time of form completion. May be explicitly stated or calculated from date of birth.",
							},
							"sex": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The patient's sex or gender as indicated on the form. May be labeled as 'Sex', 'Gender', or similar, and may include options such as 'Male', 'Female', or other designations.",
							},
							"height": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The patient's height, typically in feet/inches or centimeters. May be labeled as 'Height' and may include units.",
							},
							"weight": map[string]interface{}{
								"type":        []string{"number", "null"},
								"description": "The patient's weight, typically in pounds or kilograms. May be labeled as 'Weight' and may include units.",
							},
							"symptoms": map[string]interface{}{
								"type": "array",
								"items": map[string]interface{}{
									"type": "object",
									"properties": map[string]interface{}{
										"present": map[string]interface{}{
											"type":        []string{"boolean", "null"},
											"description": "Indicates whether the patient reports experiencing this symptom (true for present, false for absent, null if unclear).",
										},
										"symptom_name": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The name or description of the symptom (e.g., 'chest pain', 'shortness of breath', 'palpitations').",
										},
										"symptom_details": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "Additional details or context about the symptom, such as triggers, duration, or severity, if provided.",
										},
									},
									"additionalProperties": false,
									"required":             []string{"present", "symptom_name", "symptom_details"},
								},
								"description": "A list of symptoms the patient is currently experiencing or has experienced recently. Each item represents a distinct symptom or complaint, often indicated by checkboxes or written responses. May include details such as onset, frequency, or context.",
							},
							"form_date": map[string]interface{}{
								"type":              []string{"string", "null"},
								"extend:type":       "date",
								"description":       "The date the intake form was completed or reviewed. May be labeled as 'Date', 'Form Date', or similar. Used to track when the information was provided.",
							},
							"surgeries": map[string]interface{}{
								"type": "array",
								"items": map[string]interface{}{
									"type": "object",
									"properties": map[string]interface{}{
										"surgery_date": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The date or year the surgery was performed, if provided. May be partial (e.g., year only) or missing.",
										},
										"surgery_name": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The name or description of the surgical procedure (e.g., 'CABG', 'appendectomy').",
										},
									},
									"additionalProperties": false,
									"required":             []string{"surgery_date", "surgery_name"},
								},
								"description": "A list of surgical procedures the patient has undergone. Each item represents a distinct surgery, typically including the procedure name and date if available.",
							},
							"referred_by": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The name of the individual or provider who referred the patient to this clinic or provider. May be labeled as 'Referred by', 'Referral Source', or similar.",
							},
							"patient_name": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The full name of the patient completing or referenced in the intake form. This is the primary identifier for the individual receiving care. May appear with labels such as 'Patient Name', 'Name', or similar.",
							},
							"date_of_birth": map[string]interface{}{
								"type":              []string{"string", "null"},
								"extend:type":       "date",
								"description":       "The patient's date of birth. Used for age calculation and identification. May appear in various date formats and with labels such as 'DOB', 'Date of Birth', etc.",
							},
							"marital_status": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The patient's marital status as indicated on the form. May include options such as 'Single', 'Married', 'Widowed', 'Divorced', or similar.",
							},
							"chief_complaint": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The main reason for the patient's visit or referral, as described in their own words or by the referring provider. May be labeled as 'Chief Complaint', 'Reason for Visit', or similar.",
							},
							"medical_history": map[string]interface{}{
								"type": "array",
								"items": map[string]interface{}{
									"type": "object",
									"properties": map[string]interface{}{
										"present": map[string]interface{}{
											"type":        []string{"boolean", "null"},
											"description": "Indicates whether the patient currently has or has had this condition (true for present/history, false for never, null if unclear).",
										},
										"condition_name": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The name or description of the medical condition (e.g., 'coronary artery disease', 'diabetes', 'hypertension').",
										},
										"diagnosis_date": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The month and/or year the condition was diagnosed or first noted, if provided. May be partial (e.g., '08/2014') or missing.",
										},
									},
									"additionalProperties": false,
									"required":             []string{"present", "condition_name", "diagnosis_date"},
								},
								"description": "A list of the patient's current and past medical conditions, diagnoses, or significant health events. Each item represents a distinct condition, often indicated by checkboxes or written responses. May include details such as diagnosis date or status.",
							},
							"hospitalizations": map[string]interface{}{
								"type": "array",
								"items": map[string]interface{}{
									"type": "object",
									"properties": map[string]interface{}{
										"hospitalization_date": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The date, year, or time period of the hospitalization, if provided. May be partial or missing.",
										},
										"hospitalization_reason": map[string]interface{}{
											"type":        []string{"string", "null"},
											"description": "The main reason or diagnosis for the hospitalization (e.g., 'heart attack', 'CHF exacerbation').",
										},
									},
									"additionalProperties": false,
									"required":             []string{"hospitalization_date", "hospitalization_reason"},
								},
								"description": "A list of significant hospitalizations the patient has had. Each item represents a distinct hospitalization event, typically including the reason and date or time period.",
							},
							"medical_record_number": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The unique identifier assigned to the patient by the healthcare provider or facility. Commonly labeled as 'MRN', 'Medical Record Number', or similar. May include letters, numbers, or special characters.",
							},
							"primary_medical_doctor": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "The name of the patient's primary care physician or main medical provider. May be labeled as 'Primary Medical Doctor', 'Primary Care Provider', or similar.",
							},
							"history_of_present_illness": map[string]interface{}{
								"type":        []string{"string", "null"},
								"description": "A narrative description of the patient's current symptoms, their onset, duration, and progression. May include relevant context, associated symptoms, and prior interventions. Often labeled as 'History of Present Illness', 'HPI', or similar.",
							},
						},
						"required": []string{
							"age", "sex", "height", "weight", "symptoms", "form_date", "surgeries",
							"referred_by", "patient_name", "date_of_birth", "marital_status", "chief_complaint",
							"medical_history", "hospitalizations", "medical_record_number", "primary_medical_doctor",
							"history_of_present_illness",
						},
						"additionalProperties": false,
					},
					"baseProcessor": "extraction_performance",
					"advancedOptions": map[string]interface{}{
						"reviewAgent": map[string]interface{}{
							"enabled": true,
						},
						"advancedMultimodalEnabled": true,
					},
				},
			},
		},
	},
}

func main() {
	workflowName := workflow["name"].(string)
	fmt.Printf("Deploying \"%s\"…\n", workflowName)

	if state.WorkflowID != "" {
		fmt.Printf("✓ workflow already provisioned (%s) — updating steps\n", state.WorkflowID)
		_, err := apiCall("POST", fmt.Sprintf("/workflows/%s", state.WorkflowID), map[string]interface{}{
			"steps": workflow["steps"],
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
			os.Exit(1)
		}
	} else {
		// Try to find an existing workflow with the same name
		query := url.QueryEscape(workflowName)
		list, err := apiCall("GET", fmt.Sprintf("/workflows?name=%s", query), nil)
		if err == nil {
			var items []map[string]interface{}
			if data, ok := list["data"].([]interface{}); ok {
				for _, item := range data {
					items = append(items, item.(map[string]interface{}))
				}
			} else if data, ok := list["items"].([]interface{}); ok {
				for _, item := range data {
					items = append(items, item.(map[string]interface{}))
				}
			}

			for _, item := range items {
				if name, ok := item["name"].(string); ok && name == workflowName {
					if id, ok := item["id"].(string); ok {
						state.WorkflowID = id
						saveState()
						fmt.Printf("✓ workflow \"%s\" found in your account (%s) — updating steps\n", workflowName, id)
						_, err := apiCall("POST", fmt.Sprintf("/workflows/%s", id), map[string]interface{}{
							"steps": workflow["steps"],
						})
						if err != nil {
							fmt.Fprintf(os.Stderr, "%v\n", err)
							os.Exit(1)
						}
						break
					}
				}
			}
		}

		if state.WorkflowID == "" {
			created, err := apiCall("POST", "/workflows", workflow)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v\n", err)
				os.Exit(1)
			}

			var wfID string
			if id, ok := created["id"].(string); ok {
				wfID = id
			} else if wf, ok := created["workflow"].(map[string]interface{}); ok {
				if id, ok := wf["id"].(string); ok {
					wfID = id
				}
			}

			if wfID == "" {
				fmt.Fprintf(os.Stderr, "Could not read created workflow id from response\n")
				os.Exit(1)
			}

			state.WorkflowID = wfID
			saveState()
			fmt.Printf("+ created workflow (%s)\n", wfID)
		}
	}

	// Deploy the current draft as a new version (best-effort)
	apiCall("POST", fmt.Sprintf("/workflows/%s/versions", state.WorkflowID), map[string]interface{}{})

	fmt.Println("\nDone. Run documents through it with:")
	fmt.Printf("  POST %s/workflow_runs  { workflow: { id: \"%s\" }, file: { url: \"https://…\" } }\n", API, state.WorkflowID)
	fmt.Println("Or open the workflow in the Extend dashboard to review and deploy it.")
}

Frequently Asked Questions (FAQ)

Use `mode: "agentic_ocr"` in the parse step—it's designed to handle mixed handwriting and printed text. If handwriting confidence is low, add a human review step for those fields before downstream processing.
Nuanced question and depends on the use case! For an agent pipeline, you'll likely just stop at Parsing, take the markdown/HTML output and feed that into your pipeline. For Key-Value extraction into JSON, you can jump straight into Extraction because there is always a Parse step beforehand
Check `result.output.value` for null or empty fields and validate confidence by comparing parsed markdown against extracted values manually on a sample. In production, flag any extraction where required fields are null and route to human review.
Use the async `parseRuns.createAndPoll()` and `extract()` methods—they handle polling internally and work in serverless (Lambda, Vercel Functions). Set timeouts to 60–120 seconds depending on form page count; split multi-document intakes with `split()` first if latency is critical.
Tags
Patient IntakeCardiologyMedical HistorySymptom Assessment
About this template

An intake form documents patient demographics, complaints, symptom assessment, and detailed medical history. This template captures vital signs, referral information, and cardiovascular-specific conditions with dates for clinical evaluation and diagnosis support.

Document formats
  • PDF
  • Images & Scans
Requirements
  • Checkboxes & Strikethroughs
  • Long tables