feat: Trade Finance Document Validator kit#248
Conversation
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>
:robot_face: AgentKit Structural ValidationNew Contributions Detected
Check Results
|
WalkthroughChangesTrade Finance Validator
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
kits/trade-finance-validator/apps/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (29)
kits/trade-finance-validator/.gitignorekits/trade-finance-validator/README.mdkits/trade-finance-validator/agent.mdkits/trade-finance-validator/apps/.env.examplekits/trade-finance-validator/apps/.gitignorekits/trade-finance-validator/apps/actions/extract-text.tskits/trade-finance-validator/apps/actions/orchestrate.tskits/trade-finance-validator/apps/app/globals.csskits/trade-finance-validator/apps/app/layout.tsxkits/trade-finance-validator/apps/app/page.tsxkits/trade-finance-validator/apps/lib/lamatic-client.tskits/trade-finance-validator/apps/lib/utils.tskits/trade-finance-validator/apps/next-env.d.tskits/trade-finance-validator/apps/next.config.mjskits/trade-finance-validator/apps/orchestrate.tskits/trade-finance-validator/apps/package.jsonkits/trade-finance-validator/apps/tsconfig.jsonkits/trade-finance-validator/constitutions/default.mdkits/trade-finance-validator/flows/trade-finance-validator.tskits/trade-finance-validator/lamatic.config.tskits/trade-finance-validator/model-configs/trade-finance-validator_extractor.tskits/trade-finance-validator/model-configs/trade-finance-validator_reporter.tskits/trade-finance-validator/model-configs/trade-finance-validator_validator.tskits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.mdkits/trade-finance-validator/prompts/trade-finance-validator_extractor_user.mdkits/trade-finance-validator/prompts/trade-finance-validator_reporter_system.mdkits/trade-finance-validator/prompts/trade-finance-validator_reporter_user.mdkits/trade-finance-validator/prompts/trade-finance-validator_validator_system.mdkits/trade-finance-validator/prompts/trade-finance-validator_validator_user.md
| export async function extractDocumentText( | ||
| fileBase64: string, | ||
| mimeType: string | ||
| ): Promise<{ success: boolean; text?: string; error?: string }> { | ||
| try { | ||
| const buffer = Buffer.from(fileBase64, "base64"); | ||
|
|
There was a problem hiding this comment.
🩺 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:
- 1: https://nextjs.org/docs/app/api-reference/config/next-config-js/serverActions
- 2: https://nextjs.org/docs/13/app/api-reference/functions/server-actions
- 3: https://nextjs.org/docs/app/guides/server-actions
- 4: https://stackoverflow.com/questions/78196546/why-does-my-server-action-not-run-when-i-pass-in-images-that-are-too-large-using
- 5: Server Action fails silently when body size exceeds limit, preventing custom error handling vercel/next.js#74766
- 6: sebmarkbage/next.js@07483d4
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"; |
There was a problem hiding this comment.
📐 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 toimport { config } from "../../lamatic.config";kits/trade-finance-validator/apps/lib/lamatic-client.ts#L2-L2: Re-route this import toimport { config } from "../../lamatic.config";
As per coding guidelines, Kit Next.js apps must import and use../../lamatic.configto 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
| 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; | ||
| } |
There was a problem hiding this comment.
🩺 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.
| 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.
| // ── 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> | ||
| ); | ||
| } |
There was a problem hiding this comment.
📐 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
| 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); |
There was a problem hiding this comment.
🚀 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.
| 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.
| <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={{ |
There was a problem hiding this comment.
🎯 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().
| {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> | ||
| ))} |
There was a problem hiding this comment.
🎯 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.
| {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", |
There was a problem hiding this comment.
📐 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.
| "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.
| - **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. |
There was a problem hiding this comment.
🎯 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 -nRepository: 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}")
PYRepository: 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.mdRepository: Lamatic/AgentKit
Length of output: 463
🏁 Script executed:
ast-grep outline kits/trade-finance-validator/prompts/trade-finance-validator_extractor_system.mdRepository: 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}")
PYRepository: 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. |
There was a problem hiding this comment.
🗄️ 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.
|
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:
This helps keep the review process efficient for everyone. Thank you! 🙏 |
Trade Finance Document Validator
An AI-powered first-pass compliance reviewer for trade finance documents.
What it does
Flow
API Request → Extract Fields (LLM) → Validate Rules (LLM) → Generate Summary (LLM) → Finalise Output (Code) → API Response
Stack
Author
Built by Sivaprasad — trade finance document validation from real-world experience in credit and CIBG workflows.
pdf-parse.mammoth.