Skip to content

feat: Trade Finance Document Validator kit#248

Open
sivaprasad-ai wants to merge 2 commits into
Lamatic:mainfrom
sivaprasad-ai:feat/trade-finance-validator
Open

feat: Trade Finance Document Validator kit#248
sivaprasad-ai wants to merge 2 commits into
Lamatic:mainfrom
sivaprasad-ai:feat/trade-finance-validator

Conversation

@sivaprasad-ai

@sivaprasad-ai sivaprasad-ai commented Jul 15, 2026

Copy link
Copy Markdown

Trade Finance Document Validator

An AI-powered first-pass compliance reviewer for trade finance documents.

What it does

  • Upload a Letter of Credit, Trade License, or Commercial Invoice (TXT, PDF, or Word)
  • Extracts structured fields using LLM
  • Validates against a compliance rule checklist (R1–R13)
  • Generates a plain-English verdict: PASSED / PASSED WITH WARNINGS / FAILED
  • Returns a structured JSON report with confidence score

Flow

API Request → Extract Fields (LLM) → Validate Rules (LLM) → Generate Summary (LLM) → Finalise Output (Code) → API Response

Stack

  • Lamatic Studio (4 nodes)
  • Next.js 15, TypeScript, Tailwind CSS
  • Groq / Llama 3.3 70B

Author

Built by Sivaprasad — trade finance document validation from real-world experience in credit and CIBG workflows.

  • Added the Trade Finance Document Validator kit for first-pass compliance review of Trade Licenses, Letters of Credit, and Commercial Invoices.
  • Added documentation covering the agent’s purpose, workflow, supported documents, limitations, guardrails, setup, and JSON output contract.
  • Added a Next.js 15 application with:
    • Upload and paste support for TXT, PDF, and DOCX documents.
    • Drag-and-drop interactions, sample documents, validation states, result displays, confidence scores, and rule-level statuses.
    • Tailwind-based styling, animations, responsive UI, metadata, and utility helpers.
  • Added server-side document extraction:
    • PDF text extraction using pdf-parse.
    • DOCX text extraction using mammoth.
    • Direct text input support.
  • Added Lamatic orchestration:
    • Environment-based API and workflow configuration.
    • Flow execution with request polling, response normalization, and user-friendly error handling.
  • Added the Lamatic flow configuration and kit metadata, including workflow inputs, deployment links, environment requirements, and model settings.
  • Added the four-stage validation flow:
    • API request input node.
    • LLM document field extraction node.
    • LLM compliance validation node.
    • LLM plain-English report generation node.
    • Code-based output finalization node.
    • API response node returning the structured result.
  • Added prompts and deterministic validation guidance for:
    • Structured field extraction without inference.
    • Compliance rules R1–R13.
    • PASSED, PASSED WITH WARNINGS, and FAILED verdict calculation.
    • Confidence scoring and concise human-readable summaries.
  • Added model configurations for extractor, validator, and reporter LLM stages.
  • Added TypeScript, Next.js, Tailwind, dependency, environment, and generated-file configuration.

sivaprasad9390 and others added 2 commits July 15, 2026 13:09
AI-powered first-pass compliance reviewer for trade finance documents
(Letters of Credit, trade licenses, commercial invoices). Extracts
structured fields, validates against a compliance checklist, and
produces a pass/fail report with a plain-English summary.

Supports .txt, .pdf, and .docx uploads (server-side extraction via
pdf-parse/mammoth) alongside direct text paste.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

:robot_face: AgentKit Structural Validation

New Contributions Detected

  • Kit: kits/trade-finance-validator

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

⚠️ Warnings

  • kits/trade-finance-validator is missing .env.example — bundles and kits should include one

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

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Trade Finance Validator

Layer / File(s) Summary
Validation contracts and prompts
kits/trade-finance-validator/agent.md, constitutions/default.md, prompts/*
Defines extraction, compliance validation, reporting, supported document types, and JSON output contracts.
Lamatic flow and kit wiring
flows/*, model-configs/*, lamatic.config.ts, apps/orchestrate.ts
Connects model configurations and prompts into an extraction-to-response Lamatic workflow and registers the kit step.
Server execution and project runtime
apps/actions/*, apps/lib/*, apps/package.json, apps/tsconfig.json, apps/next.config.mjs, apps/.env.example
Adds document text extraction, workflow execution and polling, Lamatic client configuration, runtime settings, dependencies, and environment placeholders.
Validator interface and presentation
apps/app/*
Adds the Next.js layout and client interface for uploads, pasted text, sample documents, validation states, and rendered reports.
Kit documentation and repository support
README.md, .gitignore
Documents the validator workflow, supported inputs, output format, setup steps, and ignored local artifacts.

Suggested reviewers: amanintech, d-pamneja

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers purpose, flow, stack, and author, but it omits the required PR checklist and setup/file-structure details from the template. Add the template's checklist sections, including contribution type, file structure, validation, setup/usage, and checklist items for config, .env.example, and tests.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly identifies the kit and matches the main change.
✨ 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.

@coderabbitai
coderabbitai Bot requested review from amanintech and d-pamneja July 15, 2026 09:08

@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: 11

🤖 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/trade-finance-validator/apps/actions/extract-text.ts`:
- Around line 3-9: The upload size limit must be enforced consistently before
file contents are read. In
kits/trade-finance-validator/apps/actions/extract-text.ts, update
extractDocumentText to reject oversized base64 input with a clear error before
Buffer.from; in kits/trade-finance-validator/apps/app/page.tsx, add the same
shared maximum-size guard before file.arrayBuffer(), reusing a common limit
constant so both client and server remain aligned.

In `@kits/trade-finance-validator/apps/actions/orchestrate.ts`:
- Line 4: Update the config imports in
kits/trade-finance-validator/apps/actions/orchestrate.ts at line 4 and
kits/trade-finance-validator/apps/lib/lamatic-client.ts at line 2 to use
../../lamatic.config instead of ../orchestrate, while preserving each module’s
existing config usage.
- Around line 47-56: Update the polling loop around lamaticClient.checkStatus to
await a setTimeout-based delay between status requests, preventing rapid API
retries. Change the status validation so only definitive failure statuses
trigger an error, while transient statuses such as "pending" and "processing"
continue polling until the existing attempt limit or payload condition ends the
loop.

In `@kits/trade-finance-validator/apps/app/page.tsx`:
- Around line 7-60: Refactor the page component to follow the kit UI stack:
replace IconShield, IconUpload, IconCheck, IconX, IconWarning, and
IconFile/IconSpinner with lucide-react icons, and replace inline style objects
throughout the page with Tailwind CSS utility classes. Use shadcn/ui primitives
such as Button, Card, and Textarea for the interface, and implement the
paste-text form with react-hook-form and zod validation while preserving the
existing upload and validation behavior.
- Around line 448-456: Replace the hex-alpha suffix concatenation using
badge.color and getStatusColor in the badge boxShadow and check-row border
styling with valid CSS color composition, such as color-mix() or dedicated rgba
variables. Preserve each status color and intended transparency while ensuring
both the glow and border declarations remain valid when the source value is a
CSS var().
- Around line 509-525: Update the extracted-field rendering in the
report.extracted_fields map to treat empty strings as missing alongside nullish
values, including the displayed placeholder, danger color, font weight, and
italic styling. Preserve normal rendering for non-empty values and continue
converting present values with String(value).
- Around line 161-167: Update the FileReader flow in the file-upload handler to
add an error callback alongside reader.onload. When reading fails, transition
the upload state away from "uploading" using the existing error-state mechanism
and surface an appropriate error message, ensuring the UI does not remain stuck
spinning.
- Around line 146-151: Replace the char-by-char reduce in the isPdf/isDocx
upload path with a chunked binary-to-Base64 conversion or
FileReader.readAsDataURL approach, stripping the data URL prefix when
applicable. Preserve the existing extractDocumentText(base64, file.type) call
while avoiding large intermediate string allocations on the main thread.

In `@kits/trade-finance-validator/apps/package.json`:
- Line 22: Remove the redundant autoprefixer entry from the package manifest,
leaving the remaining dependencies unchanged because Tailwind CSS v4 and
Lightning CSS now provide vendor prefixing.

In
`@kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md`:
- Around line 4-6: The Commercial Invoice field specification and
extracted_fields schema are inconsistent for quantity and unit price. Update the
schema in the relevant extractor prompt to include matching quantity and
unit_price keys, preserving the existing invoice extraction fields and naming
conventions.

In `@kits/trade-finance-validator/README.md`:
- Line 5: Update the README’s verdict documentation and JSON example to use the
exact case-sensitive runtime values PASSED, PASSED WITH WARNINGS, and FAILED.
Replace the lowercase failed example and add an explicit warnings example so
consumers understand and can handle all validator outcomes.
🪄 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: 4ce5429f-2b4e-4e5e-b20c-89a1204e8daa

📥 Commits

Reviewing files that changed from the base of the PR and between 0ada432 and 5c4ecef.

⛔ Files ignored due to path filters (1)
  • kits/trade-finance-validator/apps/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • kits/trade-finance-validator/.gitignore
  • kits/trade-finance-validator/README.md
  • kits/trade-finance-validator/agent.md
  • kits/trade-finance-validator/apps/.env.example
  • kits/trade-finance-validator/apps/.gitignore
  • kits/trade-finance-validator/apps/actions/extract-text.ts
  • kits/trade-finance-validator/apps/actions/orchestrate.ts
  • kits/trade-finance-validator/apps/app/globals.css
  • kits/trade-finance-validator/apps/app/layout.tsx
  • kits/trade-finance-validator/apps/app/page.tsx
  • kits/trade-finance-validator/apps/lib/lamatic-client.ts
  • kits/trade-finance-validator/apps/lib/utils.ts
  • kits/trade-finance-validator/apps/next-env.d.ts
  • kits/trade-finance-validator/apps/next.config.mjs
  • kits/trade-finance-validator/apps/orchestrate.ts
  • kits/trade-finance-validator/apps/package.json
  • kits/trade-finance-validator/apps/tsconfig.json
  • kits/trade-finance-validator/constitutions/default.md
  • kits/trade-finance-validator/flows/trade-finance-validator.ts
  • kits/trade-finance-validator/lamatic.config.ts
  • kits/trade-finance-validator/model-configs/trade-finance-validator_extractor.ts
  • kits/trade-finance-validator/model-configs/trade-finance-validator_reporter.ts
  • kits/trade-finance-validator/model-configs/trade-finance-validator_validator.ts
  • kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md
  • kits/trade-finance-validator/prompts/trade-finance-validator_extractor_user.md
  • kits/trade-finance-validator/prompts/trade-finance-validator_reporter_system.md
  • kits/trade-finance-validator/prompts/trade-finance-validator_reporter_user.md
  • kits/trade-finance-validator/prompts/trade-finance-validator_validator_system.md
  • kits/trade-finance-validator/prompts/trade-finance-validator_validator_user.md

Comment on lines +3 to +9
export async function extractDocumentText(
fileBase64: string,
mimeType: string
): Promise<{ success: boolean; text?: string; error?: string }> {
try {
const buffer = Buffer.from(fileBase64, "base64");

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the affected files and nearby config for any file-size/body-size limits.
git ls-files 'kits/trade-finance-validator/apps/**/*.{ts,tsx,js,jsx,json}' | sed -n '1,200p'

printf '\n--- extract-text.ts ---\n'
sed -n '1,220p' kits/trade-finance-validator/apps/actions/extract-text.ts

printf '\n--- page.tsx ---\n'
sed -n '1,260p' kits/trade-finance-validator/apps/app/page.tsx

printf '\n--- search for size limits / bodySizeLimit / max file checks ---\n'
rg -n "bodySizeLimit|max file|file\.size|maxSize|limit" kits/trade-finance-validator/apps -g '!**/node_modules/**'

Repository: Lamatic/AgentKit

Length of output: 12275


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- package.json ---'
sed -n '1,220p' kits/trade-finance-validator/apps/package.json

printf '\n%s\n' '--- next config files ---'
find kits/trade-finance-validator/apps -maxdepth 2 \( -name 'next.config.*' -o -name 'next.config.mjs' -o -name 'next.config.ts' \) -print | sort | xargs -r -I{} sh -c 'printf "\n### %s ###\n" "$1"; sed -n "1,220p" "$1"' sh {}

printf '\n%s\n' '--- search for server action config ---'
rg -n "serverActions|bodySizeLimit|experimental" kits/trade-finance-validator/apps -g '!**/node_modules/**'

Repository: Lamatic/AgentKit

Length of output: 1711


🌐 Web query:

Next.js server actions default body size limit 1MB documentation

💡 Result:

In Next.js, the default maximum request body size for Server Actions is 1MB [1][2][3]. This limit is implemented to prevent the consumption of excessive server resources and mitigate potential DDoS attacks [4][5]. You can configure this limit in your next.config.js file using the serverActions.bodySizeLimit option [1][6]. This setting accepts either a numeric value (representing bytes) or a string format supported by the bytes library (e.g., '1000', '500kb', or '3mb') [6]. Example configuration: / @type {import('next').NextConfig} */ module.exports = { experimental: { serverActions: { bodySizeLimit: '2mb', }, }, } Important Considerations: 1. Request Rejection: When the request body exceeds the configured limit, the Server Action will be rejected by the server before your function code executes [5]. This means you cannot handle the error inside the action itself; instead, the application will typically receive a 400 status code [5]. 2. Deployment Limits: Increasing this value in Next.js does not override platform-level limits [4]. For example, if you are deploying to Vercel, your function execution is still subject to the platform's specific body size limits (e.g., 4.5MB for Node.js runtimes) [4]. 3. Client-Side Validation: Because server-side rejection happens before your logic runs, it is often recommended to implement client-side validation to check file or payload sizes before submission, allowing you to provide immediate and meaningful feedback to users [5].

Citations:


Add a shared upload size cap
Large PDFs/DOCX will hit Next.js’s 1MB Server Action body limit, and there’s no file.size guard before file.arrayBuffer() or Buffer.from(...). Add the same max on the client and in extractDocumentText so oversized uploads fail fast with a clear message.

📍 Affects 2 files
  • kits/trade-finance-validator/apps/actions/extract-text.ts#L3-L9 (this comment)
  • kits/trade-finance-validator/apps/app/page.tsx#L136-L159
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/actions/extract-text.ts` around lines 3 -
9, The upload size limit must be enforced consistently before file contents are
read. In kits/trade-finance-validator/apps/actions/extract-text.ts, update
extractDocumentText to reject oversized base64 input with a clear error before
Buffer.from; in kits/trade-finance-validator/apps/app/page.tsx, add the same
shared maximum-size guard before file.arrayBuffer(), reusing a common limit
constant so both client and server remain aligned.

"use server";

import { lamaticClient } from "@/lib/lamatic-client";
import { config } from "../orchestrate";

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Import configuration from the parent kit as per protocols.

Agent, we have an unauthorized channel open. As per our strict operational protocols, Kit Next.js apps must import and use ../../lamatic.config to read step definitions from the parent kit, instead of an intermediary proxy module like ../orchestrate. This ensures your mission intel stays centralized and accurate.

  • kits/trade-finance-validator/apps/actions/orchestrate.ts#L4-L4: Update this line to import { config } from "../../lamatic.config";
  • kits/trade-finance-validator/apps/lib/lamatic-client.ts#L2-L2: Re-route this import to import { config } from "../../lamatic.config";
    As per coding guidelines, Kit Next.js apps must import and use ../../lamatic.config to read step definitions from the parent kit.
📍 Affects 2 files
  • kits/trade-finance-validator/apps/actions/orchestrate.ts#L4-L4 (this comment)
  • kits/trade-finance-validator/apps/lib/lamatic-client.ts#L2-L2
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/actions/orchestrate.ts` at line 4, Update
the config imports in kits/trade-finance-validator/apps/actions/orchestrate.ts
at line 4 and kits/trade-finance-validator/apps/lib/lamatic-client.ts at line 2
to use ../../lamatic.config instead of ../orchestrate, while preserving each
module’s existing config usage.

Source: Coding guidelines

Comment on lines +47 to +56
while (payload?.requestId && attempts < 10) {
resData = await lamaticClient.checkStatus(payload.requestId);

if (resData.status && resData.status !== "success") {
throw new Error(resData.message || "Validation flow did not complete successfully.");
}

payload = resData?.data?.output?.result ?? resData?.result?.result ?? resData?.result;
attempts += 1;
}

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.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Implement a tactical delay in the polling loop and correct the status check.

Agent, we've spotted a flaw in your operational logic. This while loop is moving too fast. Without a delay, it will aggressively spam the API target, risking a rate-limit lockout. Furthermore, throwing an error for any status other than "success" could abort the mission prematurely if the API returns a transient status (e.g., "pending" or "processing").

Introduce a setTimeout delay and only abort on definitive failure states.

🛠️ Proposed fix to secure the polling loop
-    while (payload?.requestId && attempts < 10) {
+    while (payload?.requestId && attempts < 10) {
+      await new Promise((resolve) => setTimeout(resolve, 2000));
       resData = await lamaticClient.checkStatus(payload.requestId);
 
-      if (resData.status && resData.status !== "success") {
+      if (resData.status === "failed" || resData.status === "error") {
         throw new Error(resData.message || "Validation flow did not complete successfully.");
       }
 
       payload = resData?.data?.output?.result ?? resData?.result?.result ?? resData?.result;
       attempts += 1;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while (payload?.requestId && attempts < 10) {
resData = await lamaticClient.checkStatus(payload.requestId);
if (resData.status && resData.status !== "success") {
throw new Error(resData.message || "Validation flow did not complete successfully.");
}
payload = resData?.data?.output?.result ?? resData?.result?.result ?? resData?.result;
attempts += 1;
}
while (payload?.requestId && attempts < 10) {
await new Promise((resolve) => setTimeout(resolve, 2000));
resData = await lamaticClient.checkStatus(payload.requestId);
if (resData.status === "failed" || resData.status === "error") {
throw new Error(resData.message || "Validation flow did not complete successfully.");
}
payload = resData?.data?.output?.result ?? resData?.result?.result ?? resData?.result;
attempts += 1;
}
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/actions/orchestrate.ts` around lines 47 -
56, Update the polling loop around lamaticClient.checkStatus to await a
setTimeout-based delay between status requests, preventing rapid API retries.
Change the status validation so only definitive failure statuses trigger an
error, while transient statuses such as "pending" and "processing" continue
polling until the existing attempt limit or payload condition ends the loop.

Comment on lines +7 to +60
// ── Icons ─────────────────────────────────────────────────────────────────────
function IconShield() {
return (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
</svg>
);
}
function IconUpload() {
return (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="17 8 12 3 7 8" />
<line x1="12" y1="3" x2="12" y2="15" />
</svg>
);
}
function IconCheck() {
return (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
);
}
function IconX() {
return (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
</svg>
);
}
function IconWarning() {
return (
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
<line x1="12" y1="9" x2="12" y2="13" /><line x1="12" y1="17" x2="12.01" y2="17" />
</svg>
);
}
function IconFile() {
return (
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
);
}
function IconSpinner() {
return (
<svg className="animate-spin" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" />
</svg>
);
}

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.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Off-script: hand-rolled SVGs and inline styles instead of the kit's mandated UI stack.

Path guidelines for kit Next.js apps require Tailwind CSS v4+, shadcn/ui components, and lucide-react for icons. This file instead defines six custom inline SVG icon components (lines 8-60) and drives virtually all presentation through inline style={{...}} objects rather than Tailwind utility classes or shadcn/ui Button/Card/Textarea primitives, with no react-hook-form/zod on the paste-text form either.

Based on coding guidelines: kits/*/apps/**/*.{ts,tsx,js,jsx} requires "Tailwind CSS v4+, shadcn/ui components, react-hook-form + zod for forms, lucide-react for icons."

Also applies to: 189-575

🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/app/page.tsx` around lines 7 - 60, Refactor
the page component to follow the kit UI stack: replace IconShield, IconUpload,
IconCheck, IconX, IconWarning, and IconFile/IconSpinner with lucide-react icons,
and replace inline style objects throughout the page with Tailwind CSS utility
classes. Use shadcn/ui primitives such as Button, Card, and Textarea for the
interface, and implement the paste-text form with react-hook-form and zod
validation while preserving the existing upload and validation behavior.

Source: Coding guidelines

Comment on lines +146 to +151
if (isPdf || isDocx) {
const arrayBuffer = await file.arrayBuffer();
const base64 = btoa(
new Uint8Array(arrayBuffer).reduce((acc, byte) => acc + String.fromCharCode(byte), "")
);
const res = await extractDocumentText(base64, file.type);

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.

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Base64 encoding via char-by-char reduce — slow burn on large PDFs.

Building the base64 payload with .reduce((acc, byte) => acc + String.fromCharCode(byte), "") repeatedly allocates a growing string on the main thread, which can visibly freeze the UI for multi-MB PDFs/DOCX. Chunked conversion or FileReader.readAsDataURL() (stripping the data: prefix) is far cheaper.

⚡ Proposed fix — chunked conversion to avoid large intermediate strings
-      const arrayBuffer = await file.arrayBuffer();
-      const base64 = btoa(
-        new Uint8Array(arrayBuffer).reduce((acc, byte) => acc + String.fromCharCode(byte), "")
-      );
+      const arrayBuffer = await file.arrayBuffer();
+      const bytes = new Uint8Array(arrayBuffer);
+      const CHUNK_SIZE = 0x8000;
+      let binary = "";
+      for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
+        binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
+      }
+      const base64 = btoa(binary);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isPdf || isDocx) {
const arrayBuffer = await file.arrayBuffer();
const base64 = btoa(
new Uint8Array(arrayBuffer).reduce((acc, byte) => acc + String.fromCharCode(byte), "")
);
const res = await extractDocumentText(base64, file.type);
if (isPdf || isDocx) {
const arrayBuffer = await file.arrayBuffer();
const bytes = new Uint8Array(arrayBuffer);
const CHUNK_SIZE = 0x8000;
let binary = "";
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
}
const base64 = btoa(binary);
const res = await extractDocumentText(base64, file.type);
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/app/page.tsx` around lines 146 - 151,
Replace the char-by-char reduce in the isPdf/isDocx upload path with a chunked
binary-to-Base64 conversion or FileReader.readAsDataURL approach, stripping the
data URL prefix when applicable. Preserve the existing
extractDocumentText(base64, file.type) call while avoiding large intermediate
string allocations on the main thread.

Comment on lines +448 to +456
<span className="status-badge" style={{
padding: "7px 18px", borderRadius: "99px", fontWeight: 700,
fontSize: "12px", letterSpacing: "0.05em",
background: badge.color, color: "#fff",
boxShadow: `0 4px 14px ${badge.color}40`,
}}>
{badge.label}
</span>
<button className="btn-ghost" onClick={reset} style={{

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Disguise malfunction: var() + hex-alpha suffix doesn't blend, it breaks.

badge.color / getStatusColor() return "var(--success)" etc. Appending a hex alpha suffix (${badge.color}40, ${getStatusColor(r.status)}30) yields "var(--success)40" / "var(--success)30" — not valid CSS color syntax. The browser will drop these declarations, so the badge glow shadow (line 452) and check-row border tint (line 541) silently fail to render as designed.

🎨 Proposed fix — use color-mix() or rgba variables instead of string-concatenating var()
-                  boxShadow: `0 4px 14px ${badge.color}40`,
+                  boxShadow: `0 4px 14px color-mix(in srgb, ${badge.color} 25%, transparent)`,
-                      border: `1px solid ${getStatusColor(r.status)}30`,
+                      border: `1px solid color-mix(in srgb, ${getStatusColor(r.status)} 20%, transparent)`,

Also applies to: 538-544

🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/app/page.tsx` around lines 448 - 456,
Replace the hex-alpha suffix concatenation using badge.color and getStatusColor
in the badge boxShadow and check-row border styling with valid CSS color
composition, such as color-mix() or dedicated rgba variables. Preserve each
status color and intended transparency while ensuring both the glow and border
declarations remain valid when the source value is a CSS var().

Comment on lines +509 to +525
{Object.entries(report.extracted_fields).map(([key, value]) => (
<div key={key} style={{
display: "flex", justifyContent: "space-between", alignItems: "flex-start",
paddingBottom: "10px", borderBottom: "1px solid var(--border)",
}}>
<span style={{ fontSize: "12px", color: "var(--text-muted)", textTransform: "capitalize", flexShrink: 0, marginRight: "12px" }}>
{key.replace(/_/g, " ")}
</span>
<span style={{
fontSize: "12px", color: value != null ? "var(--text-primary)" : "var(--danger)",
fontWeight: value != null ? 500 : 400, textAlign: "right",
fontStyle: value == null ? "italic" : "normal",
}}>
{value == null ? "— missing —" : String(value)}
</span>
</div>
))}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Missing-field alarm never trips — the contract says empty string, not null.

Rendering checks value == null to decide whether to show "— missing —" in danger styling. Per trade-finance-validator_extractor_system.md rule 10, missing text fields are always returned as "", never null. That means this check practically never fires for genuinely missing data — blank values just render as plain, non-flagged text instead of the intended warning state.

🔍 Proposed fix
-                      <span style={{
-                        fontSize: "12px", color: value != null ? "var(--text-primary)" : "var(--danger)",
-                        fontWeight: value != null ? 500 : 400, textAlign: "right",
-                        fontStyle: value == null ? "italic" : "normal",
-                      }}>
-                        {value == null ? "— missing —" : String(value)}
-                      </span>
+                      <span style={{
+                        fontSize: "12px", color: value != null && value !== "" ? "var(--text-primary)" : "var(--danger)",
+                        fontWeight: value != null && value !== "" ? 500 : 400, textAlign: "right",
+                        fontStyle: value == null || value === "" ? "italic" : "normal",
+                      }}>
+                        {value == null || value === "" ? "— missing —" : String(value)}
+                      </span>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{Object.entries(report.extracted_fields).map(([key, value]) => (
<div key={key} style={{
display: "flex", justifyContent: "space-between", alignItems: "flex-start",
paddingBottom: "10px", borderBottom: "1px solid var(--border)",
}}>
<span style={{ fontSize: "12px", color: "var(--text-muted)", textTransform: "capitalize", flexShrink: 0, marginRight: "12px" }}>
{key.replace(/_/g, " ")}
</span>
<span style={{
fontSize: "12px", color: value != null ? "var(--text-primary)" : "var(--danger)",
fontWeight: value != null ? 500 : 400, textAlign: "right",
fontStyle: value == null ? "italic" : "normal",
}}>
{value == null ? "— missing —" : String(value)}
</span>
</div>
))}
{Object.entries(report.extracted_fields).map(([key, value]) => (
<div key={key} style={{
display: "flex", justifyContent: "space-between", alignItems: "flex-start",
paddingBottom: "10px", borderBottom: "1px solid var(--border)",
}}>
<span style={{ fontSize: "12px", color: "var(--text-muted)", textTransform: "capitalize", flexShrink: 0, marginRight: "12px" }}>
{key.replace(/_/g, " ")}
</span>
<span style={{
fontSize: "12px", color: value != null && value !== "" ? "var(--text-primary)" : "var(--danger)",
fontWeight: value != null && value !== "" ? 500 : 400, textAlign: "right",
fontStyle: value == null || value === "" ? "italic" : "normal",
}}>
{value == null || value === "" ? "— missing —" : String(value)}
</span>
</div>
))}
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/app/page.tsx` around lines 509 - 525,
Update the extracted-field rendering in the report.extracted_fields map to treat
empty strings as missing alongside nullish values, including the displayed
placeholder, danger color, font weight, and italic styling. Preserve normal
rendering for non-empty values and continue converting present values with
String(value).

"@radix-ui/react-tabs": "1.1.2",
"@radix-ui/react-tooltip": "1.1.6",
"@vercel/analytics": "1.3.1",
"autoprefixer": "^10.4.20",

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant autoprefixer dependency.

Agent, intelligence indicates that autoprefixer is now a ghost in the machine. With the Tailwind CSS v4 upgrade, the Oxide engine's built-in Lightning CSS handles all vendor prefixing covertly. You can safely extract this obsolete dependency from your manifest.
As per path instructions, Tailwind CSS v4 handles vendor prefixes internally without PostCSS plugins like autoprefixer.

🧹 Proposed fix
-    "autoprefixer": "^10.4.20",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"autoprefixer": "^10.4.20",
🤖 Prompt for 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.

In `@kits/trade-finance-validator/apps/package.json` at line 22, Remove the
redundant autoprefixer entry from the package manifest, leaving the remaining
dependencies unchanged because Tailwind CSS v4 and Lightning CSS now provide
vendor prefixing.

Comment on lines +4 to +6
- **Trade License**: Issued by a government authority. Contains license number, business name, owner, activity type, issue date, expiry date, issuing authority, and stamp/signature.
- **Letter of Credit (LC)**: Issued by a bank. Contains LC reference number, issuing bank, advising bank, applicant, beneficiary, amount, currency, issue date, expiry date, place of expiry, payment terms, and signatures.
- **Commercial Invoice**: Issued by seller to buyer. Contains invoice number, seller, buyer, goods description, quantity, unit price, total amount, currency, invoice date, and payment terms.

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,120p' kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md | cat -n

Repository: Lamatic/AgentKit

Length of output: 2760


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
p = Path('kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md')
text = p.read_text()
for i, line in enumerate(text.splitlines(), 1):
    if 'extracted_fields' in line or 'Commercial Invoice' in line or 'quantity' in line or 'unit_price' in line:
        print(f"{i}: {line}")
PY

Repository: Lamatic/AgentKit

Length of output: 466


🏁 Script executed:

rg -n "extracted_fields|Commercial Invoice|quantity|unit_price|unit price|qty" kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md

Repository: Lamatic/AgentKit

Length of output: 463


🏁 Script executed:

ast-grep outline kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md

Repository: Lamatic/AgentKit

Length of output: 249


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
p = Path('kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md')
print(p.exists())
if p.exists():
    for i, line in enumerate(p.read_text().splitlines(), 1):
        if 1 <= i <= 120:
            print(f"{i}: {line}")
PY

Repository: Lamatic/AgentKit

Length of output: 2633


Mission gap: add quantity and unit_price to extracted_fields
The Commercial Invoice description promises quantity and unit price, but the JSON schema has no matching fields, so that data gets dropped. Add those keys or remove them from the invoice spec.

🤖 Prompt for 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.

In
`@kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.md`
around lines 4 - 6, The Commercial Invoice field specification and
extracted_fields schema are inconsistent for quantity and unit price. Update the
schema in the relevant extractor prompt to include matching quantity and
unit_price keys, preserving the existing invoice extraction fields and naming
conventions.


I built this because I was tired of watching junior credit ops folks manually comb through Letters of Credit, trade licenses, and invoices looking for the same handful of things every time — missing signatures, expired dates, a beneficiary field that's just... blank. It's the kind of first-pass review that eats an analyst's morning and still slips up sometimes.

This kit does that first pass for you. Upload a document (or paste the text), and it extracts the key fields, runs them against a compliance checklist, and gives you a pass/fail verdict with a plain-English summary. It doesn't replace a human reviewer — it just makes sure the obvious stuff gets caught before it reaches one.

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Document the exact verdict enum.

The README currently describes only pass/fail and shows "overall_status": "failed", but the validator contract includes PASSED, PASSED WITH WARNINGS, and FAILED. Case-sensitive consumers could implement the wrong comparisons and miss warning results. Update the prose and JSON example to use the exact runtime values, including a warnings example.

Also applies to: 38-44

🤖 Prompt for 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.

In `@kits/trade-finance-validator/README.md` at line 5, Update the README’s
verdict documentation and JSON example to use the exact case-sensitive runtime
values PASSED, PASSED WITH WARNINGS, and FAILED. Replace the lowercase failed
example and add an explicit warnings example so consumers understand and can
handle all validator outcomes.

@github-actions

Copy link
Copy Markdown
Contributor

Hi @sivaprasad-ai! 👋

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! 🙏

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.

1 participant