Feat: Support Triage [agentkit-challenge]#80
Feat: Support Triage [agentkit-challenge]#80VITianYash42 wants to merge 8 commits intoLamatic:mainfrom
Conversation
WalkthroughThis PR establishes a complete Next.js-based "AI Support Triage Engine" automation kit within the support-triage directory. It introduces a client-side interface for processing support tickets, a backend API route for AI integration via Lamatic, comprehensive project configuration, and documentation. Changes
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 8
🧹 Nitpick comments (4)
kits/automation/support-triage/README.md (1)
16-17: Update placeholder Flow ID.The Flow ID shows
your-flow-idas a placeholder. Consider either removing this line (since users will set it via environment variables) or noting this is obtained from Lamatic Studio after flow creation.kits/automation/support-triage/app/layout.tsx (1)
15-18: Update boilerplate metadata.The metadata still contains default "Create Next App" values. Update to reflect the actual kit purpose.
✏️ Suggested metadata
export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "AI Support Triage Engine", + description: "Automated customer support ticket categorization, sentiment analysis, and draft response generation", };kits/automation/support-triage/app/globals.css (1)
22-26: Use the configured font variable instead of hardcoded Arial.The
@theme inlineblock defines--font-sans: var(--font-geist-sans), but the body styles hardcodeArial, Helvetica, sans-serif. Use the Tailwind font variable for consistency with the configured Geist fonts.✏️ Proposed fix
body { background: var(--background); color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + font-family: var(--font-sans), Arial, Helvetica, sans-serif; }kits/automation/support-triage/config.json (1)
19-22: Populate public URLs in config for discoverability.Given this PR already provides a live preview and walkthrough, leaving
demoUrl,deployUrl, anddocumentationUrlempty misses useful kit metadata.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dfad26f1-5b68-4704-bd09-a8fec7c77d22
⛔ Files ignored due to path filters (7)
kits/automation/support-triage/app/favicon.icois excluded by!**/*.icokits/automation/support-triage/package-lock.jsonis excluded by!**/package-lock.jsonkits/automation/support-triage/public/file.svgis excluded by!**/*.svgkits/automation/support-triage/public/globe.svgis excluded by!**/*.svgkits/automation/support-triage/public/next.svgis excluded by!**/*.svgkits/automation/support-triage/public/vercel.svgis excluded by!**/*.svgkits/automation/support-triage/public/window.svgis excluded by!**/*.svg
📒 Files selected for processing (12)
kits/automation/support-triage/.gitignorekits/automation/support-triage/README.mdkits/automation/support-triage/app/globals.csskits/automation/support-triage/app/layout.tsxkits/automation/support-triage/app/page.tsxkits/automation/support-triage/app/utils.tskits/automation/support-triage/config.jsonkits/automation/support-triage/eslint.config.mjskits/automation/support-triage/next.config.tskits/automation/support-triage/package.jsonkits/automation/support-triage/postcss.config.mjskits/automation/support-triage/tsconfig.json
| export const lamaticClient = new Lamatic({ | ||
| endpoint:process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ENDPOINT as string, | ||
| projectId: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_ID as string, | ||
| apiKey: process.env.NEXT_PUBLIC_LAMATIC_PROJECT_API_KEY as string, | ||
| }) |
There was a problem hiding this comment.
Security: API key exposed to the browser via NEXT_PUBLIC_ prefix.
Environment variables prefixed with NEXT_PUBLIC_ are bundled into the client-side JavaScript and visible to anyone inspecting the page. The NEXT_PUBLIC_LAMATIC_PROJECT_API_KEY will be exposed in the browser, allowing unauthorized use of your API credentials.
Move API calls to a server-side API route (app/api/triage/route.ts) and use non-prefixed environment variables.
🔒 Recommended approach: Create a server-side API route
Create app/api/triage/route.ts:
import { Lamatic } from 'lamatic';
import { NextRequest, NextResponse } from 'next/server';
const lamaticClient = new Lamatic({
endpoint: process.env.LAMATIC_PROJECT_ENDPOINT!,
projectId: process.env.LAMATIC_PROJECT_ID!,
apiKey: process.env.LAMATIC_PROJECT_API_KEY!,
});
export async function POST(request: NextRequest) {
const { ticket_text } = await request.json();
const response = await lamaticClient.executeFlow(
process.env.LAMATIC_FLOW_ID!,
{ ticket_text }
);
return NextResponse.json(response);
}There was a problem hiding this comment.
please use server side JWT encryptions
There was a problem hiding this comment.
@amanintech, understood! Here's the mission plan to implement server-side JWT authentication to lock down the /api/triage route while keeping all credentials out of the browser.
Mission: Server-side JWT Encryption for /api/triage
- Add
josefor Edge-compatible JWT signing/verification - Add
JWT_SECRETto.env.example - Create
/api/tokenroute to issue short-lived JWTs server-side - Protect
/api/triageroute with JWT verification - Remove
utils.ts(the leaked client) - Update
page.tsxto fetch a token before calling/api/triage
Here's the overall security flow after these changes:
sequenceDiagram
participant Browser
participant TokenServer as /api/token (Server)
participant TriageServer as /api/triage (Server)
participant Lamatic
Browser->>+TokenServer: POST (no credentials)
TokenServer-->>-Browser: { token: "<signed JWT, 2min TTL>" }
Browser->>+TriageServer: POST Authorization: Bearer <token>
TriageServer->>+TriageServer: jwtVerify(token, JWT_SECRET)
TriageServer->>+Lamatic: executeFlow(flowId, { ticket_text })
Lamatic-->>-TriageServer: triage result
TriageServer-->>-Browser: { category, sentiment, urgency, draft }
Key security properties of this approach:
- 🔒
LAMATIC_PROJECT_API_KEY,LAMATIC_PROJECT_ID, andJWT_SECRETnever leave the server - ⏱️ JWTs are short-lived (2 min), limiting replay attack windows
- 🚫
/api/triagerejects any request without a valid, unexpired JWT - ✅ No
NEXT_PUBLIC_prefixes needed anywhere
✏️ Learnings added
Learnt from: amanintech
Repo: Lamatic/AgentKit PR: 80
File: kits/automation/support-triage/app/utils.ts:0-0
Timestamp: 2026-03-27T19:13:29.605Z
Learning: In `kits/automation/support-triage`, the maintainer (amanintech) requires server-side JWT authentication for API routes. Use the `jose` library with an `HS256` short-lived JWT (2-minute TTL) issued by `/api/token` and verified in `/api/triage`. The JWT_SECRET must be a non-NEXT_PUBLIC_ env var. All Lamatic credentials (LAMATIC_PROJECT_ENDPOINT, LAMATIC_PROJECT_ID, LAMATIC_PROJECT_API_KEY, LAMATIC_FLOW_ID) must also be non-NEXT_PUBLIC_ and server-only.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: CR
Repo: Lamatic/AgentKit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T17:08:51.738Z
Learning: Applies to kits/**/lib/lamatic-client.ts : Use the `lib/lamatic-client.ts` pattern to initialize the Lamatic SDK with `LAMATIC_API_URL`, `LAMATIC_PROJECT_ID`, and `LAMATIC_API_KEY`
Learnt from: CR
Repo: Lamatic/AgentKit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T17:08:51.738Z
Learning: Applies to kits/**/actions/**/*.ts : Kit server action files (e.g., `actions/orchestrate.ts`) must call Lamatic flows via the SDK and read flow IDs from environment variables
Failed to handle agent chat message. Please try again.
There was a problem hiding this comment.
Actionable comments posted: 4
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 431fe6de-06eb-4766-89f8-5b0d5cd6b042
📒 Files selected for processing (7)
kits/automation/support-triage/.env.examplekits/automation/support-triage/.gitignorekits/automation/support-triage/app/api/triage/route.jskits/automation/support-triage/app/globals.csskits/automation/support-triage/app/layout.tsxkits/automation/support-triage/app/page.tsxkits/automation/support-triage/config.json
✅ Files skipped from review due to trivial changes (2)
- kits/automation/support-triage/.gitignore
- kits/automation/support-triage/config.json
🚧 Files skipped from review as they are similar to previous changes (1)
- kits/automation/support-triage/app/layout.tsx
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ca9f0c9f-ba30-4ca1-ab93-fda9e0b4cbb1
📒 Files selected for processing (1)
kits/automation/support-triage/app/page.tsx
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
kits/automation/support-triage/app/api/triage/route.ts (2)
12-12:⚠️ Potential issue | 🟠 MajorAgent, your perimeter is unguarded—hostile payloads may breach.
The API currently trusts client input without validation. A missing, non-string, or empty
ticket_textwill pass through to the Lamatic provider, causing unnecessary calls and ambiguous failures. This intel was previously transmitted—awaiting implementation.🛡️ Proposed validation block
- const { ticket_text } = await request.json(); + const body = await request.json(); + const ticket_text = + typeof body?.ticket_text === "string" ? body.ticket_text.trim() : ""; + + if (!ticket_text) { + return NextResponse.json( + { error: "ticket_text must be a non-empty string." }, + { status: 400 } + ); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@kits/automation/support-triage/app/api/triage/route.ts` at line 12, Validate the incoming ticket_text immediately after parsing request.json(): ensure ticket_text exists, is a string, and is not empty/whitespace; if validation fails return a 400/Bad Request response with a clear error message instead of calling the Lamatic provider. Update the code around the const { ticket_text } = await request.json(); extraction (the request.json() parsing and any subsequent call to the Lamatic provider) to perform these checks and short-circuit on invalid input.
19-20:⚠️ Potential issue | 🟠 MajorAgent, mission control is receiving false positives.
The
executeFlowresponse may include{ status: "error", message: ... }, which this route currently returns as HTTP 200. The frontend inpage.tsx(lines 26-39) checks fordata.errorand rate-limit patterns, but a Lamatic error response won't trigger those guards—it'll slip through as "success."Other kits in this repo check
response?.status === "error"and handle accordingly. This intel was previously transmitted—awaiting alignment with established protocol.🔧 Proposed response handling
const response = await lamaticClient.executeFlow(flowId, { ticket_text }); - return NextResponse.json(response); + if (response?.status === "error") { + return NextResponse.json( + { error: response?.message || "Lamatic flow execution failed." }, + { status: 502 } + ); + } + + return NextResponse.json(response?.result ?? response);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@kits/automation/support-triage/app/api/triage/route.ts` around lines 19 - 20, The route currently returns lamaticClient.executeFlow(flowId, { ticket_text }) directly as HTTP 200 even when the response is an error object; update the handler in route.ts to inspect the returned value from lamaticClient.executeFlow (e.g., check response?.status === "error" or presence of response.message) and return an appropriate non-200 response (use NextResponse.json with a 4xx/5xx status or NextResponse.error) when an error status is present, otherwise return the successful payload via NextResponse.json; reference lamaticClient.executeFlow, flowId, ticket_text, and NextResponse.json when making this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@kits/automation/support-triage/app/api/triage/route.ts`:
- Around line 4-8: The Lamatic client is being constructed at module load using
non-null assertions (Lamatic and lamaticClient built from
process.env.LAMATIC_PROJECT_ENDPOINT!, LAMATIC_PROJECT_ID!,
LAMATIC_PROJECT_API_KEY!), which will crash the module with a cryptic error if
any env var is missing; change this to either validate env vars up-front with
clear diagnostic messages or lazily create the client at request time via a
factory like getLamaticClient() that checks
process.env.LAMATIC_PROJECT_ENDPOINT/ID/API_KEY and throws or returns a
controlled error; update any callers (e.g., where flowId is checked) to call the
factory and handle/report the explicit error instead of relying on non-null
assertions at import time.
- Line 21: The catch currently types the caught value as any; change it to
unknown (catch(error: unknown)) and explicitly narrow before using it: check if
error is an instance of Error to access error.message/stack, otherwise coerce to
string (e.g., String(error)) before logging/returning. Update the error handling
inside the same route handler in route.ts (the catch(error: any) block) to
perform this narrowing so TypeScript safety is preserved.
---
Duplicate comments:
In `@kits/automation/support-triage/app/api/triage/route.ts`:
- Line 12: Validate the incoming ticket_text immediately after parsing
request.json(): ensure ticket_text exists, is a string, and is not
empty/whitespace; if validation fails return a 400/Bad Request response with a
clear error message instead of calling the Lamatic provider. Update the code
around the const { ticket_text } = await request.json(); extraction (the
request.json() parsing and any subsequent call to the Lamatic provider) to
perform these checks and short-circuit on invalid input.
- Around line 19-20: The route currently returns
lamaticClient.executeFlow(flowId, { ticket_text }) directly as HTTP 200 even
when the response is an error object; update the handler in route.ts to inspect
the returned value from lamaticClient.executeFlow (e.g., check response?.status
=== "error" or presence of response.message) and return an appropriate non-200
response (use NextResponse.json with a 4xx/5xx status or NextResponse.error)
when an error status is present, otherwise return the successful payload via
NextResponse.json; reference lamaticClient.executeFlow, flowId, ticket_text, and
NextResponse.json when making this change.
🪄 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: ad30a0ae-20a4-4a81-979e-a620388e7fe7
📒 Files selected for processing (1)
kits/automation/support-triage/app/api/triage/route.ts
| const lamaticClient = new Lamatic({ | ||
| endpoint: process.env.LAMATIC_PROJECT_ENDPOINT!, | ||
| projectId: process.env.LAMATIC_PROJECT_ID!, | ||
| apiKey: process.env.LAMATIC_PROJECT_API_KEY!, | ||
| }); |
There was a problem hiding this comment.
Agent, this initialization sequence has a critical vulnerability.
Non-null assertions (!) at module initialization time mean if any environment variable is missing, the entire module will fail to load with a cryptic runtime error—long before your helpful flowId check on line 15-17 can provide meaningful feedback.
Consider validating these values at request time or failing fast with clear diagnostics at startup.
🛡️ Proposed defensive initialization
-const lamaticClient = new Lamatic({
- endpoint: process.env.LAMATIC_PROJECT_ENDPOINT!,
- projectId: process.env.LAMATIC_PROJECT_ID!,
- apiKey: process.env.LAMATIC_PROJECT_API_KEY!,
-});
+function getLamaticClient() {
+ const endpoint = process.env.LAMATIC_PROJECT_ENDPOINT;
+ const projectId = process.env.LAMATIC_PROJECT_ID;
+ const apiKey = process.env.LAMATIC_PROJECT_API_KEY;
+
+ if (!endpoint || !projectId || !apiKey) {
+ throw new Error("Missing Lamatic configuration: LAMATIC_PROJECT_ENDPOINT, LAMATIC_PROJECT_ID, and LAMATIC_PROJECT_API_KEY are required.");
+ }
+
+ return new Lamatic({ endpoint, projectId, apiKey });
+}
+
+const lamaticClient = getLamaticClient();📝 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.
| const lamaticClient = new Lamatic({ | |
| endpoint: process.env.LAMATIC_PROJECT_ENDPOINT!, | |
| projectId: process.env.LAMATIC_PROJECT_ID!, | |
| apiKey: process.env.LAMATIC_PROJECT_API_KEY!, | |
| }); | |
| function getLamaticClient() { | |
| const endpoint = process.env.LAMATIC_PROJECT_ENDPOINT; | |
| const projectId = process.env.LAMATIC_PROJECT_ID; | |
| const apiKey = process.env.LAMATIC_PROJECT_API_KEY; | |
| if (!endpoint || !projectId || !apiKey) { | |
| throw new Error("Missing Lamatic configuration: LAMATIC_PROJECT_ENDPOINT, LAMATIC_PROJECT_ID, and LAMATIC_PROJECT_API_KEY are required."); | |
| } | |
| return new Lamatic({ endpoint, projectId, apiKey }); | |
| } | |
| const lamaticClient = getLamaticClient(); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@kits/automation/support-triage/app/api/triage/route.ts` around lines 4 - 8,
The Lamatic client is being constructed at module load using non-null assertions
(Lamatic and lamaticClient built from process.env.LAMATIC_PROJECT_ENDPOINT!,
LAMATIC_PROJECT_ID!, LAMATIC_PROJECT_API_KEY!), which will crash the module with
a cryptic error if any env var is missing; change this to either validate env
vars up-front with clear diagnostic messages or lazily create the client at
request time via a factory like getLamaticClient() that checks
process.env.LAMATIC_PROJECT_ENDPOINT/ID/API_KEY and throws or returns a
controlled error; update any callers (e.g., where flowId is checked) to call the
factory and handle/report the explicit error instead of relying on non-null
assertions at import time.
|
|
||
| const response = await lamaticClient.executeFlow(flowId, { ticket_text }); | ||
| return NextResponse.json(response); | ||
| } catch (error: any) { |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Agent, any is a liability in your cover.
Using any type defeats TypeScript's safety guarantees. Prefer unknown and narrow explicitly, or use a more specific error type.
♻️ Proposed type-safe error handling
- } catch (error: any) {
- return NextResponse.json({ error: error.message || "API execution failed" }, { status: 500 });
+ } catch (error: unknown) {
+ const message = error instanceof Error ? error.message : "API execution failed";
+ return NextResponse.json({ error: message }, { status: 500 });
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@kits/automation/support-triage/app/api/triage/route.ts` at line 21, The catch
currently types the caught value as any; change it to unknown (catch(error:
unknown)) and explicitly narrow before using it: check if error is an instance
of Error to access error.message/stack, otherwise coerce to string (e.g.,
String(error)) before logging/returning. Update the error handling inside the
same route handler in route.ts (the catch(error: any) block) to perform this
narrowing so TypeScript safety is preserved.
What This Kit Does
Automates customer support by taking inbound tickets and instantly generating a category, sentiment analysis, urgency level, and a draft email response. This saves time, reduces manual routing work, and improves response clarity.
Video Walkthrough: (https://drive.google.com/file/d/192fqT63JLxS9tOcBvN-nEK8ll36xbKhs/view?usp=sharing)
Providers & Prerequisites
(Note: Requires a 60-second cooldown between requests to prevent 429 Rate Limit errors. The Next.js UI explicitly catches and handles this exception.)
(Note 2: The Lamatic Studio UI currently lacks the 'Export' button on the flow menu as documented in CONTRIBUTING.md, so raw JSON flow files are intentionally omitted.)
How to Run Locally
cd kits/automation/support-triagenpm installcp .env.example .env.localand fill in valuesnpm run devLive Preview
https://agent-kit-git-feat-suppo-3f22fd-yash-singhals-projects-d43367ba.vercel.app/
Lamatic Flow
Flow ID:
c5e67b16-fa77-454d-80d4-77b40adbda38Files Added Summary
Configuration & Setup Files
.gitignore- Ignores Node.js artifacts, Next.js build output (.next/,out/,build/), environment files (.env*), TypeScript build artifacts, and common development filespackage.json- Defines thelamatic-triageNext.js application with dependencies:lamatic(^0.3.2),next(16.2.0),react/react-dom(19.2.4); includes dev dependencies for Tailwind, TypeScript, and ESLinttsconfig.json- TypeScript configuration with ES2017 target, strict type checking, React JSX viareact-jsx, Next.js plugin support, and path alias mapping@/*next.config.ts- Next.js configuration file (typed as NextConfig)eslint.config.mjs- ESLint flat configuration usingeslint-config-nextwith custom ignore patterns for.next/,out/,build/, andnext-env.d.tspostcss.config.mjs- PostCSS configuration enabling@tailwindcss/postcsspluginconfig.json- Automation metadata defining the "AI Support Triage Engine" with Lamatic Flow and Gemini integrations, features list, and demo/GitHub URLsEnvironment & Documentation
.env.example- Template for required environment variables:LAMATIC_PROJECT_ENDPOINT,LAMATIC_PROJECT_ID,LAMATIC_PROJECT_API_KEY,LAMATIC_FLOW_IDREADME.md- Documentation describing the kit's purpose, prerequisites (Lamatic Studio Flow + Gemini with 60-second cooldown), and local setup instructionsFrontend Application
app/layout.tsx- Root Next.js layout component; initializes Google Fonts (GeistandGeist_Mono), exports metadata, and renders the HTML document structureapp/globals.css- Global CSS with Tailwind integration; defines custom properties for--background/--foregroundwith light/dark mode support and font variable mappingsapp/page.tsx- Client-side page component (169 lines) featuring:ticketText,loading, andtriageData/api/triagewith error handling for rate limits (429) and quota errorsBackend API
app/api/triage/route.ts- Next.js API route handler:ticket_textfrom the clientlamaticClient.executeFlow(flowId, { ticket_text })LAMATIC_FLOW_IDor execution failuresHigh-Level Flow Overview
The Support Triage kit automates customer support ticket processing through a three-tier architecture:
The flow is identified by environment variable
NEXT_PUBLIC_LAMATIC_FLOW_ID(ID: c5e67b16-fa77-454d-80d4-77b40adbda38) and includes built-in rate-limit handling with a 60-second cooldown between requests to avoid Gemini Free Tier 429 errors.