InsuranceParse → Extract

Loss Run Report Extractor

Extracts claim details, injury descriptions, and financial summaries from workers' compensation claims.

Ship it with Extend

Live pipeline

a real document, processed end to end · view only
Source documentloss_run_2 (1).jpeg

Step-by-step

A claim summary is a loss run report issued by an insurance carrier that documents all active and closed injury claims, including claimant details, injury circumstances, claim status indicators, and financial summaries broken down by indemnity, medical, and expense categories. This template takes in loss run claim summaries and outputs markdown (.md) capturing the document's full text and layout, and JSON (.json) with structured claim fields including employee information, injury dates, claim status flags, financial totals by category, and report metadata per the extraction schema by using Extend's Parse, Extract primitives.

Input
loss run claim summaries
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

Parse workers' compensation claim summary to markdown

InputSource document (PDF, image, or scan)
Config
blockOptions.text.agentic.enabledtruechanged
chunkingStrategy.type"document"
engine"parse_performance"
Outputmarkdown (.md) capturing the document's full text, tables, and layout

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

Step 2

Extract

Extract workers' compensation claim summary fields

InputOutput of the previous step
Config
schemacustom schema — 5 fieldschanged
advancedOptions.advancedMultimodalEnabledtruechanged
advancedOptions.reviewAgent.enabledtruechanged
baseProcessor"extraction_performance"
OutputJSON (.json) with structured fields per the extraction schema

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

Example code

{
  "name": "Workers' Compensation Claim Summary 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": [
              "claims",
              "program",
              "employer",
              "date_printed",
              "valued_as_of"
            ],
            "properties": {
              "claims": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "sdtf",
                    "status",
                    "surgery",
                    "adjuster",
                    "litigated",
                    "longshore",
                    "voc_rehab",
                    "claim_type",
                    "controvert",
                    "date_hired",
                    "financials",
                    "fraudulent",
                    "occupation",
                    "settlement",
                    "subrogated",
                    "case_manager",
                    "claim_number",
                    "employee_ssn",
                    "jurisdiction",
                    "employee_name",
                    "date_of_injury",
                    "emp_report_date",
                    "carrier_entry_date",
                    "carrier_notify_date",
                    "accident_description"
                  ],
                  "properties": {
                    "sdtf": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."
                    },
                    "surgery": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."
                    },
                    "adjuster": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."
                    },
                    "litigated": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."
                    },
                    "longshore": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."
                    },
                    "voc_rehab": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."
                    },
                    "claim_type": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."
                    },
                    "controvert": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."
                    },
                    "date_hired": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
                      "extend:type": "date"
                    },
                    "financials": {
                      "type": "object",
                      "required": [
                        "total",
                        "expense",
                        "medical",
                        "indemnity"
                      ],
                      "properties": {
                        "total": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount recovered on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount reserved for this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total net incurred amount for this claim (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount incurred during the current month."
                            }
                          },
                          "description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
                          "additionalProperties": false
                        },
                        "expense": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total expense payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for expenses on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for expenses on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred expense amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The expense amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The expense amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for the expense portion of the claim.",
                          "additionalProperties": false
                        },
                        "medical": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total medical payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for medical on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for medical payments on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred medical amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The medical amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The medical amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for the medical portion of the claim.",
                          "additionalProperties": false
                        },
                        "indemnity": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total indemnity payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for indemnity on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for indemnity payments on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred indemnity amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The indemnity amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The indemnity amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for indemnity (wage replacement) portion of the claim.",
                          "additionalProperties": false
                        }
                      },
                      "description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
                      "additionalProperties": false
                    },
                    "fraudulent": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."
                    },
                    "occupation": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."
                    },
                    "settlement": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."
                    },
                    "subrogated": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."
                    },
                    "case_manager": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or identifier of the case manager handling this claim, if applicable."
                    },
                    "claim_number": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."
                    },
                    "employee_ssn": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."
                    },
                    "jurisdiction": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."
                    },
                    "employee_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."
                    },
                    "date_of_injury": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
                      "extend:type": "date"
                    },
                    "emp_report_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
                      "extend:type": "date"
                    },
                    "carrier_entry_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
                      "extend:type": "date"
                    },
                    "carrier_notify_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
                      "extend:type": "date"
                    },
                    "accident_description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats."
              },
              "program": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."
              },
              "employer": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."
              },
              "date_printed": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
                "extend:type": "date"
              },
              "valued_as_of": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
                "extend:type": "date"
              }
            },
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {
              "enabled": true
            },
            "advancedMultimodalEnabled": true
          }
        }
      }
    }
  ]
}
# Workers' Compensation Claim Summary Processing — Extend AI Skill

## What this pipeline does

This pipeline ingests Workers' Compensation Claim Summary documents (typically multi-page loss run reports) and extracts structured claim data including employee details, injury dates, claim status flags, and detailed financial breakdowns by category (medical, indemnity, expense). It uses agentic OCR to handle complex table layouts and embedded claim data, then extracts into a nested JSON schema with per-claim financials and document-level metadata.

## When to use this

- **Loss run ingestion**: Automatically parse carrier-issued loss run reports into normalized JSON for downstream claim management systems.
- **Bulk claim data import**: Process monthly or quarterly loss run snapshots to populate claims databases with current reserves, payments, and incurred amounts.
- **Claims analytics & reporting**: Extract structured financial data to feed BI dashboards, actuarial analyses, or compliance audits.
- **Litigation/settlement tracking**: Capture claim status flags (litigated, settled, controverted, fraudulent) for case management and reserves forecasting.
- **Multi-jurisdiction consolidation**: Handle loss runs from different states/jurisdictions and normalize claim and financial data into a single schema.

## Processor pipeline

### Step 1: Parse with agentic OCR
**Processor**: `parse_performance` with agentic text extraction enabled  
**Purpose**: Convert PDF (often scanned or mixed-format) into clean markdown preserving table structure and claim boundaries  
**Key config**:
- `engine: "parse_performance"` — higher-fidelity parsing for complex, multi-section documents
- `blockOptions.text.agentic.enabled: true` — enables LLM-assisted OCR for handwriting, degraded scans, and non-standard layouts
- `chunkingStrategy.type: "document"` — keeps entire loss run as one logical chunk (critical for table context)

**Why**: Loss run reports mix structured tables with narrative descriptions and status flags. Agentic OCR handles scanned carrier documents, watermarks, and irregular column alignment that pure CV-based parsing fails on. Document-level chunking preserves claim groupings and financial rollups.

### Step 2: Extract structured fields
**Processor**: `extraction_performance` with review agent enabled  
**Purpose**: Parse markdown into nested JSON schema capturing claim-level and document-level metadata, with per-category financials  
**Key config**:
- `baseProcessor: "extraction_performance"` — production-grade extraction with internal validation
- `advancedOptions.reviewAgent.enabled: true` — LLM verifies extracted numbers and flags (e.g., "Y"/"N" fields), catches numeric formatting issues
- `advancedOptions.advancedMultimodalEnabled: true` — leverages parsed layout info for table cell association

**Why**: The schema is deep (4-level nesting: document → claims array → claim → financials → {total, medical, indemnity, expense} objects). Review agent catches common errors: misaligned reserve/payment columns, swapped medical/indemnity subtotals, dates in unexpected formats. Advanced multimodal uses visual bounding boxes from parse step to correctly align table values.

---

## TypeScript implementation



---

## CLI equivalent

```bash
# Step 1: Parse loss run to markdown
extend parse loss_run_sample.pdf

# Step 2: Extract structured claim data using the schema
extend extract loss_run_sample.pdf \
  --schema wc-claims-schema.json \
  --processor extraction_performance

# Or run the pre-configured workflow (if saved in your Extend account)
extend run workflow_wc_claim_summary \
  --file loss_run_sample.pdf
```

Where `wc-claims-schema.json` is the full extraction schema (see Schema section below).

---

## Schema

```json
{
  "type": "object",
  "properties": {
    "employer": {
      "type": ["string", "null"],
      "description": "Name of employer or insured organization. This is the entity covered by the workers' compensation policy."
    },
    "program": {
      "type": ["string", "null"],
      "description": "Insurance program, policy, or coverage type. May be a program name, code, or description of the coverage structure."
    },
    "date_printed": {
      "type": ["string", "null"],
      "extend:type": "date",
      "description": "Report generation or print date (ISO yyyy-mm-dd format). This is the official date of the loss run document."
    },
    "valued_as_of": {
      "type": ["string", "null"],
      "extend:type": "date",
      "description": "Valuation date for all financial figures in the report (ISO yyyy-mm-dd). All reserves, payments, and inc
import fs from "fs";
import { ExtendClient, extendDate, extendCurrency } from "extend-ai";
import { z } from "zod";

/**
 * Zod schema for Workers' Compensation Claim Summary extraction.
 * Mirrors the nested structure: document metadata + array of claims with financials.
 */
const claimFinancialsSchema = z.object({
  payments: z.number().nullable().describe("Total payments made to date"),
  recovery: z.number().nullable().describe("Total amount recovered"),
  reserves: z.number().nullable().describe("Total amount reserved"),
  net_incurred: z.number().nullable().describe("Net incurred (reserves + payments - recoveries)"),
  paid_this_month: z.number().nullable().describe("Amount paid this month"),
  incurred_this_month: z.number().nullable().describe("Amount incurred this month"),
});

const claimSchema = z.object({
  // Identifiers
  claim_number: z.string().nullable().describe("Unique claim identifier (e.g., 'CLM-2024-001234')"),
  employee_name: z.string().nullable().describe("Name of the injured worker"),
  employee_ssn: z.string().nullable().describe("Social Security Number (may be redacted)"),
  
  // Dates
  date_of_injury: extendDate().describe("Date of injury incident (ISO yyyy-mm-dd)"),
  emp_report_date: extendDate().describe("Date employee reported the injury"),
  carrier_notify_date: extendDate().describe("Date insurance carrier was notified"),
  carrier_entry_date: extendDate().describe("Date claim was entered into carrier system"),
  date_hired: extendDate().describe("Employee hire date"),
  
  // Claim details
  occupation: z.string().nullable().describe("Job title at time of injury"),
  jurisdiction: z.string().nullable().describe("State/jurisdiction where claim is filed"),
  claim_type: z.string().nullable().describe("Claim type (e.g., 'Medical Only', 'Indemnity', 'Lost Time')"),
  status: z.string().nullable().describe("Current status (e.g., 'Open', 'Closed')"),
  accident_description: z.string().nullable().describe("Narrative description of the accident or injury"),
  
  // Status flags (typically Y/N)
  surgery: z.string().nullable().describe("Surgery performed? (Y/N or similar)"),
  litigated: z.string().nullable().describe("Claim in litigation? (Y/N)"),
  settled: z.string().nullable().describe("Claim settled? (Y/N)"),
  controvert: z.string().nullable().describe("Claim controverted/disputed? (Y/N)"),
  voc_rehab: z.string().nullable().describe("Vocational rehabilitation provided? (Y/N)"),
  subrogated: z.string().nullable().describe("Claim subrogated? (Y/N)"),
  fraudulent: z.string().nullable().describe("Suspected/confirmed fraud? (Y/N)"),
  sdtf: z.string().nullable().describe("Subject to Second Disability Trust Fund? (Y/N)"),
  longshore: z.string().nullable().describe("Subject to LHWCA or similar? (Y/N)"),
  
  // Personnel
  adjuster: z.string().nullable().describe("Assigned claims adjuster name or ID"),
  case_manager: z.string().nullable().describe("Case manager name or ID, if applicable"),
  
  // Financials: broken down by category (medical, indemnity, expense) plus total
  financials: z.object({
    total: claimFinancialsSchema.describe("Total across all categories"),
    medical: claimFinancialsSchema.describe("Medical portion only"),
    indemnity: claimFinancialsSchema.describe("Indemnity (wage replacement) portion only"),
    expense: claimFinancialsSchema.describe("Expenses portion only"),
  }).describe("Financial summary: reserves, payments, recoveries, net incurred, and monthly values by category"),
});

const lossRunSchema = z.object({
  employer: z.string().nullable().describe("Name of employer/insured organization"),
  program: z.string().nullable().describe("Insurance program or coverage type"),
  date_printed: extendDate().describe("Report generation/print date (ISO yyyy-mm-dd)"),
  valued_as_of: extendDate().describe("Valuation date for all amounts in the report (ISO yyyy-mm-dd)"),
  claims: z.array(claimSchema).describe("Array of individual claims in this loss run"),
});

/**
 * Process a Workers' Compensation Claim Summary loss run document.
 * Uploads the file, parses it with agentic OCR, then extracts structured claim data.
 * @param filePath Path to local loss run PDF file
 */
async function processWorkersCompensationClaimSummary(filePath: string) {
  const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });

  console.log(`[WC Loss Run] Processing: ${filePath}`);

  // Convert local file to data URL (base64)
  const fileBuffer = fs.readFileSync(filePath);
  const base64 = fileBuffer.toString("base64");
  const dataUrl = `data:application/pdf;base64,${base64}`;

  // Step 1: Parse the loss run with agentic OCR
  console.log("[Step 1/2] Parsing loss run with agentic OCR...");
  const parseRun = await client.parseRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      mode: "agentic_ocr", // Scanned, handwritten, or complex table layouts
      outputType: "markdown",
    },
  });

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

  const parsedMarkdown = parseRun.output.chunks
    .map((chunk) => chunk.content)
    .join("\n\n");

  console.log(
    `[Step 1/2] Parsed ${parseRun.output.chunks.length} chunks. ` +
    `Markdown length: ${parsedMarkdown.length} characters.`
  );

  // Step 2: Extract structured claim data
  console.log("[Step 2/2] Extracting structured claim data...");
  const extractRun = await client.extractRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      schema: lossRunSchema,
      baseProcessor: "extraction_performance", // Production-grade extraction
    },
  });

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

  const lossRunData = extractRun.output.value;

  console.log(`[Step 2/2] Extraction complete.`);
  console.log(`Employer: ${lossRunData.employer}`);
  console.log(`Program: ${lossRunData.program}`);
  console.log(`Report Date: ${lossRunData.date_printed}`);
  console.log(`Valued As Of: ${lossRunData.valued_as_of}`);
  console.log(`Total Claims: ${lossRunData.claims.length}`);

  // Example: Print first claim summary (if any)
  if (lossRunData.claims.length > 0) {
    const firstClaim = lossRunData.claims[0];
    console.log(`\n[Sample Claim #1]`);
    console.log(`  Claim #: ${firstClaim.claim_number}`);
    console.log(`  Employee: ${firstClaim.employee_name}`);
    console.log(`  DOI: ${firstClaim.date_of_injury}`);
    console.log(`  Status: ${firstClaim.status}`);
    console.log(`  Total Net Incurred: $${firstClaim.financials.total.net_incurred?.toFixed(2) ?? "N/A"}`);
  }

  // Return full structured data for downstream processing
  return {
    status: "success",
    document: {
      employer: lossRunData.employer,
      program: lossRunData.program,
      dateReported: lossRunData.date_printed,
      valuedAsOf: lossRunData.valued_as_of,
    },
    claims: lossRunData.claims.map((claim) => ({
      claimNumber: claim.claim_number,
      employeeName: claim.employee_name,
      employeeSSN: claim.employee_ssn,
      dateOfInjury: claim.date_of_injury,
      occupation: claim.occupation,
      jurisdiction: claim.jurisdiction,
      claimType: claim.claim_type,
      status: claim.status,
      accidentDescription: claim.accident_description,
      flags: {
        surgery: claim.surgery,
        litigated: claim.litigated,
        settled: claim.settled,
        controverted: claim.controvert,
        vocRehab: claim.voc_rehab,
        subrogated: claim.subrogated,
        fraudulent: claim.fraudulent,
        sdtf: claim.sdtf,
        longshore: claim.longshore,
      },
      personnel: {
        adjuster: claim.adjuster,
        caseManager: claim.case_manager,
      },
      financials: {
        total: {
          payments: claim.financials.total.payments,
          recovery: claim.financials.total.recovery,
          reserves: claim.financials.total.reserves,
          netIncurred: claim.financials.total.net_incurred,
          paidThisMonth: claim.financials.total.paid_this_month,
          incurredThisMonth: claim.financials.total.incurred_this_month,
        },
        medical: {
          payments: claim.financials.medical.payments,
          recovery: claim.financials.medical.recovery,
          reserves: claim.financials.medical.reserves,
          netIncurred: claim.financials.medical.net_incurred,
          paidThisMonth: claim.financials.medical.paid_this_month,
          incurredThisMonth: claim.financials.medical.incurred_this_month,
        },
        indemnity: {
          payments: claim.financials.indemnity.payments,
          recovery: claim.financials.indemnity.recovery,
          reserves: claim.financials.indemnity.reserves,
          netIncurred: claim.financials.indemnity.net_incurred,
          paidThisMonth: claim.financials.indemnity.paid_this_month,
          incurredThisMonth: claim.financials.indemnity.incurred_this_month,
        },
        expense: {
          payments: claim.financials.expense.payments,
          recovery: claim.financials.expense.recovery,
          reserves: claim.financials.expense.reserves,
          netIncurred: claim.financials.expense.net_incurred,
          paidThisMonth: claim.financials.expense.paid_this_month,
          incurredThisMonth: claim.financials.expense.incurred_this_month,
        },
      },
    })),
    rawMarkdown: parsedMarkdown, // Useful for debugging or RAG
  };
}

// Auto-invoke if run directly
const filePath = process.argv[2] || "__FILE_PATH__";
processWorkersCompensationClaimSummary(filePath)
  .then((result) => {
    console.log("\n=== EXTRACTION RESULT ===");
    console.log(JSON.stringify(result, null, 2));
  })
  .catch((error) => {
    console.error("Error:", error.message);
    process.exit(1);
  });
import os
import json
from typing import Optional
from extend_ai import Extend
from pydantic import BaseModel, Field

# Define nested financial schema
class ClaimFinancials(BaseModel):
    payments: Optional[float] = Field(None, description="Total payments made to date")
    recovery: Optional[float] = Field(None, description="Total amount recovered")
    reserves: Optional[float] = Field(None, description="Total amount reserved")
    net_incurred: Optional[float] = Field(None, description="Net incurred (reserves + payments - recoveries)")
    paid_this_month: Optional[float] = Field(None, description="Amount paid this month")
    incurred_this_month: Optional[float] = Field(None, description="Amount incurred this month")

# Define claim schema
class Claim(BaseModel):
    # Identifiers
    claim_number: Optional[str] = Field(None, description="Unique claim identifier (e.g., 'CLM-2024-001234')")
    employee_name: Optional[str] = Field(None, description="Name of the injured worker")
    employee_ssn: Optional[str] = Field(None, description="Social Security Number (may be redacted)")
    
    # Dates
    date_of_injury: Optional[str] = Field(None, description="Date of injury incident (ISO yyyy-mm-dd)")
    emp_report_date: Optional[str] = Field(None, description="Date employee reported the injury")
    carrier_notify_date: Optional[str] = Field(None, description="Date insurance carrier was notified")
    carrier_entry_date: Optional[str] = Field(None, description="Date claim was entered into carrier system")
    date_hired: Optional[str] = Field(None, description="Employee hire date")
    
    # Claim details
    occupation: Optional[str] = Field(None, description="Job title at time of injury")
    jurisdiction: Optional[str] = Field(None, description="State/jurisdiction where claim is filed")
    claim_type: Optional[str] = Field(None, description="Claim type (e.g., 'Medical Only', 'Indemnity', 'Lost Time')")
    status: Optional[str] = Field(None, description="Current status (e.g., 'Open', 'Closed')")
    accident_description: Optional[str] = Field(None, description="Narrative description of the accident or injury")
    
    # Status flags
    surgery: Optional[str] = Field(None, description="Surgery performed? (Y/N or similar)")
    litigated: Optional[str] = Field(None, description="Claim in litigation? (Y/N)")
    settlement: Optional[str] = Field(None, description="Claim settled? (Y/N)")
    controvert: Optional[str] = Field(None, description="Claim controverted/disputed? (Y/N)")
    voc_rehab: Optional[str] = Field(None, description="Vocational rehabilitation provided? (Y/N)")
    subrogated: Optional[str] = Field(None, description="Claim subrogated? (Y/N)")
    fraudulent: Optional[str] = Field(None, description="Suspected/confirmed fraud? (Y/N)")
    sdtf: Optional[str] = Field(None, description="Subject to Second Disability Trust Fund? (Y/N)")
    longshore: Optional[str] = Field(None, description="Subject to LHWCA or similar? (Y/N)")
    
    # Personnel
    adjuster: Optional[str] = Field(None, description="Assigned claims adjuster name or ID")
    case_manager: Optional[str] = Field(None, description="Case manager name or ID, if applicable")
    
    # Financials
    class FinancialsNested(BaseModel):
        total: ClaimFinancials = Field(description="Total across all categories")
        medical: ClaimFinancials = Field(description="Medical portion only")
        indemnity: ClaimFinancials = Field(description="Indemnity (wage replacement) portion only")
        expense: ClaimFinancials = Field(description="Expenses portion only")
    
    financials: FinancialsNested = Field(description="Financial summary: reserves, payments, recoveries, net incurred, and monthly values by category")

# Define loss run schema
class LossRun(BaseModel):
    employer: Optional[str] = Field(None, description="Name of employer/insured organization")
    program: Optional[str] = Field(None, description="Insurance program or coverage type")
    date_printed: Optional[str] = Field(None, description="Report generation/print date (ISO yyyy-mm-dd)")
    valued_as_of: Optional[str] = Field(None, description="Valuation date for all amounts in the report (ISO yyyy-mm-dd)")
    claims: list[Claim] = Field(description="Array of individual claims in this loss run")

def process_workers_compensation_claim_summary(file_path: str) -> dict:
    """
    Process a Workers' Compensation Claim Summary loss run document.
    Uploads the file, parses it with agentic OCR, then extracts structured claim data.
    
    Args:
        file_path: Path to local loss run PDF file
    
    Returns:
        Dictionary containing extracted structured data
    """
    client = Extend(token=os.getenv("EXTEND_API_KEY"))
    
    print(f"[WC Loss Run] Processing: {file_path}")
    
    # Convert local file to data URL (base64)
    with open(file_path, "rb") as f:
        file_buffer = f.read()
    base64_str = __import__("base64").b64encode(file_buffer).decode("utf-8")
    data_url = f"data:application/pdf;base64,{base64_str}"
    
    # Step 1: Parse the loss run with agentic OCR
    print("[Step 1/2] Parsing loss run with agentic OCR...")
    parse_run = client.parse_runs.create_and_poll(
        file={"url": data_url},
        config={
            "mode": "agentic_ocr",
            "output_type": "markdown",
        }
    )
    
    if parse_run.status != "PROCESSED":
        raise Exception(f"Parse failed with status: {parse_run.status}")
    
    parsed_markdown = "\n\n".join(chunk.content for chunk in parse_run.output.chunks)
    
    print(
        f"[Step 1/2] Parsed {len(parse_run.output.chunks)} chunks. "
        f"Markdown length: {len(parsed_markdown)} characters."
    )
    
    # Step 2: Extract structured claim data
    print("[Step 2/2] Extracting structured claim data...")
    extract_run = client.extract_runs.create_and_poll(
        file={"url": data_url},
        config={
            "schema": LossRun,
            "base_processor": "extraction_performance",
        }
    )
    
    if extract_run.status != "PROCESSED":
        raise Exception(f"Extraction failed with status: {extract_run.status}")
    
    loss_run_data = extract_run.output.value
    
    print("[Step 2/2] Extraction complete.")
    print(f"Employer: {loss_run_data.employer}")
    print(f"Program: {loss_run_data.program}")
    print(f"Report Date: {loss_run_data.date_printed}")
    print(f"Valued As Of: {loss_run_data.valued_as_of}")
    print(f"Total Claims: {len(loss_run_data.claims)}")
    
    # Example: Print first claim summary (if any)
    if loss_run_data.claims:
        first_claim = loss_run_data.claims[0]
        print(f"\n[Sample Claim #1]")
        print(f"  Claim #: {first_claim.claim_number}")
        print(f"  Employee: {first_claim.employee_name}")
        print(f"  DOI: {first_claim.date_of_injury}")
        print(f"  Status: {first_claim.status}")
        net_incurred = first_claim.financials.total.net_incurred
        print(f"  Total Net Incurred: ${net_incurred:.2f if net_incurred else 'N/A'}")
    
    # Return full structured data for downstream processing
    return {
        "status": "success",
        "document": {
            "employer": loss_run_data.employer,
            "program": loss_run_data.program,
            "date_reported": loss_run_data.date_printed,
            "valued_as_of": loss_run_data.valued_as_of,
        },
        "claims": [
            {
                "claim_number": claim.claim_number,
                "employee_name": claim.employee_name,
                "employee_ssn": claim.employee_ssn,
                "date_of_injury": claim.date_of_injury,
                "occupation": claim.occupation,
                "jurisdiction": claim.jurisdiction,
                "claim_type": claim.claim_type,
                "status": claim.status,
                "accident_description": claim.accident_description,
                "flags": {
                    "surgery": claim.surgery,
                    "litigated": claim.litigated,
                    "settled": claim.settlement,
                    "controverted": claim.controvert,
                    "voc_rehab": claim.voc_rehab,
                    "subrogated": claim.subrogated,
                    "fraudulent": claim.fraudulent,
                    "sdtf": claim.sdtf,
                    "longshore": claim.longshore,
                },
                "personnel": {
                    "adjuster": claim.adjuster,
                    "case_manager": claim.case_manager,
                },
                "financials": {
                    "total": {
                        "payments": claim.financials.total.payments,
                        "recovery": claim.financials.total.recovery,
                        "reserves": claim.financials.total.reserves,
                        "net_incurred": claim.financials.total.net_incurred,
                        "paid_this_month": claim.financials.total.paid_this_month,
                        "incurred_this_month": claim.financials.total.incurred_this_month,
                    },
                    "medical": {
                        "payments": claim.financials.medical.payments,
                        "recovery": claim.financials.medical.recovery,
                        "reserves": claim.financials.medical.reserves,
                        "net_incurred": claim.financials.medical.net_incurred,
                        "paid_this_month": claim.financials.medical.paid_this_month,
                        "incurred_this_month": claim.financials.medical.incurred_this_month,
                    },
                    "indemnity": {
                        "payments": claim.financials.indemnity.payments,
                        "recovery": claim.financials.indemnity.recovery,
                        "reserves": claim.financials.indemnity.reserves,
                        "net_incurred": claim.financials.indemnity.net_incurred,
                        "paid_this_month": claim.financials.indemnity.paid_this_month,
                        "incurred_this_month": claim.financials.indemnity.incurred_this_month,
                    },
                    "expense": {
                        "payments": claim.financials.expense.payments,
                        "recovery": claim.financials.expense.recovery,
                        "reserves": claim.financials.expense.reserves,
                        "net_incurred": claim.financials.expense.net_incurred,
                        "paid_this_month": claim.financials.expense.paid_this_month,
                        "incurred_this_month": claim.financials.expense.incurred_this_month,
                    },
                },
            }
            for claim in loss_run_data.claims
        ],
        "raw_markdown": parsed_markdown,
    }

# Auto-invoke if run directly
if __name__ == "__main__":
    import sys
    
    file_path = sys.argv[1] if len(sys.argv) > 1 else "__FILE_PATH__"
    
    try:
        result = process_workers_compensation_claim_summary(file_path)
        print("\n=== EXTRACTION RESULT ===")
        print(json.dumps(result, indent=2))
    except Exception as e:
        print(f"Error: {str(e)}", file=sys.stderr)
        sys.exit(1)
import java.io.IOException;
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;

import com.extend.client.ExtendClient;
import com.extend.client.models.ExtractRunRequest;
import com.extend.client.models.ExtractRunResult;
import com.extend.client.models.ParseRunRequest;
import com.extend.client.models.ParseRunResult;
import com.extend.client.models.FileInput;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Process a Workers' Compensation Claim Summary loss run document.
 * Uploads the file, parses it with agentic OCR, then extracts structured claim data.
 */
public class WorkersCompensationClaimSummaryProcessor {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static void main(String[] args) throws IOException {
        String filePath = args.length > 0 ? args[0] : "__FILE_PATH__";
        try {
            Map<String, Object> result = processWorkersCompensationClaimSummary(filePath);
            System.out.println("\n=== EXTRACTION RESULT ===");
            System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(result));
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            System.exit(1);
        }
    }

    public static Map<String, Object> processWorkersCompensationClaimSummary(String filePath) 
            throws IOException, InterruptedException {
        String apiKey = System.getenv("EXTEND_API_KEY");
        ExtendClient client = new ExtendClient.Builder().token(apiKey).build();

        System.out.println("[WC Loss Run] Processing: " + filePath);

        // Convert local file to data URL (base64)
        byte[] fileBuffer = Files.readAllBytes(Paths.get(filePath));
        String base64 = Base64.getEncoder().encodeToString(fileBuffer);
        String dataUrl = "data:application/pdf;base64," + base64;

        // Step 1: Parse the loss run with agentic OCR
        System.out.println("[Step 1/2] Parsing loss run with agentic OCR...");
        ParseRunRequest parseRequest = ParseRunRequest.builder()
                .file(new FileInput(dataUrl))
                .mode("agentic_ocr")
                .outputType("markdown")
                .build();

        ParseRunResult parseRun = client.parseRuns().createAndPoll(parseRequest);

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

        StringBuilder parsedMarkdown = new StringBuilder();
        int chunkCount = parseRun.getOutput().getChunks().size();
        for (Map<String, Object> chunk : parseRun.getOutput().getChunks()) {
            if (parsedMarkdown.length() > 0) {
                parsedMarkdown.append("\n\n");
            }
            parsedMarkdown.append(chunk.get("content"));
        }

        System.out.println("[Step 1/2] Parsed " + chunkCount + " chunks. " +
                "Markdown length: " + parsedMarkdown.length() + " characters.");

        // Step 2: Extract structured claim data
        System.out.println("[Step 2/2] Extracting structured claim data...");
        
        Map<String, Object> schemaMap = buildLossRunSchema();
        
        ExtractRunRequest extractRequest = ExtractRunRequest.builder()
                .file(new FileInput(dataUrl))
                .schema(schemaMap)
                .baseProcessor("extraction_performance")
                .build();

        ExtractRunResult extractRun = client.extractRuns().createAndPoll(extractRequest);

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

        Map<String, Object> lossRunData = (Map<String, Object>) extractRun.getOutput().getValue();

        System.out.println("[Step 2/2] Extraction complete.");
        System.out.println("Employer: " + lossRunData.get("employer"));
        System.out.println("Program: " + lossRunData.get("program"));
        System.out.println("Report Date: " + lossRunData.get("date_printed"));
        System.out.println("Valued As Of: " + lossRunData.get("valued_as_of"));

        List<Map<String, Object>> claims = (List<Map<String, Object>>) lossRunData.get("claims");
        System.out.println("Total Claims: " + claims.size());

        // Example: Print first claim summary (if any)
        if (!claims.isEmpty()) {
            Map<String, Object> firstClaim = claims.get(0);
            System.out.println("\n[Sample Claim #1]");
            System.out.println("  Claim #: " + firstClaim.get("claim_number"));
            System.out.println("  Employee: " + firstClaim.get("employee_name"));
            System.out.println("  DOI: " + firstClaim.get("date_of_injury"));
            System.out.println("  Status: " + firstClaim.get("status"));

            Map<String, Object> financials = (Map<String, Object>) firstClaim.get("financials");
            Map<String, Object> total = (Map<String, Object>) financials.get("total");
            Object netIncurred = total.get("net_incurred");
            String netIncurredStr = netIncurred != null ? String.format("%.2f", netIncurred) : "N/A";
            System.out.println("  Total Net Incurred: $" + netIncurredStr);
        }

        // Build return structure
        Map<String, Object> document = new HashMap<>();
        document.put("employer", lossRunData.get("employer"));
        document.put("program", lossRunData.get("program"));
        document.put("dateReported", lossRunData.get("date_printed"));
        document.put("valuedAsOf", lossRunData.get("valued_as_of"));

        List<Map<String, Object>> processedClaims = new ArrayList<>();
        for (Map<String, Object> claim : claims) {
            processedClaims.add(transformClaim(claim));
        }

        Map<String, Object> result = new HashMap<>();
        result.put("status", "success");
        result.put("document", document);
        result.put("claims", processedClaims);
        result.put("rawMarkdown", parsedMarkdown.toString());

        return result;
    }

    private static Map<String, Object> transformClaim(Map<String, Object> claim) {
        Map<String, Object> transformed = new HashMap<>();
        transformed.put("claimNumber", claim.get("claim_number"));
        transformed.put("employeeName", claim.get("employee_name"));
        transformed.put("employeeSSN", claim.get("employee_ssn"));
        transformed.put("dateOfInjury", claim.get("date_of_injury"));
        transformed.put("occupation", claim.get("occupation"));
        transformed.put("jurisdiction", claim.get("jurisdiction"));
        transformed.put("claimType", claim.get("claim_type"));
        transformed.put("status", claim.get("status"));
        transformed.put("accidentDescription", claim.get("accident_description"));

        Map<String, Object> flags = new HashMap<>();
        flags.put("surgery", claim.get("surgery"));
        flags.put("litigated", claim.get("litigated"));
        flags.put("settled", claim.get("settlement"));
        flags.put("controverted", claim.get("controvert"));
        flags.put("vocRehab", claim.get("voc_rehab"));
        flags.put("subrogated", claim.get("subrogated"));
        flags.put("fraudulent", claim.get("fraudulent"));
        flags.put("sdtf", claim.get("sdtf"));
        flags.put("longshore", claim.get("longshore"));
        transformed.put("flags", flags);

        Map<String, Object> personnel = new HashMap<>();
        personnel.put("adjuster", claim.get("adjuster"));
        personnel.put("caseManager", claim.get("case_manager"));
        transformed.put("personnel", personnel);

        Map<String, Object> claimFinancials = (Map<String, Object>) claim.get("financials");
        Map<String, Object> financials = new HashMap<>();
        financials.put("total", transformFinancialCategory((Map<String, Object>) claimFinancials.get("total")));
        financials.put("medical", transformFinancialCategory((Map<String, Object>) claimFinancials.get("medical")));
        financials.put("indemnity", transformFinancialCategory((Map<String, Object>) claimFinancials.get("indemnity")));
        financials.put("expense", transformFinancialCategory((Map<String, Object>) claimFinancials.get("expense")));
        transformed.put("financials", financials);

        return transformed;
    }

    private static Map<String, Object> transformFinancialCategory(Map<String, Object> category) {
        Map<String, Object> transformed = new HashMap<>();
        transformed.put("payments", category.get("payments"));
        transformed.put("recovery", category.get("recovery"));
        transformed.put("reserves", category.get("reserves"));
        transformed.put("netIncurred", category.get("net_incurred"));
        transformed.put("paidThisMonth", category.get("paid_this_month"));
        transformed.put("incurredThisMonth", category.get("incurred_this_month"));
        return transformed;
    }

    private static Map<String, Object> buildLossRunSchema() {
        Map<String, Object> schema = new HashMap<>();
        schema.put("type", "object");

        Map<String, Object> properties = new HashMap<>();

        // employer
        Map<String, Object> employer = new HashMap<>();
        employer.put("type", new Object[]{"string", "null"});
        employer.put("description", "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.");
        properties.put("employer", employer);

        // program
        Map<String, Object> program = new HashMap<>();
        program.put("type", new Object[]{"string", "null"});
        program.put("description", "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.");
        properties.put("program", program);

        // date_printed
        Map<String, Object> datePrinted = new HashMap<>();
        datePrinted.put("type", new Object[]{"string", "null"});
        datePrinted.put("extend:type", "date");
        datePrinted.put("description", "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.");
        properties.put("date_printed", datePrinted);

        // valued_as_of
        Map<String, Object> valuedAsOf = new HashMap<>();
        valuedAsOf.put("type", new Object[]{"string", "null"});
        valuedAsOf.put("extend:type", "date");
        valuedAsOf.put("description", "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.");
        properties.put("valued_as_of", valuedAsOf);

        // claims array
        Map<String, Object> claimsArray = new HashMap<>();
        claimsArray.put("type", "array");
        claimsArray.put("items", buildClaimItemSchema());
        claimsArray.put("description", "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.");
        properties.put("claims", claimsArray);

        schema.put("properties", properties);
        schema.put("required", new String[]{"claims", "program", "employer", "date_printed", "valued_as_of"});
        schema.put("additionalProperties", false);

        return schema;
    }

    private static Map<String, Object> buildClaimItemSchema() {
        Map<String, Object> claimSchema = new HashMap<>();
        claimSchema.put("type", "object");

        Map<String, Object> properties = new HashMap<>();

        // Identifiers
        properties.put("claim_number", stringProperty("The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."));
        properties.put("employee_name", stringProperty("The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."));
        properties.put("employee_ssn", stringProperty("The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."));

        // Dates
        properties.put("date_of_injury", dateProperty("The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar."));
        properties.put("emp_report_date", dateProperty("The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar."));
        properties.put("carrier_notify_date", dateProperty("The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'."));
        properties.put("carrier_entry_date", dateProperty("The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'."));
        properties.put("date_hired", dateProperty("The date the employee was hired by the employer. May be labeled as 'Date Hired'."));

        // Claim details
        properties.put("occupation", stringProperty("The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."));
        properties.put("jurisdiction", stringProperty("The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."));
        properties.put("claim_type", stringProperty("The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."));
        properties.put("status", stringProperty("The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."));
        properties.put("accident_description", stringProperty("A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."));

        // Status flags
        properties.put("surgery", stringProperty("Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."));
        properties.put("litigated", stringProperty("Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."));
        properties.put("settlement", stringProperty("Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."));
        properties.put("controvert", stringProperty("Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."));
        properties.put("voc_rehab", stringProperty("Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."));
        properties.put("subrogated", stringProperty("Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."));
        properties.put("fraudulent", stringProperty("Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."));
        properties.put("sdtf", stringProperty("Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."));
        properties.put("longshore", stringProperty("Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."));

        // Personnel
        properties.put("adjuster", stringProperty("The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."));
        properties.put("case_manager", stringProperty("The name or identifier of the case manager handling this claim, if applicable."));

        // Financials
        properties.put("financials", buildFinancialsSchema());

        claimSchema.put("properties", properties);
        claimSchema.put("required", new String[]{
            "sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab",
            "claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation",
            "settlement", "subrogated", "case_manager", "claim_number", "employee_ssn",
            "jurisdiction", "employee_name", "date_of_injury", "emp_report_date",
            "carrier_entry_date", "carrier_notify_date", "accident_description"
        });
        claimSchema.put("additionalProperties", false);

        return claimSchema;
    }

    private static Map<String, Object> buildFinancialsSchema() {
        Map<String, Object> financials = new HashMap<>();
        financials.put("type", "object");

        Map<String, Object> properties = new HashMap<>();
        properties.put("total", buildFinancialCategorySchema("Total financials for this claim, summing indemnity, medical, and expense categories."));
        properties.put("medical", buildFinancialCategorySchema("Financial details for the medical portion of the claim."));
        properties.put("indemnity", buildFinancialCategorySchema("Financial details for indemnity (wage replacement) portion of the claim."));
        properties.put("expense", buildFinancialCategorySchema("Financial details for the expense portion of the claim."));

        financials.put("properties", properties);
        financials.put("required", new String[]{"total", "expense", "medical", "indemnity"});
        financials.put("additionalProperties", false);
        financials.put("description", "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.");

        return financials;
    }

    private static Map<String, Object> buildFinancialCategorySchema(String description) {
        Map<String, Object> category = new HashMap<>();
        category.put("type", "object");

        Map<String, Object> properties = new HashMap<>();
        properties.put("payments", numberProperty("Total payments made to date"));
        properties.put("recovery", numberProperty("Total amount recovered"));
        properties.put("reserves", numberProperty("Total amount reserved"));
        properties.put("net_incurred", numberProperty("Net incurred (reserves + payments - recoveries)"));
        properties.put("paid_this_month", numberProperty("Amount paid this month"));
        properties.put("incurred_this_month", numberProperty("Amount incurred this month"));

        category.put("properties", properties);
        category.put("required", new String[]{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"});
        category.put("additionalProperties", false);
        category.put("description", description);

        return category;
    }

    private static Map<String, Object> stringProperty(String description) {
        Map<String, Object> prop = new HashMap<>();
        prop.put("type", new Object[]{"string", "null"});
        prop.put("description", description);
        return prop;
    }

    private static Map<String, Object> dateProperty(String description) {
        Map<String, Object> prop = new HashMap<>();
        prop.put("type", new Object[]{"string", "null"});
        prop.put("extend:type", "date");
        prop.put("description", description);
        return prop;
    }

    private static Map<String, Object> numberProperty(String description) {
        Map<String, Object> prop = new HashMap<>();
        prop.put("type", new Object[]{"number", "null"});
        prop.put("description", description);
        return prop;
    }
}
package main

import (
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/extend-ai/extend-go/client"
	"github.com/extend-ai/extend-go/types"
)

// ClaimFinancials represents the financial details for a claim category.
type ClaimFinancials struct {
	Payments         *float64 `json:"payments"`
	Recovery         *float64 `json:"recovery"`
	Reserves         *float64 `json:"reserves"`
	NetIncurred      *float64 `json:"net_incurred"`
	PaidThisMonth    *float64 `json:"paid_this_month"`
	IncurredThisMonth *float64 `json:"incurred_this_month"`
}

// ClaimFinancialsCategory groups financials by category.
type ClaimFinancialsCategory struct {
	Total    ClaimFinancials `json:"total"`
	Medical  ClaimFinancials `json:"medical"`
	Indemnity ClaimFinancials `json:"indemnity"`
	Expense  ClaimFinancials `json:"expense"`
}

// Claim represents a single workers' compensation claim.
type Claim struct {
	ClaimNumber        *string                   `json:"claim_number"`
	EmployeeName       *string                   `json:"employee_name"`
	EmployeeSSN        *string                   `json:"employee_ssn"`
	DateOfInjury       *string                   `json:"date_of_injury"`
	EmpReportDate      *string                   `json:"emp_report_date"`
	CarrierNotifyDate  *string                   `json:"carrier_notify_date"`
	CarrierEntryDate   *string                   `json:"carrier_entry_date"`
	DateHired          *string                   `json:"date_hired"`
	Occupation         *string                   `json:"occupation"`
	Jurisdiction       *string                   `json:"jurisdiction"`
	ClaimType          *string                   `json:"claim_type"`
	Status             *string                   `json:"status"`
	AccidentDescription *string                   `json:"accident_description"`
	Surgery            *string                   `json:"surgery"`
	Litigated          *string                   `json:"litigated"`
	Settled            *string                   `json:"settlement"`
	Controvert         *string                   `json:"controvert"`
	VocRehab           *string                   `json:"voc_rehab"`
	Subrogated         *string                   `json:"subrogated"`
	Fraudulent         *string                   `json:"fraudulent"`
	SDTF               *string                   `json:"sdtf"`
	Longshore          *string                   `json:"longshore"`
	Adjuster           *string                   `json:"adjuster"`
	CaseManager        *string                   `json:"case_manager"`
	Financials         ClaimFinancialsCategory  `json:"financials"`
}

// LossRun represents the complete loss run document.
type LossRun struct {
	Employer      *string `json:"employer"`
	Program       *string `json:"program"`
	DatePrinted   *string `json:"date_printed"`
	ValuedAsOf    *string `json:"valued_as_of"`
	Claims        []Claim `json:"claims"`
}

// ExtractionResult is the output structure returned by the processing function.
type ExtractionResult struct {
	Status      string                 `json:"status"`
	Document    DocumentInfo           `json:"document"`
	Claims      []ProcessedClaim       `json:"claims"`
	RawMarkdown string                 `json:"rawMarkdown"`
}

// DocumentInfo contains document-level metadata.
type DocumentInfo struct {
	Employer      *string `json:"employer"`
	Program       *string `json:"program"`
	DateReported  *string `json:"dateReported"`
	ValuedAsOf    *string `json:"valuedAsOf"`
}

// ProcessedClaim is the normalized output structure for each claim.
type ProcessedClaim struct {
	ClaimNumber         *string           `json:"claimNumber"`
	EmployeeName        *string           `json:"employeeName"`
	EmployeeSSN         *string           `json:"employeeSSN"`
	DateOfInjury        *string           `json:"dateOfInjury"`
	Occupation          *string           `json:"occupation"`
	Jurisdiction        *string           `json:"jurisdiction"`
	ClaimType           *string           `json:"claimType"`
	Status              *string           `json:"status"`
	AccidentDescription *string           `json:"accidentDescription"`
	Flags               ClaimFlags        `json:"flags"`
	Personnel           PersonnelInfo     `json:"personnel"`
	Financials          ProcessedFinancials `json:"financials"`
}

// ClaimFlags groups boolean/status flags.
type ClaimFlags struct {
	Surgery      *string `json:"surgery"`
	Litigated    *string `json:"litigated"`
	Settled      *string `json:"settled"`
	Controverted *string `json:"controverted"`
	VocRehab     *string `json:"vocRehab"`
	Subrogated   *string `json:"subrogated"`
	Fraudulent   *string `json:"fraudulent"`
	SDTF         *string `json:"sdtf"`
	Longshore    *string `json:"longshore"`
}

// PersonnelInfo groups assigned personnel.
type PersonnelInfo struct {
	Adjuster    *string `json:"adjuster"`
	CaseManager *string `json:"caseManager"`
}

// ProcessedFinancials groups financial data by category.
type ProcessedFinancials struct {
	Total    FinancialCategory `json:"total"`
	Medical  FinancialCategory `json:"medical"`
	Indemnity FinancialCategory `json:"indemnity"`
	Expense  FinancialCategory `json:"expense"`
}

// FinancialCategory represents a single financial category.
type FinancialCategory struct {
	Payments         *float64 `json:"payments"`
	Recovery         *float64 `json:"recovery"`
	Reserves         *float64 `json:"reserves"`
	NetIncurred      *float64 `json:"netIncurred"`
	PaidThisMonth    *float64 `json:"paidThisMonth"`
	IncurredThisMonth *float64 `json:"incurredThisMonth"`
}

// ProcessWorkersCompensationClaimSummary processes a workers' compensation loss run document.
// It uploads the file, parses it with agentic OCR, then extracts structured claim data.
func ProcessWorkersCompensationClaimSummary(filePath string) (*ExtractionResult, error) {
	c := client.NewExtendClient(client.WithToken(os.Getenv("EXTEND_API_KEY")))

	log.Printf("[WC Loss Run] Processing: %s", filePath)

	// Convert local file to data URL (base64)
	fileBuffer, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %w", err)
	}
	base64Str := base64.StdEncoding.EncodeToString(fileBuffer)
	dataURL := fmt.Sprintf("data:application/pdf;base64,%s", base64Str)

	// Step 1: Parse the loss run with agentic OCR
	log.Println("[Step 1/2] Parsing loss run with agentic OCR...")
	parseRun, err := c.ParseRuns.CreateAndPoll(&types.ParseRunConfig{
		File: &types.FileInput{URL: dataURL},
		Config: &types.ParseConfig{
			Mode:       "agentic_ocr",
			OutputType: "markdown",
		},
	})
	if err != nil {
		return nil, fmt.Errorf("parse failed: %w", err)
	}

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

	var parsedMarkdown string
	for _, chunk := range parseRun.Output.Chunks {
		parsedMarkdown += chunk.Content + "\n\n"
	}

	log.Printf("[Step 1/2] Parsed %d chunks. Markdown length: %d characters.",
		len(parseRun.Output.Chunks), len(parsedMarkdown))

	// Step 2: Extract structured claim data
	log.Println("[Step 2/2] Extracting structured claim data...")
	lossRunSchema := map[string]interface{}{
		"type": "object",
		"properties": map[string]interface{}{
			"employer":      map[string]interface{}{"type": []interface{}{"string", "null"}},
			"program":       map[string]interface{}{"type": []interface{}{"string", "null"}},
			"date_printed":  map[string]interface{}{"type": []interface{}{"string", "null"}, "extend:type": "date"},
			"valued_as_of":  map[string]interface{}{"type": []interface{}{"string", "null"}, "extend:type": "date"},
			"claims":        map[string]interface{}{"type": "array"},
		},
	}

	extractRun, err := c.ExtractRuns.CreateAndPoll(&types.ExtractRunConfig{
		File: &types.FileInput{URL: dataURL},
		Config: &types.ExtractConfig{
			Schema:        lossRunSchema,
			BaseProcessor: "extraction_performance",
		},
	})
	if err != nil {
		return nil, fmt.Errorf("extraction failed: %w", err)
	}

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

	// Parse the output into LossRun struct
	outputBytes, _ := json.Marshal(extractRun.Output.Value)
	var lossRunData LossRun
	if err := json.Unmarshal(outputBytes, &lossRunData); err != nil {
		return nil, fmt.Errorf("failed to parse extracted data: %w", err)
	}

	log.Println("[Step 2/2] Extraction complete.")
	if lossRunData.Employer != nil {
		log.Printf("Employer: %s", *lossRunData.Employer)
	}
	if lossRunData.Program != nil {
		log.Printf("Program: %s", *lossRunData.Program)
	}
	if lossRunData.DatePrinted != nil {
		log.Printf("Report Date: %s", *lossRunData.DatePrinted)
	}
	if lossRunData.ValuedAsOf != nil {
		log.Printf("Valued As Of: %s", *lossRunData.ValuedAsOf)
	}
	log.Printf("Total Claims: %d", len(lossRunData.Claims))

	// Example: Print first claim summary (if any)
	if len(lossRunData.Claims) > 0 {
		firstClaim := lossRunData.Claims[0]
		log.Println("\n[Sample Claim #1]")
		if firstClaim.ClaimNumber != nil {
			log.Printf("  Claim #: %s", *firstClaim.ClaimNumber)
		}
		if firstClaim.EmployeeName != nil {
			log.Printf("  Employee: %s", *firstClaim.EmployeeName)
		}
		if firstClaim.DateOfInjury != nil {
			log.Printf("  DOI: %s", *firstClaim.DateOfInjury)
		}
		if firstClaim.Status != nil {
			log.Printf("  Status: %s", *firstClaim.Status)
		}
		if firstClaim.Financials.Total.NetIncurred != nil {
			log.Printf("  Total Net Incurred: $%.2f", *firstClaim.Financials.Total.NetIncurred)
		}
	}

	// Build result structure
	result := &ExtractionResult{
		Status: "success",
		Document: DocumentInfo{
			Employer:     lossRunData.Employer,
			Program:      lossRunData.Program,
			DateReported: lossRunData.DatePrinted,
			ValuedAsOf:   lossRunData.ValuedAsOf,
		},
		Claims:      make([]ProcessedClaim, len(lossRunData.Claims)),
		RawMarkdown: parsedMarkdown,
	}

	for i, claim := range lossRunData.Claims {
		result.Claims[i] = ProcessedClaim{
			ClaimNumber:         claim.ClaimNumber,
			EmployeeName:        claim.EmployeeName,
			EmployeeSSN:         claim.EmployeeSSN,
			DateOfInjury:        claim.DateOfInjury,
			Occupation:          claim.Occupation,
			Jurisdiction:        claim.Jurisdiction,
			ClaimType:           claim.ClaimType,
			Status:              claim.Status,
			AccidentDescription: claim.AccidentDescription,
			Flags: ClaimFlags{
				Surgery:      claim.Surgery,
				Litigated:    claim.Litigated,
				Settled:      claim.Settled,
				Controverted: claim.Controvert,
				VocRehab:     claim.VocRehab,
				Subrogated:   claim.Subrogated,
				Fraudulent:   claim.Fraudulent,
				SDTF:         claim.SDTF,
				Longshore:    claim.Longshore,
			},
			Personnel: PersonnelInfo{
				Adjuster:    claim.Adjuster,
				CaseManager: claim.CaseManager,
			},
			Financials: ProcessedFinancials{
				Total: FinancialCategory{
					Payments:         claim.Financials.Total.Payments,
					Recovery:         claim.Financials.Total.Recovery,
					Reserves:         claim.Financials.Total.Reserves,
					NetIncurred:      claim.Financials.Total.NetIncurred,
					PaidThisMonth:    claim.Financials.Total.PaidThisMonth,
					IncurredThisMonth: claim.Financials.Total.IncurredThisMonth,
				},
				Medical: FinancialCategory{
					Payments:         claim.Financials.Medical.Payments,
					Recovery:         claim.Financials.Medical.Recovery,
					Reserves:         claim.Financials.Medical.Reserves,
					NetIncurred:      claim.Financials.Medical.NetIncurred,
					PaidThisMonth:    claim.Financials.Medical.PaidThisMonth,
					IncurredThisMonth: claim.Financials.Medical.IncurredThisMonth,
				},
				Indemnity: FinancialCategory{
					Payments:         claim.Financials.Indemnity.Payments,
					Recovery:         claim.Financials.Indemnity.Recovery,
					Reserves:         claim.Financials.Indemnity.Reserves,
					NetIncurred:      claim.Financials.Indemnity.NetIncurred,
					PaidThisMonth:    claim.Financials.Indemnity.PaidThisMonth,
					IncurredThisMonth: claim.Financials.Indemnity.IncurredThisMonth,
				},
				Expense: FinancialCategory{
					Payments:         claim.Financials.Expense.Payments,
					Recovery:         claim.Financials.Expense.Recovery,
					Reserves:         claim.Financials.Expense.Reserves,
					NetIncurred:      claim.Financials.Expense.NetIncurred,
					PaidThisMonth:    claim.Financials.Expense.PaidThisMonth,
					IncurredThisMonth: claim.Financials.Expense.IncurredThisMonth,
				},
			},
		}
	}

	return result, nil
}

func main() {
	flag.Parse()
	filePath := flag.Arg(0)
	if filePath == "" {
		filePath = "__FILE_PATH__"
	}

	result, err := ProcessWorkersCompensationClaimSummary(filePath)
	if err != nil {
		log.Fatalf("Error: %v", err)
	}

	log.Println("\n=== EXTRACTION RESULT ===")
	resultJSON, _ := json.MarshalIndent(result, "", "  ")
	fmt.Println(string(resultJSON))
}
// Deploy the "Workers' Compensation Claim Summary" 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/loss-run-report.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: loss-run-report).

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, "loss-run-report.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": "Workers' Compensation Claim Summary 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": [
              "claims",
              "program",
              "employer",
              "date_printed",
              "valued_as_of"
            ],
            "properties": {
              "claims": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "sdtf",
                    "status",
                    "surgery",
                    "adjuster",
                    "litigated",
                    "longshore",
                    "voc_rehab",
                    "claim_type",
                    "controvert",
                    "date_hired",
                    "financials",
                    "fraudulent",
                    "occupation",
                    "settlement",
                    "subrogated",
                    "case_manager",
                    "claim_number",
                    "employee_ssn",
                    "jurisdiction",
                    "employee_name",
                    "date_of_injury",
                    "emp_report_date",
                    "carrier_entry_date",
                    "carrier_notify_date",
                    "accident_description"
                  ],
                  "properties": {
                    "sdtf": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."
                    },
                    "status": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."
                    },
                    "surgery": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."
                    },
                    "adjuster": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."
                    },
                    "litigated": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."
                    },
                    "longshore": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."
                    },
                    "voc_rehab": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."
                    },
                    "claim_type": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."
                    },
                    "controvert": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."
                    },
                    "date_hired": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
                      "extend:type": "date"
                    },
                    "financials": {
                      "type": "object",
                      "required": [
                        "total",
                        "expense",
                        "medical",
                        "indemnity"
                      ],
                      "properties": {
                        "total": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount recovered on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount reserved for this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total net incurred amount for this claim (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total amount incurred during the current month."
                            }
                          },
                          "description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
                          "additionalProperties": false
                        },
                        "expense": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total expense payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for expenses on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for expenses on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred expense amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The expense amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The expense amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for the expense portion of the claim.",
                          "additionalProperties": false
                        },
                        "medical": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total medical payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for medical on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for medical payments on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred medical amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The medical amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The medical amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for the medical portion of the claim.",
                          "additionalProperties": false
                        },
                        "indemnity": {
                          "type": "object",
                          "required": [
                            "payments",
                            "recovery",
                            "reserves",
                            "net_incurred",
                            "paid_this_month",
                            "incurred_this_month"
                          ],
                          "properties": {
                            "payments": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The total indemnity payments made to date on this claim."
                            },
                            "recovery": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount recovered for indemnity on this claim."
                            },
                            "reserves": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The amount reserved for indemnity payments on this claim."
                            },
                            "net_incurred": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The net incurred indemnity amount (reserves plus payments minus recoveries)."
                            },
                            "paid_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The indemnity amount paid during the current month."
                            },
                            "incurred_this_month": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "The indemnity amount incurred during the current month."
                            }
                          },
                          "description": "Financial details for indemnity (wage replacement) portion of the claim.",
                          "additionalProperties": false
                        }
                      },
                      "description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
                      "additionalProperties": false
                    },
                    "fraudulent": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."
                    },
                    "occupation": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."
                    },
                    "settlement": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."
                    },
                    "subrogated": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."
                    },
                    "case_manager": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name or identifier of the case manager handling this claim, if applicable."
                    },
                    "claim_number": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."
                    },
                    "employee_ssn": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."
                    },
                    "jurisdiction": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."
                    },
                    "employee_name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."
                    },
                    "date_of_injury": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
                      "extend:type": "date"
                    },
                    "emp_report_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
                      "extend:type": "date"
                    },
                    "carrier_entry_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
                      "extend:type": "date"
                    },
                    "carrier_notify_date": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
                      "extend:type": "date"
                    },
                    "accident_description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats."
              },
              "program": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."
              },
              "employer": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."
              },
              "date_printed": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
                "extend:type": "date"
              },
              "valued_as_of": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
                "extend:type": "date"
              }
            },
            "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); });
#!/usr/bin/env python3
"""
Deploy the "Workers' Compensation Claim Summary" 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/loss-run-report.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)
    python provision.py

Generated by doc1 (template: loss-run-report).
"""

import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, Optional

import httpx

API = "https://api.extend.ai"
VERSION = "2026-02-09"
API_KEY = os.getenv("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 / "loss-run-report.json"


def load_state() -> Dict[str, Any]:
    if STATE_FILE.exists():
        return json.loads(STATE_FILE.read_text())
    return {}


def save_state(state: Dict[str, Any]) -> None:
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    STATE_FILE.write_text(json.dumps(state, indent=2))


async def api(
    method: str, path_name: str, body: Optional[Dict[str, Any]] = None
) -> Any:
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "x-extend-api-version": VERSION,
    }
    if body:
        headers["Content-Type"] = "application/json"

    async with httpx.AsyncClient() as client:
        res = await client.request(
            method,
            API + path_name,
            headers=headers,
            json=body,
        )
        try:
            data = res.json()
        except Exception:
            data = {}

        if not res.is_success:
            error_msg = json.dumps(data)[:300]
            raise RuntimeError(
                f"{method} {path_name} failed ({res.status_code}): {error_msg}"
            )
        return data


WORKFLOW = {
    "name": "Workers' Compensation Claim Summary 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": [
                            "claims",
                            "program",
                            "employer",
                            "date_printed",
                            "valued_as_of",
                        ],
                        "properties": {
                            "claims": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "sdtf",
                                        "status",
                                        "surgery",
                                        "adjuster",
                                        "litigated",
                                        "longshore",
                                        "voc_rehab",
                                        "claim_type",
                                        "controvert",
                                        "date_hired",
                                        "financials",
                                        "fraudulent",
                                        "occupation",
                                        "settlement",
                                        "subrogated",
                                        "case_manager",
                                        "claim_number",
                                        "employee_ssn",
                                        "jurisdiction",
                                        "employee_name",
                                        "date_of_injury",
                                        "emp_report_date",
                                        "carrier_entry_date",
                                        "carrier_notify_date",
                                        "accident_description",
                                    ],
                                    "properties": {
                                        "sdtf": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "status": {
                                            "type": ["string", "null"],
                                            "description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'.",
                                        },
                                        "surgery": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "adjuster": {
                                            "type": ["string", "null"],
                                            "description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'.",
                                        },
                                        "litigated": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "longshore": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "voc_rehab": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "claim_type": {
                                            "type": ["string", "null"],
                                            "description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'.",
                                        },
                                        "controvert": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "date_hired": {
                                            "type": ["string", "null"],
                                            "description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
                                            "extend:type": "date",
                                        },
                                        "financials": {
                                            "type": "object",
                                            "required": ["total", "expense", "medical", "indemnity"],
                                            "properties": {
                                                "total": {
                                                    "type": "object",
                                                    "required": [
                                                        "payments",
                                                        "recovery",
                                                        "reserves",
                                                        "net_incurred",
                                                        "paid_this_month",
                                                        "incurred_this_month",
                                                    ],
                                                    "properties": {
                                                        "payments": {
                                                            "type": ["number", "null"],
                                                            "description": "The total payments made to date on this claim.",
                                                        },
                                                        "recovery": {
                                                            "type": ["number", "null"],
                                                            "description": "The total amount recovered on this claim.",
                                                        },
                                                        "reserves": {
                                                            "type": ["number", "null"],
                                                            "description": "The total amount reserved for this claim.",
                                                        },
                                                        "net_incurred": {
                                                            "type": ["number", "null"],
                                                            "description": "The total net incurred amount for this claim (reserves plus payments minus recoveries).",
                                                        },
                                                        "paid_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The total amount paid during the current month.",
                                                        },
                                                        "incurred_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The total amount incurred during the current month.",
                                                        },
                                                    },
                                                    "description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
                                                    "additionalProperties": False,
                                                },
                                                "expense": {
                                                    "type": "object",
                                                    "required": [
                                                        "payments",
                                                        "recovery",
                                                        "reserves",
                                                        "net_incurred",
                                                        "paid_this_month",
                                                        "incurred_this_month",
                                                    ],
                                                    "properties": {
                                                        "payments": {
                                                            "type": ["number", "null"],
                                                            "description": "The total expense payments made to date on this claim.",
                                                        },
                                                        "recovery": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount recovered for expenses on this claim.",
                                                        },
                                                        "reserves": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount reserved for expenses on this claim.",
                                                        },
                                                        "net_incurred": {
                                                            "type": ["number", "null"],
                                                            "description": "The net incurred expense amount (reserves plus payments minus recoveries).",
                                                        },
                                                        "paid_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The expense amount paid during the current month.",
                                                        },
                                                        "incurred_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The expense amount incurred during the current month.",
                                                        },
                                                    },
                                                    "description": "Financial details for the expense portion of the claim.",
                                                    "additionalProperties": False,
                                                },
                                                "medical": {
                                                    "type": "object",
                                                    "required": [
                                                        "payments",
                                                        "recovery",
                                                        "reserves",
                                                        "net_incurred",
                                                        "paid_this_month",
                                                        "incurred_this_month",
                                                    ],
                                                    "properties": {
                                                        "payments": {
                                                            "type": ["number", "null"],
                                                            "description": "The total medical payments made to date on this claim.",
                                                        },
                                                        "recovery": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount recovered for medical on this claim.",
                                                        },
                                                        "reserves": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount reserved for medical payments on this claim.",
                                                        },
                                                        "net_incurred": {
                                                            "type": ["number", "null"],
                                                            "description": "The net incurred medical amount (reserves plus payments minus recoveries).",
                                                        },
                                                        "paid_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The medical amount paid during the current month.",
                                                        },
                                                        "incurred_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The medical amount incurred during the current month.",
                                                        },
                                                    },
                                                    "description": "Financial details for the medical portion of the claim.",
                                                    "additionalProperties": False,
                                                },
                                                "indemnity": {
                                                    "type": "object",
                                                    "required": [
                                                        "payments",
                                                        "recovery",
                                                        "reserves",
                                                        "net_incurred",
                                                        "paid_this_month",
                                                        "incurred_this_month",
                                                    ],
                                                    "properties": {
                                                        "payments": {
                                                            "type": ["number", "null"],
                                                            "description": "The total indemnity payments made to date on this claim.",
                                                        },
                                                        "recovery": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount recovered for indemnity on this claim.",
                                                        },
                                                        "reserves": {
                                                            "type": ["number", "null"],
                                                            "description": "The amount reserved for indemnity payments on this claim.",
                                                        },
                                                        "net_incurred": {
                                                            "type": ["number", "null"],
                                                            "description": "The net incurred indemnity amount (reserves plus payments minus recoveries).",
                                                        },
                                                        "paid_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The indemnity amount paid during the current month.",
                                                        },
                                                        "incurred_this_month": {
                                                            "type": ["number", "null"],
                                                            "description": "The indemnity amount incurred during the current month.",
                                                        },
                                                    },
                                                    "description": "Financial details for indemnity (wage replacement) portion of the claim.",
                                                    "additionalProperties": False,
                                                },
                                            },
                                            "description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
                                            "additionalProperties": False,
                                        },
                                        "fraudulent": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "occupation": {
                                            "type": ["string", "null"],
                                            "description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'.",
                                        },
                                        "settlement": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "subrogated": {
                                            "type": ["string", "null"],
                                            "description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary.",
                                        },
                                        "case_manager": {
                                            "type": ["string", "null"],
                                            "description": "The name or identifier of the case manager handling this claim, if applicable.",
                                        },
                                        "claim_number": {
                                            "type": ["string", "null"],
                                            "description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value.",
                                        },
                                        "employee_ssn": {
                                            "type": ["string", "null"],
                                            "description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy.",
                                        },
                                        "jurisdiction": {
                                            "type": ["string", "null"],
                                            "description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'.",
                                        },
                                        "employee_name": {
                                            "type": ["string", "null"],
                                            "description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'.",
                                        },
                                        "date_of_injury": {
                                            "type": ["string", "null"],
                                            "description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
                                            "extend:type": "date",
                                        },
                                        "emp_report_date": {
                                            "type": ["string", "null"],
                                            "description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
                                            "extend:type": "date",
                                        },
                                        "carrier_entry_date": {
                                            "type": ["string", "null"],
                                            "description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
                                            "extend:type": "date",
                                        },
                                        "carrier_notify_date": {
                                            "type": ["string", "null"],
                                            "description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
                                            "extend:type": "date",
                                        },
                                        "accident_description": {
                                            "type": ["string", "null"],
                                            "description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where.",
                                        },
                                    },
                                    "additionalProperties": False,
                                },
                                "description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.",
                            },
                            "program": {
                                "type": ["string", "null"],
                                "description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.",
                            },
                            "employer": {
                                "type": ["string", "null"],
                                "description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.",
                            },
                            "date_printed": {
                                "type": ["string", "null"],
                                "description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
                                "extend:type": "date",
                            },
                            "valued_as_of": {
                                "type": ["string", "null"],
                                "description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
                                "extend:type": "date",
                            },
                        },
                        "additionalProperties": False,
                    },
                    "baseProcessor": "extraction_performance",
                    "advancedOptions": {
                        "reviewAgent": {
                            "enabled": True,
                        },
                        "advancedMultimodalEnabled": True,
                    },
                }
            },
        },
    ],
}


async def main() -> None:
    state = load_state()
    print(f'Deploying "{WORKFLOW["name"]}…"')

    if state.get("workflowId"):
        wf_id = state["workflowId"]
        print(f"✓ workflow already provisioned ({wf_id}) — updating steps")
        await api("POST", f"/workflows/{wf_id}", {"steps": WORKFLOW["steps"]})
    else:
        try:
            list_resp = await api(
                "GET",
                f"/workflows?name={httpx.URL(WORKFLOW['name']).params}",
            )
            items = list_resp.get("data") or list_resp.get("items") or []
            existing = next(
                (item for item in items if item.get("name") == WORKFLOW["name"]),
                None,
            )
            if existing and existing.get("id"):
                state["workflowId"] = existing["id"]
                save_state(state)
                print(
                    f'✓ workflow "{WORKFLOW["name"]}" found in your account ({existing["id"]}) — updating steps'
                )
                await api(
                    "POST",
                    f"/workflows/{existing['id']}",
                    {"steps": WORKFLOW["steps"]},
                )
        except Exception:
            pass

        if not state.get("workflowId"):
            created = await api("POST", "/workflows", WORKFLOW)
            wf_id = created.get("id") or created.get("workflow", {}).get("id")
            if not wf_id:
                raise RuntimeError(
                    "Could not read created workflow id from response"
                )
            state["workflowId"] = wf_id
            save_state(state)
            print(f"+ created workflow ({wf_id})")

    wf_id = state["workflowId"]
    try:
        await api("POST", f"/workflows/{wf_id}/versions", {})
    except Exception:
        pass

    print("\nDone. Run documents through it with:")
    print(
        f'  POST {API}/workflow_runs  {{ workflow: {{ id: "{wf_id}" }}, file: {{ url: "https://…" }} }}'
    )
    print("Or open the workflow in the Extend dashboard to review and deploy it.")


if __name__ == "__main__":
    import asyncio

    try:
        asyncio.run(main())
    except Exception as e:
        print(str(e), file=sys.stderr)
        sys.exit(1)
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class WorkersCompensationProvisioner {
  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("loss-run-report.json");
  private static final ObjectMapper MAPPER = new ObjectMapper();
  private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();

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

  static class State {
    public String workflowId;

    public State() {}
    public State(String workflowId) { this.workflowId = workflowId; }
  }

  private static State loadState() throws IOException {
    if (Files.exists(STATE_FILE)) {
      return MAPPER.readValue(STATE_FILE.toFile(), State.class);
    }
    return new State();
  }

  private static void saveState(State state) throws IOException {
    Files.createDirectories(STATE_DIR);
    MAPPER.writerWithDefaultPrettyPrinter().writeValue(STATE_FILE.toFile(), state);
  }

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

    if (body != null) {
      String jsonBody = MAPPER.writeValueAsString(body);
      requestBuilder.header("Content-Type", "application/json");
      requestBuilder.method(method, HttpRequest.BodyPublishers.ofString(jsonBody));
    } else {
      requestBuilder.method(method, HttpRequest.BodyPublishers.noBody());
    }

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

    Map<String, Object> data = new LinkedHashMap<>();
    if (!response.body().isEmpty()) {
      try {
        data = MAPPER.readValue(response.body(), Map.class);
      } catch (Exception ignored) {}
    }

    if (response.statusCode() < 200 || response.statusCode() >= 300) {
      String bodyPreview = MAPPER.writeValueAsString(data);
      if (bodyPreview.length() > 300) {
        bodyPreview = bodyPreview.substring(0, 300);
      }
      throw new Exception(String.format("%s %s failed (%d): %s", method, pathName, response.statusCode(), bodyPreview));
    }

    return data;
  }

  @SuppressWarnings("unchecked")
  private static Map<String, Object> buildWorkflow() {
    Map<String, Object> financialTemplate = new LinkedHashMap<>();
    financialTemplate.put("type", "object");
    financialTemplate.put("required", List.of("payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"));

    Map<String, Object> props = new LinkedHashMap<>();
    for (String key : List.of("payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month")) {
      Map<String, Object> prop = new LinkedHashMap<>();
      prop.put("type", List.of("number", "null"));
      props.put(key, prop);
    }
    financialTemplate.put("properties", props);
    financialTemplate.put("additionalProperties", false);

    Map<String, Object> financialsProps = new LinkedHashMap<>();
    for (String cat : List.of("total", "expense", "medical", "indemnity")) {
      financialsProps.put(cat, MAPPER.convertValue(financialTemplate, Map.class));
    }

    Map<String, Object> financials = new LinkedHashMap<>();
    financials.put("type", "object");
    financials.put("required", List.of("total", "expense", "medical", "indemnity"));
    financials.put("properties", financialsProps);
    financials.put("additionalProperties", false);

    Map<String, Object> claimProps = new LinkedHashMap<>();
    claimProps.put("sdtf", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."));
    claimProps.put("status", Map.of("type", List.of("string", "null"), "description", "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."));
    claimProps.put("surgery", Map.of("type", List.of("string", "null"), "description", "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."));
    claimProps.put("adjuster", Map.of("type", List.of("string", "null"), "description", "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."));
    claimProps.put("litigated", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."));
    claimProps.put("longshore", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."));
    claimProps.put("voc_rehab", Map.of("type", List.of("string", "null"), "description", "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."));
    claimProps.put("claim_type", Map.of("type", List.of("string", "null"), "description", "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."));
    claimProps.put("controvert", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."));
    claimProps.put("date_hired", Map.of("type", List.of("string", "null"), "description", "The date the employee was hired by the employer. May be labeled as 'Date Hired'.", "extend:type", "date"));
    claimProps.put("financials", financials);
    claimProps.put("fraudulent", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."));
    claimProps.put("occupation", Map.of("type", List.of("string", "null"), "description", "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."));
    claimProps.put("settlement", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."));
    claimProps.put("subrogated", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."));
    claimProps.put("case_manager", Map.of("type", List.of("string", "null"), "description", "The name or identifier of the case manager handling this claim, if applicable."));
    claimProps.put("claim_number", Map.of("type", List.of("string", "null"), "description", "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."));
    claimProps.put("employee_ssn", Map.of("type", List.of("string", "null"), "description", "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."));
    claimProps.put("jurisdiction", Map.of("type", List.of("string", "null"), "description", "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."));
    claimProps.put("employee_name", Map.of("type", List.of("string", "null"), "description", "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."));
    claimProps.put("date_of_injury", Map.of("type", List.of("string", "null"), "description", "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.", "extend:type", "date"));
    claimProps.put("emp_report_date", Map.of("type", List.of("string", "null"), "description", "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.", "extend:type", "date"));
    claimProps.put("carrier_entry_date", Map.of("type", List.of("string", "null"), "description", "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.", "extend:type", "date"));
    claimProps.put("carrier_notify_date", Map.of("type", List.of("string", "null"), "description", "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.", "extend:type", "date"));
    claimProps.put("accident_description", Map.of("type", List.of("string", "null"), "description", "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."));

    Map<String, Object> claimItem = new LinkedHashMap<>();
    claimItem.put("type", "object");
    claimItem.put("required", List.of("sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab", "claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation", "settlement", "subrogated", "case_manager", "claim_number", "employee_ssn", "jurisdiction", "employee_name", "date_of_injury", "emp_report_date", "carrier_entry_date", "carrier_notify_date", "accident_description"));
    claimItem.put("properties", claimProps);
    claimItem.put("additionalProperties", false);

    Map<String, Object> claimsArray = new LinkedHashMap<>();
    claimsArray.put("type", "array");
    claimsArray.put("items", claimItem);
    claimsArray.put("description", "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.");

    Map<String, Object> schemaProps = new LinkedHashMap<>();
    schemaProps.put("claims", claimsArray);
    schemaProps.put("program", Map.of("type", List.of("string", "null"), "description", "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."));
    schemaProps.put("employer", Map.of("type", List.of("string", "null"), "description", "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."));
    schemaProps.put("date_printed", Map.of("type", List.of("string", "null"), "description", "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.", "extend:type", "date"));
    schemaProps.put("valued_as_of", Map.of("type", List.of("string", "null"), "description", "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.", "extend:type", "date"));

    Map<String, Object> schema = new LinkedHashMap<>();
    schema.put("type", "object");
    schema.put("required", List.of("claims", "program", "employer", "date_printed", "valued_as_of"));
    schema.put("properties", schemaProps);
    schema.put("additionalProperties", false);

    Map<String, Object> extractorConfig = new LinkedHashMap<>();
    extractorConfig.put("schema", schema);
    extractorConfig.put("baseProcessor", "extraction_performance");
    Map<String, Object> reviewAgent = new LinkedHashMap<>();
    reviewAgent.put("enabled", true);
    Map<String, Object> advancedOptions = new LinkedHashMap<>();
    advancedOptions.put("reviewAgent", reviewAgent);
    advancedOptions.put("advancedMultimodalEnabled", true);
    extractorConfig.put("advancedOptions", advancedOptions);

    Map<String, Object> extraction2Config = new LinkedHashMap<>();
    extraction2Config.put("extractorConfig", extractorConfig);

    Map<String, Object> parseConfig = new LinkedHashMap<>();
    Map<String, Object> blockOptions = new LinkedHashMap<>();
    Map<String, Object> text = new LinkedHashMap<>();
    Map<String, Object> agentic = new LinkedHashMap<>();
    agentic.put("enabled", true);
    text.put("agentic", agentic);
    blockOptions.put("text", text);
    parseConfig.put("blockOptions", blockOptions);
    Map<String, Object> chunkingStrategy = new LinkedHashMap<>();
    chunkingStrategy.put("type", "document");
    parseConfig.put("chunkingStrategy", chunkingStrategy);

    Map<String, Object> parse1Config = new LinkedHashMap<>();
    parse1Config.put("parseConfig", parseConfig);

    Map<String, Object> trigger = new LinkedHashMap<>();
    trigger.put("step", "parse1");
    Map<String, Object> startTrigger = new LinkedHashMap<>();
    startTrigger.put("name", "startTrigger1");
    startTrigger.put("type", "TRIGGER");
    startTrigger.put("next", List.of(trigger));

    Map<String, Object> parse1Next = new LinkedHashMap<>();
    parse1Next.put("step", "extraction2");
    Map<String, Object> parse1Step = new LinkedHashMap<>();
    parse1Step.put("name", "parse1");
    parse1Step.put("type", "PARSE");
    parse1Step.put("config", parse1Config);
    parse1Step.put("next", List.of(parse1Next));

    Map<String, Object> extraction2Step = new LinkedHashMap<>();
    extraction2Step.put("name", "extraction2");
    extraction2Step.put("type", "EXTRACT");
    extraction2Step.put("config", extraction2Config);

    Map<String, Object> workflow = new LinkedHashMap<>();
    workflow.put("name", "Workers' Compensation Claim Summary Processing Pipeline");
    workflow.put("steps", List.of(startTrigger, parse1Step, extraction2Step));

    return workflow;
  }

  @SuppressWarnings("unchecked")
  public static void main(String[] args) {
    try {
      State state = loadState();
      Map<String, Object> workflow = buildWorkflow();
      String workflowName = (String) workflow.get("name");

      System.out.println("Deploying \"" + workflowName + "\"…");

      if (state.workflowId != null && !state.workflowId.isEmpty()) {
        System.out.println("✓ workflow already provisioned (" + state.workflowId + ") — updating steps");
        api("POST", "/workflows/" + state.workflowId, Map.of("steps", workflow.get("steps")));
      } else {
        try {
          String encoded = URLEncoder.encode(workflowName, StandardCharsets.UTF_8);
          Map<String, Object> list = api("GET", "/workflows?name=" + encoded, null);
          List<Map<String, Object>> items = (List<Map<String, Object>>) (list.getOrDefault("data", list.getOrDefault("items", List.of())));
          String existingId = null;
          for (Map<String, Object> item : items) {
            if (workflowName.equals(item.get("name"))) {
              existingId = (String) item.get("id");
              break;
            }
          }
          if (existingId != null) {
            state.workflowId = existingId;
            saveState(state);
            System.out.println("✓ workflow \"" + workflowName + "\" found in your account (" + existingId + ") — updating steps");
            api("POST", "/workflows/" + existingId, Map.of("steps", workflow.get("steps")));
          }
        } catch (Exception ignored) {}

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

      try {
        api("POST", "/workflows/" + state.workflowId + "/versions", Map.of());
      } catch (Exception ignored) {}

      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);
    }
  }
}
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"
)

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

type FinancialDetails struct {
	Payments          *float64 `json:"payments"`
	Recovery          *float64 `json:"recovery"`
	Reserves          *float64 `json:"reserves"`
	NetIncurred       *float64 `json:"net_incurred"`
	PaidThisMonth     *float64 `json:"paid_this_month"`
	IncurredThisMonth *float64 `json:"incurred_this_month"`
}

type Financials struct {
	Total    FinancialDetails `json:"total"`
	Expense  FinancialDetails `json:"expense"`
	Medical  FinancialDetails `json:"medical"`
	Indemnity FinancialDetails `json:"indemnity"`
}

type ClaimItem struct {
	SDTF                string     `json:"sdtf"`
	Status              *string    `json:"status"`
	Surgery             *string    `json:"surgery"`
	Adjuster            *string    `json:"adjuster"`
	Litigated           *string    `json:"litigated"`
	Longshore           *string    `json:"longshore"`
	VocRehab            *string    `json:"voc_rehab"`
	ClaimType           *string    `json:"claim_type"`
	Controvert          *string    `json:"controvert"`
	DateHired           *string    `json:"date_hired"`
	Financials          Financials `json:"financials"`
	Fraudulent          *string    `json:"fraudulent"`
	Occupation          *string    `json:"occupation"`
	Settlement          *string    `json:"settlement"`
	Subrogated          *string    `json:"subrogated"`
	CaseManager         *string    `json:"case_manager"`
	ClaimNumber         *string    `json:"claim_number"`
	EmployeeSSN         *string    `json:"employee_ssn"`
	Jurisdiction        *string    `json:"jurisdiction"`
	EmployeeName        *string    `json:"employee_name"`
	DateOfInjury        *string    `json:"date_of_injury"`
	EmpReportDate       *string    `json:"emp_report_date"`
	CarrierEntryDate    *string    `json:"carrier_entry_date"`
	CarrierNotifyDate   *string    `json:"carrier_notify_date"`
	AccidentDescription *string    `json:"accident_description"`
}

type WorkflowStep struct {
	Name   string          `json:"name"`
	Type   string          `json:"type"`
	Config map[string]interface{} `json:"config,omitempty"`
	Next   []map[string]string `json:"next,omitempty"`
}

type WorkflowRequest struct {
	Name  string         `json:"name"`
	Steps []WorkflowStep `json:"steps"`
}

type WorkflowResponse struct {
	ID       string `json:"id"`
	Workflow struct {
		ID string `json:"id"`
	} `json:"workflow"`
}

type WorkflowListResponse struct {
	Data  []map[string]interface{} `json:"data"`
	Items []map[string]interface{} `json:"items"`
}

var (
	apiKey   string
	stateDir string
	stateFile string
	state    State
)

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

	wd, _ := os.Getwd()
	stateDir = filepath.Join(wd, ".extend")
	stateFile = filepath.Join(stateDir, "loss-run-report.json")

	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, _ := json.MarshalIndent(state, "", "  ")
	return os.WriteFile(stateFile, data, 0644)
}

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

	req, _ := http.NewRequest(method, API+pathName, reqBody)
	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()

	respBody, _ := io.ReadAll(resp.Body)
	var data map[string]interface{}
	json.Unmarshal(respBody, &data)

	if !resp.Ok {
		errMsg := string(respBody)
		if len(errMsg) > 300 {
			errMsg = errMsg[:300]
		}
		return nil, fmt.Errorf("%s %s failed (%d): %s", method, pathName, resp.StatusCode, errMsg)
	}
	return data, nil
}

func buildWorkflow() WorkflowRequest {
	return WorkflowRequest{
		Name: "Workers' Compensation Claim Summary Processing Pipeline",
		Steps: []WorkflowStep{
			{
				Name: "startTrigger1",
				Type: "TRIGGER",
				Next: []map[string]string{{"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]bool{"enabled": true},
							},
						},
						"chunkingStrategy": map[string]string{"type": "document"},
					},
				},
				Next: []map[string]string{{"step": "extraction2"}},
			},
			{
				Name: "extraction2",
				Type: "EXTRACT",
				Config: map[string]interface{}{
					"extractorConfig": map[string]interface{}{
						"schema": map[string]interface{}{
							"type": "object",
							"required": []string{"claims", "program", "employer", "date_printed", "valued_as_of"},
							"properties": map[string]interface{}{
								"claims": map[string]interface{}{
									"type": "array",
									"items": map[string]interface{}{
										"type": "object",
										"required": []string{"sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab", "claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation", "settlement", "subrogated", "case_manager", "claim_number", "employee_ssn", "jurisdiction", "employee_name", "date_of_injury", "emp_report_date", "carrier_entry_date", "carrier_notify_date", "accident_description"},
										"properties": map[string]interface{}{
											"sdtf": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary.",
											},
											"status": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'.",
											},
											"surgery": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary.",
											},
											"adjuster": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'.",
											},
											"litigated": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary.",
											},
											"longshore": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary.",
											},
											"voc_rehab": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary.",
											},
											"claim_type": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'.",
											},
											"controvert": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary.",
											},
											"date_hired": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
												"extend:type": "date",
											},
											"financials": map[string]interface{}{
												"type": "object",
												"required": []string{"total", "expense", "medical", "indemnity"},
												"properties": map[string]interface{}{
													"total": map[string]interface{}{
														"type": "object",
														"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
														"properties": map[string]interface{}{
															"payments": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total payments made to date on this claim.",
															},
															"recovery": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total amount recovered on this claim.",
															},
															"reserves": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total amount reserved for this claim.",
															},
															"net_incurred": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total net incurred amount for this claim (reserves plus payments minus recoveries).",
															},
															"paid_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total amount paid during the current month.",
															},
															"incurred_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total amount incurred during the current month.",
															},
														},
														"description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
														"additionalProperties": false,
													},
													"expense": map[string]interface{}{
														"type": "object",
														"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
														"properties": map[string]interface{}{
															"payments": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total expense payments made to date on this claim.",
															},
															"recovery": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount recovered for expenses on this claim.",
															},
															"reserves": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount reserved for expenses on this claim.",
															},
															"net_incurred": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The net incurred expense amount (reserves plus payments minus recoveries).",
															},
															"paid_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The expense amount paid during the current month.",
															},
															"incurred_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The expense amount incurred during the current month.",
															},
														},
														"description": "Financial details for the expense portion of the claim.",
														"additionalProperties": false,
													},
													"medical": map[string]interface{}{
														"type": "object",
														"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
														"properties": map[string]interface{}{
															"payments": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total medical payments made to date on this claim.",
															},
															"recovery": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount recovered for medical on this claim.",
															},
															"reserves": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount reserved for medical payments on this claim.",
															},
															"net_incurred": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The net incurred medical amount (reserves plus payments minus recoveries).",
															},
															"paid_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The medical amount paid during the current month.",
															},
															"incurred_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The medical amount incurred during the current month.",
															},
														},
														"description": "Financial details for the medical portion of the claim.",
														"additionalProperties": false,
													},
													"indemnity": map[string]interface{}{
														"type": "object",
														"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
														"properties": map[string]interface{}{
															"payments": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The total indemnity payments made to date on this claim.",
															},
															"recovery": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount recovered for indemnity on this claim.",
															},
															"reserves": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The amount reserved for indemnity payments on this claim.",
															},
															"net_incurred": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The net incurred indemnity amount (reserves plus payments minus recoveries).",
															},
															"paid_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The indemnity amount paid during the current month.",
															},
															"incurred_this_month": map[string]interface{}{
																"type": []string{"number", "null"},
																"description": "The indemnity amount incurred during the current month.",
															},
														},
														"description": "Financial details for indemnity (wage replacement) portion of the claim.",
														"additionalProperties": false,
													},
												},
												"description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
												"additionalProperties": false,
											},
											"fraudulent": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary.",
											},
											"occupation": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'.",
											},
											"settlement": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary.",
											},
											"subrogated": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary.",
											},
											"case_manager": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The name or identifier of the case manager handling this claim, if applicable.",
											},
											"claim_number": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value.",
											},
											"employee_ssn": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy.",
											},
											"jurisdiction": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'.",
											},
											"employee_name": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'.",
											},
											"date_of_injury": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
												"extend:type": "date",
											},
											"emp_report_date": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
												"extend:type": "date",
											},
											"carrier_entry_date": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
												"extend:type": "date",
											},
											"carrier_notify_date": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
												"extend:type": "date",
											},
											"accident_description": map[string]interface{}{
												"type": []string{"string", "null"},
												"description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where.",
											},
										},
										"additionalProperties": false,
									},
									"description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.",
								},
								"program": map[string]interface{}{
									"type": []string{"string", "null"},
									"description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.",
								},
								"employer": map[string]interface{}{
									"type": []string{"string", "null"},
									"description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.",
								},
								"date_printed": map[string]interface{}{
									"type": []string{"string", "null"},
									"description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
									"extend:type": "date",
								},
								"valued_as_of": map[string]interface{}{
									"type": []string{"string", "null"},
									"description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
									"extend:type": "date",
								},
							},
							"additionalProperties": false,
						},
						"baseProcessor": "extraction_performance",
						"advancedOptions": map[string]interface{}{
							"reviewAgent": map[string]bool{"enabled": true},
							"advancedMultimodalEnabled": true,
						},
					},
				},
			},
		},
	}
}

func main() {
	workflow := buildWorkflow()
	fmt.Printf("Deploying \"%s\"…\n", workflow.Name)

	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, "Error: %v\n", err)
			os.Exit(1)
		}
	} else {
		// Try to find existing workflow by name
		query := url.QueryEscape(workflow.Name)
		list, err := apiCall("GET", fmt.Sprintf("/workflows?name=%s", query), nil)
		var existing map[string]interface{}

		if err == nil {
			var items []map[string]interface{}
			if data, ok := list["data"].([]interface{}); ok {
				for _, v := range data {
					items = append(items, v.(map[string]interface{}))
				}
			} else if data, ok := list["items"].([]interface{}); ok {
				for _, v := range data {
					items = append(items, v.(map[string]interface{}))
				}
			}

			for _, item := range items {
				if name, ok := item["name"].(string); ok && name == workflow.Name {
					existing = item
					break
				}
			}
		}

		if existing != nil && existing["id"] != nil {
			state.WorkflowID = existing["id"].(string)
			saveState()
			fmt.Printf("✓ workflow \"%s\" found in your account (%s) — updating steps\n", workflow.Name, state.WorkflowID)
			_, err := apiCall("POST", fmt.Sprintf("/workflows/%s", state.WorkflowID), map[string]interface{}{"steps": workflow.Steps})
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %v\n", err)
				os.Exit(1)
			}
		} else {
			created, err := apiCall("POST", "/workflows", workflow)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error: %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.Fprintln(os.Stderr, "Could not read created workflow id from response")
				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 async (`parseRuns.createAndPoll()`) for anything over ~10 pages total per request—it's optimized for volume and handles the agentic_ocr mode at scale without timeouts. Sync parse works fine for single short claims.
If extraction confidence is below 0.85 on financial fields (total_benefits, medical_costs) or dates (return_to_work_date), flag for human review.
Tags
Workers CompensationClaims ManagementInjury ReportFinancial SummaryInsurance Claims
About this template

This template processes Loss Run documents, capturing essential claim information including claim numbers, dates of injury, employee details, accident descriptions, and financial reserves and payments. It handles structured claim data with embedded tables showing cost breakdowns by category (medical, indemnity, expenses) and claim status indicators.

Document formats
  • PDF
  • Excel / CSV
Requirements
  • Long tables
  • Checkboxes & Strikethroughs
  • Complex layouts