Skip to content

feat: Add self-verifying document extractor kit - #224

Closed
Krishhiv wants to merge 2 commits into
Lamatic:mainfrom
Krishhiv:feat/self-verifying-extractor
Closed

feat: Add self-verifying document extractor kit#224
Krishhiv wants to merge 2 commits into
Lamatic:mainfrom
Krishhiv:feat/self-verifying-extractor

Conversation

@Krishhiv

@Krishhiv Krishhiv commented Jul 11, 2026

Copy link
Copy Markdown

Summary

A Kit that pulls the key details out of everyday documents — invoices, bills, receipts, contracts — then independently re-verifies each field against the source text and flags anything it can't prove. Hence, it never quietly hands you the wrong due date or amount.

Ordinary extraction tools (including the existing invoice-summariser, resume-parser, and document-parsing kits) do a single confident pass and assert whatever they read. This kit treats extraction as two stages: pull the data, then prove each value against the original text before asserting it. Anything that it can't ground to an exact span is flagged for review instead of being guessed.

The problem it solves

A single misread number in a document has real consequences — a transposed digit in a due date costs a late fee; a total that was never actually stated triggers a wrong payment. LLM extractors have no notion of "I'm not sure about this one." This kit adds exactly that.

How it works

document ─▶ [1] extract ─▶ [2] verify ─▶ [app evidence gate] ─▶ [3] report ─▶ Verified ✓
             (LLM)          (LLM)          (exact code checks)      (code)     Needs review ⚠
                                                                                Not found 🔍
Stage Type Role
extract LLM Pulls a fixed schema (document_type, vendor_or_sender, total_amount, due_date, account_or_invoice_number, key_terms[]). Deliberately lean.
verify LLM (separate reasoning pass) Adversarial by design. Must find an exact supporting span; forbidden from inferring, calculating, or normalising. Emits supported/ambiguous/unsupported + confidence + source_quote.
Application evidence gate TypeScript (deterministic) The novel part. Re-check that every claimed quote is an exact substring and that every value occurs verbatim in its quote; downgrade anything that fails, regardless of model confidence. key_terms is split, and each item is grounded independently.
report Code (deterministic) Routes into three buckets — Verified / Needs review / Not found. The app recomputes the same routing and asserts the flow agrees.

Why a separate verify flow? Running verification as its own reasoning pass — with the document and the extraction as inputs — lets it genuinely disagree with the extractor. And because an LLM can still return an overconfident verdict or a reconstructed quote, a deterministic code gate has the final say: confidence is advisory; exact evidence is mandatory.

What's included

  • Kit (type: "kit") with a runnable Next.js app.
  • 3 core flows (extract, verify, report) + 1 optional (parse-pdf).
  • Externalised prompts, model-configs, and scripts, all @referenced.
  • flows/README.md — exact Studio recreation steps + smoke tests.
  • App: strict orchestration with per-stage timeouts + fail-closed error handling, environment validation, a three-column UI, and an honest "Simulate an extraction error" toggle.
  • Optional PDF upload: parse-pdf flow + upload route that validates (extension/MIME/size/%PDF- signature), stores in short-lived Vercel Blob, parses, and deletes the blob in a finally. Verified fields get source_page. Text-based PDFs only.

Testing & quality

npm run check passes: 32 unit tests (evidence gate, key_terms splitting, not-found routing, malformed JSON, flow-error handling, PDF validation, page attribution), ESLint clean, tsc --noEmit clean, next build succeeds. Node ≥ 20.9, lamatic SDK pinned.

Notes for reviewers

  • No secrets committed — only .env.example. PDF is optional; the app runs on pasted text without DOC_PARSE_PDF_FLOW / BLOB_READ_WRITE_TOKEN.
  • key_terms verification is deterministic exact-presence by design — the app owns that check rather than deferring to the model's fuzzy "is this a key term" judgment.
  • parse-pdf runs extractFromFileNode with Join Pages on for Lamatic deploy compatibility → page attribution is exact for single-page docs and collapses to p.1 for multi-page (documented in the flow + README).

1. Select Contribution Type

  • Kit

2. General Requirements

  • PR is for one project only (no unrelated changes)
  • No secrets, API keys, or real credentials are committed
  • Folder name uses kebab-case; step IDs match flow files (extract/verify/report/parse-pdf)
  • Documented in README.md (purpose, setup, usage) — plus flows/README.md for flow recreation

3. File Structure

  • Metadata present as lamatic.config.ts (current format; config.json is deprecated per CLAUDE.md)
  • Flows are self-contained flows/<name>.ts files (current format) — the old flows/<name>/config.json + inputs.json + meta.json layout no longer applies
  • .env.example with placeholder values only (root + apps/)
  • Flows built and deployed in Lamatic Studio; committed .ts files represent those graphs

4. Validation

  • npm install && npm run dev works locally (UI runs); npm run check (lint + typecheck + 32 tests + build) is green
  • PR title uses the required feat: prefix
  • GitHub Actions workflows pass — will confirm after opening
  • CodeRabbit / review comments addressed — will resolve after review
  • No unrelated files or projects modified
  • Added kit documentation and agent spec:
    • kits/self-verifying-extractor/README.md
    • kits/self-verifying-extractor/agent.md
    • kits/self-verifying-extractor/constitutions/default.md
    • kits/self-verifying-extractor/flows/README.md
  • Added environment examples and ignore rules:
    • kits/self-verifying-extractor/.env.example
    • kits/self-verifying-extractor/.gitignore
    • kits/self-verifying-extractor/apps/.env.example
    • kits/self-verifying-extractor/apps/.gitignore
    • kits/self-verifying-extractor/apps/.npmrc
  • Added core Lamatic kit configuration + flow definitions:
    • kits/self-verifying-extractor/lamatic.config.ts
    • kits/self-verifying-extractor/flows/extract.ts (Trigger: graphqlNode; Nodes: triggerNode, dynamicNode; Edges: defaultEdge, responseEdge)
    • kits/self-verifying-extractor/flows/verify.ts (Trigger: graphqlNode; Nodes: triggerNode, dynamicNode; Edges: defaultEdge, responseEdge)
    • kits/self-verifying-extractor/flows/report.ts (Trigger: graphqlNode; Nodes: triggerNode, dynamicNode; Edges: defaultEdge, responseEdge)
    • kits/self-verifying-extractor/flows/parse-pdf.ts (Trigger: graphqlNode; Nodes: triggerNode, dynamicNode; Edges: defaultEdge, responseEdge)
    • Note: no checked-in flow.json was found in the repo; node types were taken directly from flows/*.ts.
  • Added prompts and model configs for extraction + verification:
    • kits/self-verifying-extractor/prompts/extract_extract-fields_system.md
    • kits/self-verifying-extractor/prompts/extract_extract-fields_user.md
    • kits/self-verifying-extractor/prompts/verify_verify-fields_system.md
    • kits/self-verifying-extractor/prompts/verify_verify-fields_user.md
    • kits/self-verifying-extractor/model-configs/extract_extract-fields.ts
    • kits/self-verifying-extractor/model-configs/verify_verify-fields.ts
  • Added pipeline/flow scripts:
    • kits/self-verifying-extractor/scripts/extract_parse-json.ts
    • kits/self-verifying-extractor/scripts/parse-pdf_collate.ts
    • kits/self-verifying-extractor/scripts/report_route.ts
  • Added sample assets:
    • kits/self-verifying-extractor/assets/sample-invoice.txt
    • kits/self-verifying-extractor/assets/sample-invoice.pdf
    • kits/self-verifying-extractor/assets/sample-financial-snippet.txt
  • Added Next.js app (UI + orchestration + validation/tests):
    • kits/self-verifying-extractor/apps/README.md
    • kits/self-verifying-extractor/apps/package.json
    • kits/self-verifying-extractor/apps/tsconfig.json
    • kits/self-verifying-extractor/apps/next.config.mjs
    • kits/self-verifying-extractor/apps/eslint.config.mjs
    • kits/self-verifying-extractor/apps/postcss.config.mjs
    • kits/self-verifying-extractor/apps/app/layout.tsx
    • kits/self-verifying-extractor/apps/app/globals.css
    • kits/self-verifying-extractor/apps/app/page.tsx
    • kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts
    • kits/self-verifying-extractor/apps/actions/orchestrate.ts
    • kits/self-verifying-extractor/apps/orchestrate.js
    • kits/self-verifying-extractor/apps/lib/environment.ts (fail-closed env validation)
    • kits/self-verifying-extractor/apps/lib/lamatic-client.ts (cached client)
    • kits/self-verifying-extractor/apps/lib/pdf.ts (PDF validation + safe blob naming)
    • kits/self-verifying-extractor/apps/lib/pipeline.ts (deterministic extraction verification, evidence grounding, routing, and report consistency)
    • kits/self-verifying-extractor/apps/tests/environment.test.ts
    • kits/self-verifying-extractor/apps/tests/pdf.test.ts
    • kits/self-verifying-extractor/apps/tests/pipeline.test.ts
  • Flow behavior (high level, as implemented by the Lamatic node graph + app pipeline):
    • Extract: triggerNode (graphqlNode)dynamicNode (LLM extract fields)dynamicNode (parse JSON)responseEdge with { extraction }.
    • Verify: triggerNodedynamicNode (LLM verify fields with exact-span grounding)responseEdge with { verifications }.
    • Report: triggerNodedynamicNode (deterministic route & build report)responseEdge with verified / needs_review / not_found + report + summary.
    • Parse PDF (optional stage 0): triggerNodedynamicNode (extractFromPDF with joinPages)dynamicNode (collate pages into --- Page N --- markers)responseEdge with { text, page_count }.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 895354f6-dc49-49e6-b83d-f24b8a9f6b30

📥 Commits

Reviewing files that changed from the base of the PR and between eb3d472 and 06a252d.

📒 Files selected for processing (6)
  • kits/self-verifying-extractor/apps/.gitignore
  • kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts
  • kits/self-verifying-extractor/apps/app/page.tsx
  • kits/self-verifying-extractor/apps/lib/environment.ts
  • kits/self-verifying-extractor/apps/lib/pdf.ts
  • kits/self-verifying-extractor/apps/tests/pdf.test.ts

Walkthrough

Changes

Self-Verifying Document Extraction

Layer / File(s) Summary
Flow contracts and model behavior
kits/self-verifying-extractor/flows/*, prompts/*, scripts/*, constitutions/*, lamatic.config.ts, assets/*
Defines extract, verify, report, and optional PDF parsing flows with strict prompts, model configurations, deterministic routing scripts, sample documents, and deployment documentation.
Evidence validation and routing
kits/self-verifying-extractor/apps/lib/pipeline.ts, apps/tests/pipeline.test.ts
Adds fail-closed parsing, extraction and verification contracts, exact evidence grounding, page attribution, verdict routing, simulation, and report consistency tests.
Application execution and PDF ingestion
apps/actions/orchestrate.ts, apps/lib/*, apps/app/api/parse-pdf/route.ts, apps/tests/*
Adds environment validation, cached Lamatic access, timed pipeline execution, PDF validation/upload/parsing, cleanup, and related tests.
Next.js interface and project setup
apps/app/*, apps/package.json, apps/tsconfig.json, apps/next.config.mjs, apps/README.md, apps/.env.example, apps/.gitignore
Adds the interactive extraction UI, result buckets, PDF controls, structured output display, styling, environment templates, and application configuration.

Suggested reviewers: amanintech, d-pamneja

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main change and matches the kit added in this PR.
Description check ✅ Passed The description covers the required checklist sections and explains the kit, setup, files, and validation with only minor template deviations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

:robot_face: AgentKit Structural Validation

New Contributions Detected

  • Kit: kits/self-verifying-extractor

Check Results

Check Status
No edits to existing kits ✅ Pass
Required root files present ✅ Pass
Flow .ts files present ✅ Pass
lamatic.config.ts valid ✅ Pass
No changes outside kits/ ✅ Pass

🎉 All checks passed! This contribution follows the AgentKit structure.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@kits/self-verifying-extractor/apps/.gitignore`:
- Around line 19-22: Update the environment-file ignore patterns in the
gitignore configuration to match all dotenv variants, including production and
development files, while preserving the existing exclusions for .env and
.env.local.

In `@kits/self-verifying-extractor/apps/actions/orchestrate.ts`:
- Line 22: Replace the config import in the actions orchestrate module so it
uses the parent kit’s ../../lamatic.config instead of the local
../orchestrate.js bridge, while preserving the existing config usage.

In `@kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts`:
- Around line 71-76: Update the blob cleanup in the finally block to retain
best-effort response behavior while logging any error from del(blobUrl). Replace
the silent catch with an error handler that records the blob URL and deletion
failure details for operator investigation.
- Around line 43-46: Update the blob upload options in the parse-PDF route to
prevent predictable public URLs: prefer private access with a short-lived signed
URL if supported by the configured `@vercel/blob` setup; otherwise retain public
access but enable addRandomSuffix so uploaded document URLs are unguessable
during parsing.

In `@kits/self-verifying-extractor/apps/app/page.tsx`:
- Line 64: Rename the state pair in the component from document/setDocument to
documentText/setDocumentText, and update every corresponding reference
throughout the component, including the listed handlers and JSX usages. Preserve
the existing state behavior while avoiding shadowing the global DOM document.

In `@kits/self-verifying-extractor/apps/lib/environment.ts`:
- Around line 60-62: Update the endpoint validation in the environment
configuration flow to reject http:// URLs outside development, while continuing
to allow both http:// and https:// when NODE_ENV is development. Keep https://
valid in all environments and preserve the existing ConfigurationError for
invalid protocols.

In `@kits/self-verifying-extractor/apps/lib/pdf.ts`:
- Around line 54-61: Update safeBlobName so filenames whose sanitized value is
empty or begins with a dot use a non-hidden default base name before appending
the .pdf extension. Preserve the existing sanitization and timestamped
self-verifying-extractor path for normal filenames.

In `@kits/self-verifying-extractor/apps/orchestrate.js`:
- Around line 1-56: Convert the orchestrator config bridge from JavaScript to
TypeScript by renaming orchestrate.js to orchestrate.ts, then update the import
in apps/actions/orchestrate.ts to reference the TypeScript module through the
existing .js runtime import convention.

In `@kits/self-verifying-extractor/apps/package.json`:
- Around line 22-42: Update the dependencies for the Next.js app by adding
react-hook-form and zod, plus the shadcn/ui support packages used by the app
such as `@radix-ui/`* components, class-variance-authority, clsx, and
tailwind-merge. If the app contains no form-based inputs, retain only the
shadcn/ui dependencies and confirm that react-hook-form and zod are unnecessary.
- Around line 27-29: Update the dependencies in the app package manifest to
comply with the kit version policy: use a supported Next.js 14–15 release and
React 18, and align the corresponding React types, Next.js types, and ESLint
configuration packages with those versions. Do not retain the current Next.js 16
and React 19 combination unless the policy is explicitly updated instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 33bb95dd-1c35-43ed-bad7-75a9e9374ee1

📥 Commits

Reviewing files that changed from the base of the PR and between dafde4c and eb3d472.

⛔ Files ignored due to path filters (2)
  • kits/self-verifying-extractor/apps/package-lock.json is excluded by !**/package-lock.json
  • kits/self-verifying-extractor/assets/sample-invoice.pdf is excluded by !**/*.pdf
📒 Files selected for processing (44)
  • kits/self-verifying-extractor/.env.example
  • kits/self-verifying-extractor/.gitignore
  • kits/self-verifying-extractor/README.md
  • kits/self-verifying-extractor/agent.md
  • kits/self-verifying-extractor/apps/.env.example
  • kits/self-verifying-extractor/apps/.gitignore
  • kits/self-verifying-extractor/apps/.npmrc
  • kits/self-verifying-extractor/apps/README.md
  • kits/self-verifying-extractor/apps/actions/orchestrate.ts
  • kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts
  • kits/self-verifying-extractor/apps/app/globals.css
  • kits/self-verifying-extractor/apps/app/layout.tsx
  • kits/self-verifying-extractor/apps/app/page.tsx
  • kits/self-verifying-extractor/apps/eslint.config.mjs
  • kits/self-verifying-extractor/apps/lib/environment.ts
  • kits/self-verifying-extractor/apps/lib/lamatic-client.ts
  • kits/self-verifying-extractor/apps/lib/pdf.ts
  • kits/self-verifying-extractor/apps/lib/pipeline.ts
  • kits/self-verifying-extractor/apps/next.config.mjs
  • kits/self-verifying-extractor/apps/orchestrate.js
  • kits/self-verifying-extractor/apps/package.json
  • kits/self-verifying-extractor/apps/postcss.config.mjs
  • kits/self-verifying-extractor/apps/tests/environment.test.ts
  • kits/self-verifying-extractor/apps/tests/pdf.test.ts
  • kits/self-verifying-extractor/apps/tests/pipeline.test.ts
  • kits/self-verifying-extractor/apps/tsconfig.json
  • kits/self-verifying-extractor/assets/sample-financial-snippet.txt
  • kits/self-verifying-extractor/assets/sample-invoice.txt
  • kits/self-verifying-extractor/constitutions/default.md
  • kits/self-verifying-extractor/flows/README.md
  • kits/self-verifying-extractor/flows/extract.ts
  • kits/self-verifying-extractor/flows/parse-pdf.ts
  • kits/self-verifying-extractor/flows/report.ts
  • kits/self-verifying-extractor/flows/verify.ts
  • kits/self-verifying-extractor/lamatic.config.ts
  • kits/self-verifying-extractor/model-configs/extract_extract-fields.ts
  • kits/self-verifying-extractor/model-configs/verify_verify-fields.ts
  • kits/self-verifying-extractor/prompts/extract_extract-fields_system.md
  • kits/self-verifying-extractor/prompts/extract_extract-fields_user.md
  • kits/self-verifying-extractor/prompts/verify_verify-fields_system.md
  • kits/self-verifying-extractor/prompts/verify_verify-fields_user.md
  • kits/self-verifying-extractor/scripts/extract_parse-json.ts
  • kits/self-verifying-extractor/scripts/parse-pdf_collate.ts
  • kits/self-verifying-extractor/scripts/report_route.ts

Comment thread kits/self-verifying-extractor/apps/.gitignore
Comment thread kits/self-verifying-extractor/apps/actions/orchestrate.ts
Comment thread kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts
Comment thread kits/self-verifying-extractor/apps/app/api/parse-pdf/route.ts
Comment thread kits/self-verifying-extractor/apps/app/page.tsx Outdated
Comment thread kits/self-verifying-extractor/apps/lib/environment.ts Outdated
Comment thread kits/self-verifying-extractor/apps/lib/pdf.ts
Comment thread kits/self-verifying-extractor/apps/orchestrate.js
Comment thread kits/self-verifying-extractor/apps/package.json
Comment thread kits/self-verifying-extractor/apps/package.json
@Krishhiv

Copy link
Copy Markdown
Author

Thanks, CodeRabbit, addressed 6, declining 4 with reasons:

Applied: expanded .gitignore env patterns; log blob del() failures; addRandomSuffix: true for unguessable temp URLs; renamed document→documentText to avoid shadowing the DOM global; require https:// in production; safeBlobName fallback for empty/dotfile names (+test).

Declining:

Import ../../lamatic.config instead of ../orchestrate.js — these are different modules. orchestrate.js is the runtime flow-config bridge (config.flows/config.api); lamatic.config.ts is kit metadata (name/type/steps). Swapping breaks the app, and this matches the reference kits (content-generation, deep-search).
Convert orchestrate.js→.ts — the .js bridge is the established AgentKit pattern across reference kits; conversion is churn with no functional gain.
Add react-hook-form/zod/Radix/shadcn deps — the app has no forms and no shadcn/ui; these would be unused (per your own caveat, confirmed unnecessary).
Downgrade to Next 14–15 / React 18 — the reference kit content-generation ships Next 16 + React 19; this kit matches it. npm run check (lint + typecheck + 33 tests +

@github-actions

Copy link
Copy Markdown
Contributor

Hi @Krishhiv! 👋

Before this PR can be reviewed by maintainers, please resolve all comments and requested changes from the CodeRabbit automated review.

Steps to follow:

  1. Read through all CodeRabbit comments carefully
  2. Address each issue raised (or reply explaining why you disagree)
  3. Push your fixes as new commits
  4. Once all issues are resolved, comment here so we can re-review

This helps keep the review process efficient for everyone. Thank you! 🙏

@akshatvirmani

Copy link
Copy Markdown
Contributor

/validate

@github-actions

Copy link
Copy Markdown
Contributor

📡 Running Studio validation — results will appear here shortly.

@github-actions

Copy link
Copy Markdown
Contributor

Studio Runtime Validation (Phase 2)

Studio validation failed. The kit was rejected by Lamatic Studio.

Errors

self-verifying-extractor

  • Flow: extract — config_json.nodes must be a non-empty array
  • Flow: parse-pdf — config_json.nodes must be a non-empty array
  • Flow: report — config_json.nodes must be a non-empty array
  • Flow: verify — config_json.nodes must be a non-empty array

Please fix the errors above and push a new commit to re-run validation.
Refer to CONTRIBUTING.md for guidance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants