feat: Add mock-ai interviewer Agentkit#101
feat: Add mock-ai interviewer Agentkit#101sreecharan1306 wants to merge 5 commits intoLamatic:mainfrom
Conversation
📝 WalkthroughWalkthroughAdds a new Next.js "mockai" agent kit at Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Page as App/Page (Next.js)
participant Orchestrate as Server Action\n(actions/orchestrate.ts)
participant LamaticClient as Lamatic Client\n(lib/lamatic-client.ts)
participant LamaticAPI as Lamatic API
User->>Page: Submit jobTitle, yearsOfExp, jobDesc
Page->>Orchestrate: generateQuestions(jobTitle, yearsOfExp, jobDesc)
Orchestrate->>LamaticClient: executeFlow(questionWorkflowId, inputs)
LamaticClient->>LamaticAPI: POST /flows/execute (with credentials)
LamaticAPI-->>LamaticClient: { result: { data: questions[] } }
LamaticClient-->>Orchestrate: flow response
Orchestrate-->>Page: { success: true, questions }
User->>Page: Provide answers (text or voice)
Page->>Orchestrate: evaluateAnswers(candidateResponses)
Orchestrate->>LamaticClient: executeFlow(feedbackWorkflowId, responses)
LamaticClient->>LamaticAPI: POST /flows/execute (with credentials)
LamaticAPI-->>LamaticClient: { result: { rating, positives, negatives } }
LamaticClient-->>Orchestrate: feedback response
Orchestrate-->>Page: { success: true, feedback }
Page->>User: Render rating, positives, negatives
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 19
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (17)
kits/agentic/mockai/.gitignore-19-21 (1)
19-21:⚠️ Potential issue | 🟡 MinorAdd
.env.localto prevent accidental secret commits.The
.gitignoreexcludes.envbut is missing.env.local, which is commonly used by Next.js for local environment variables. As per coding guidelines, both.envand.env.localmust be excluded.Proposed fix
# env files .env +.env.localkits/agentic/mockai/components/ui/slider.tsx-16-24 (1)
16-24:⚠️ Potential issue | 🟡 MinorReconsider the
[min, max]fallback behavior for_values.When neither
valuenordefaultValueis provided,_valuesdefaults to[min, max], which renders exactly two thumbs regardless of intended use. This creates a range slider by default, which may not match the expected behavior for a single-value slider.Consider using
[min]as the fallback to render a single thumb by default, or document that consumers must provide an explicitdefaultValue.kits/agentic/mockai/components/ui/kbd.tsx-18-24 (1)
18-24:⚠️ Potential issue | 🟡 MinorUse a structural wrapper for
KbdGroupinstead of<kbd>.
KbdGroupis typed asReact.ComponentProps<'div'>but currently renders<kbd>, which gives incorrect semantics for a group container.Proposed fix
function KbdGroup({ className, ...props }: React.ComponentProps<'div'>) { return ( - <kbd + <div data-slot="kbd-group" className={cn('inline-flex items-center gap-1', className)} {...props} - /> + /> ) }kits/agentic/mockai/components/ui/carousel.tsx-64-105 (1)
64-105:⚠️ Potential issue | 🟡 MinorAdd symmetric cleanup for the
reInitevent listener in the effect's return statement.The code subscribes to both
reInitandselectevents (lines 99–100), but the cleanup only unsubscribes fromselect(line 105). Since Embla listeners persist until explicitly removed viaoff(), thereInitlistener should also be cleaned up to prevent memory leaks.Current cleanup (incomplete)
return () => { api?.off('select', onSelect) }Update to:
return () => { api?.off('reInit', onSelect) api?.off('select', onSelect) }kits/agentic/mockai/components/ui/carousel.tsx-78-88 (1)
78-88:⚠️ Potential issue | 🟡 MinorMatch keyboard navigation to the chosen orientation.
Lines 80-85 always consume Left/Right. When
orientation="vertical", the buttons render as up/down controls but the keyboard path still ignores ArrowUp/ArrowDown, so vertical carousels are inconsistent for keyboard users.♿ Proposed fix
const handleKeyDown = React.useCallback( (event: React.KeyboardEvent<HTMLDivElement>) => { - if (event.key === 'ArrowLeft') { + const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp' + const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown' + + if (event.key === prevKey) { event.preventDefault() scrollPrev() - } else if (event.key === 'ArrowRight') { + } else if (event.key === nextKey) { event.preventDefault() scrollNext() } }, - [scrollPrev, scrollNext], + [orientation, scrollPrev, scrollNext], )kits/agentic/mockai/hooks/use-toast.ts-174-182 (1)
174-182:⚠️ Potential issue | 🟡 MinorIncorrect
useEffectdependency causes unnecessary re-subscriptions.The dependency array includes
[state], but the effect only subscribes/unsubscribes the listener. This causes the effect to re-run on every state change, repeatedly adding and removing the samesetStatefrom the listeners array. The dependency should be empty[]to subscribe once on mount and cleanup on unmount.🐛 Proposed fix
React.useEffect(() => { listeners.push(setState) return () => { const index = listeners.indexOf(setState) if (index > -1) { listeners.splice(index, 1) } } - }, [state]) + }, [])kits/agentic/mockai/components/ui/empty.tsx-71-81 (1)
71-81:⚠️ Potential issue | 🟡 MinorType and element mismatch in
EmptyDescription.The component is typed as
React.ComponentProps<'p'>but renders a<div>element. This inconsistency could cause confusion when consumers expect paragraph-specific behavior or accessibility semantics.🐛 Proposed fix - align type with element
-function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) { +function EmptyDescription({ className, ...props }: React.ComponentProps<'div'>) { return ( <div data-slot="empty-description"Or alternatively, render a
<p>element to match the type:function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) { return ( - <div + <p data-slot="empty-description" className={cn( 'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4', className, )} {...props} - /> + /> ) }kits/agentic/mockai/components/ui/input-group.tsx-70-76 (1)
70-76:⚠️ Potential issue | 🟡 MinorAddon click handler can be silently overridden and misses textarea focus.
Because
...propsis spread afteronClick, consumeronClickcan replace this logic entirely. Also, focusing onlyinputskipsInputGroupTextareacontrols.💡 Proposed fix
function InputGroupAddon({ className, align = 'inline-start', + onClick, ...props }: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) { return ( <div @@ - onClick={(e) => { - if ((e.target as HTMLElement).closest('button')) { + onClick={(e) => { + onClick?.(e) + if (e.defaultPrevented) return + if ((e.target as HTMLElement).closest('button,[role="button"]')) { return } - e.currentTarget.parentElement?.querySelector('input')?.focus() + e.currentTarget.parentElement + ?.querySelector<HTMLElement>('[data-slot="input-group-control"]') + ?.focus() }} {...props} /> ) }kits/agentic/mockai/components/ui/field.tsx-194-229 (1)
194-229:⚠️ Potential issue | 🟡 MinorDon't render an empty alert when no error messages exist.
errors=[](or entries withoutmessage) still produces a truthy empty<ul>, soFieldErrorrendersrole="alert"with no content. Filter the messages first and returnnullwhen the filtered list is empty.Suggested fix
const content = useMemo(() => { if (children) { return children } - if (!errors) { + const messages = + errors?.flatMap((error) => (error?.message ? [error.message] : [])) ?? [] + + if (messages.length === 0) { return null } - if (errors.length === 1 && errors[0]?.message) { - return errors[0].message + if (messages.length === 1) { + return messages[0] } return ( <ul className="ml-4 flex list-disc flex-col gap-1"> - {errors.map( - (error, index) => - error?.message && <li key={index}>{error.message}</li>, - )} + {messages.map((message, index) => ( + <li key={index}>{message}</li> + ))} </ul> ) }, [children, errors])kits/agentic/mockai/components/ui/sidebar.tsx-609-612 (1)
609-612:⚠️ Potential issue | 🟡 MinorRemove or make
Math.random()deterministic.While this component is marked
'use client'and doesn't face hydration mismatches,Math.random()in the render path still creates non-deterministic skeleton widths on each mount, which can complicate testing and reproducibility. Consider accepting the width as a prop, using a seeded random number, or applying a fixed width instead.kits/agentic/mockai/orchestrate.js-1-44 (1)
1-44:⚠️ Potential issue | 🟡 MinorConvert to TypeScript and fix type issues.
This file should be
orchestrate.tsper the project guideline requiring TypeScript for all kit files. Additionally:
pollingshould be boolean: Lines 19 and 36 use"false"(string) instead offalse(boolean).- Missing type definitions: TypeScript would provide better compile-time safety for the config structure.
🔧 Suggested TypeScript conversion
-export const config = { +interface FlowConfig { + name: string; + type: string; + workflowId: string | undefined; + description: string; + expectedOutput: string[]; + inputSchema: Record<string, string>; + outputSchema: Record<string, string>; + mode: string; + polling: boolean; +} + +interface OrchestrateConfig { + type: string; + flows: Record<string, FlowConfig>; + api: { + endpoint: string | undefined; + projectId: string | undefined; + apiKey: string | undefined; + }; +} + +export const config: OrchestrateConfig = { "type": "atomic", "flows": { "question" : { ... "mode": "sync", - "polling" : "false" + "polling" : false }, "feedback" : { ... - "polling" : "false" + "polling" : false } }, ... }As per coding guidelines: "Use TypeScript for all kit components and server actions".
kits/agentic/mockai/app/layout.tsx-6-7 (1)
6-7:⚠️ Potential issue | 🟡 MinorLoaded fonts are not applied to the DOM.
The Geist font objects are instantiated but their class names are never applied. The underscore prefix suggests these are intentionally unused, but this means the fonts won't actually render.
🛠️ Proposed fix to apply the fonts
-const _geist = Geist({ subsets: ["latin"] }); -const _geistMono = Geist_Mono({ subsets: ["latin"] }); +const geist = Geist({ subsets: ["latin"], variable: "--font-geist-sans" }); +const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-geist-mono" });Then apply to the body:
- <body className={`font-sans antialiased`}> + <body className={`${geist.variable} ${geistMono.variable} font-sans antialiased`}>kits/agentic/mockai/.env.example-1-6 (1)
1-6:⚠️ Potential issue | 🟡 MinorFix inconsistent
.envformatting.The file has inconsistent spacing around
=signs (lines 2-4 have spaces, lines 5-6 don't) and is missing a trailing newline. Some env parsers may behave unexpectedly with spaces around=.🛠️ Proposed fix for consistent formatting
-# AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID" -LAMATIC_API_URL = "LAMATIC_API_URL" -LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID" -LAMATIC_API_KEY = "LAMATIC_API_KEY" -AGENTIC_FEEDBACK_FLOW_ID="Feedback agent Flow ID" -AGENTIC_QUESTION_FLOW_ID="Question agent Flow ID" +# AGENTIC_GENERATE_CONTENT="AGENTIC_GENERATE_CONTENT Flow ID" +LAMATIC_API_URL="your_lamatic_api_url" +LAMATIC_PROJECT_ID="your_lamatic_project_id" +LAMATIC_API_KEY="your_lamatic_api_key" +AGENTIC_FEEDBACK_FLOW_ID="your_feedback_flow_id" +AGENTIC_QUESTION_FLOW_ID="your_question_flow_id"kits/agentic/mockai/README.md-2-4 (1)
2-4:⚠️ Potential issue | 🟡 MinorAdd alt text to the hero image.
The
<img>tag is missingalt, which is already being flagged by markdownlint and hurts accessibility for screen-reader users.kits/agentic/mockai/README.md-82-97 (1)
82-97:⚠️ Potential issue | 🟡 MinorAdd a language to the repo-structure fence.
The block starting on Line 82 is unlabeled, so it will keep tripping MD040.
textis enough here.kits/agentic/mockai/components/ui/chart.tsx-235-239 (1)
235-239:⚠️ Potential issue | 🟡 MinorRender
0values in the tooltip.The current truthy check hides legitimate zero datapoints, so a series value of
0disappears from the tooltip. Check fornull/undefinedinstead.🩹 Minimal fix
- {item.value && ( + {item.value !== undefined && item.value !== null && ( <span className="text-foreground font-mono font-medium tabular-nums"> {item.value.toLocaleString()} </span> )}kits/agentic/mockai/components/ui/toast.tsx-77-87 (1)
77-87:⚠️ Potential issue | 🟡 MinorGive the close control an accessible name.
This is currently an icon-only button, so assistive tech will announce an unnamed control. Add
aria-labelor hidden text.♿ Minimal fix
<ToastPrimitives.Close ref={ref} + aria-label="Close toast" className={cn( 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600', className, )}
🧹 Nitpick comments (26)
kits/agentic/mockai/components/ui/use-mobile.tsx (1)
10-12: Preferevent.matchesover recheckingwindow.innerWidth.The
changeevent already provides the query result viaevent.matches. Using it avoids redundant property access and is more idiomatic.♻️ Suggested improvement
- const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - } + const onChange = (event: MediaQueryListEvent) => { + setIsMobile(event.matches) + }kits/agentic/mockai/components/ui/hover-card.tsx (1)
1-1: Rename this component file to PascalCase.The file path uses
hover-card.tsx; please rename toHoverCard.tsxto match the components filename convention.As per coding guidelines:
kits/**/components/**/*.{tsx,ts}: Use PascalCase for React component filenames in thecomponents/directory.kits/agentic/mockai/components/ui/collapsible.tsx (1)
1-33: Filename casing does not follow the component naming guideline.
kits/agentic/mockai/components/ui/collapsible.tsxis lowercase; guideline requires PascalCase filenames incomponents/.Rename to
Collapsible.tsx(and update imports accordingly).
Based on learnings, "Applies to kits//components//*.{tsx,ts} : Use PascalCase for React component filenames in thecomponents/directory".kits/agentic/mockai/components/ui/skeleton.tsx (1)
1-13: Consider PascalCase filename to match coding guidelines.The file is named
skeleton.tsxbut the coding guidelines specify PascalCase for React component filenames in thecomponents/directory (e.g.,Skeleton.tsx). However, this follows standard shadcn/ui naming conventions which use lowercase. Consider whether to align with project guidelines or maintain shadcn/ui consistency across all UI components.kits/agentic/mockai/hooks/use-mobile.ts (1)
5-19: Consider exposing loading state to prevent layout flash on mobile.The hook coerces
undefinedtofalsevia!!isMobile, meaning mobile users briefly see desktop layout until the effect runs. For layout-critical usage, consider returningundefinedduring the indeterminate state so consumers can show a loading placeholder or skeleton.Alternative signature if needed
-export function useIsMobile() { +export function useIsMobile(): boolean | undefined { const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) // ... effect unchanged ... - return !!isMobile + return isMobile }kits/agentic/mockai/components/ui/switch.tsx (1)
1-31: Consider renaming toSwitch.tsxfor consistency with coding guidelines.The component implementation correctly wraps
@radix-ui/react-switchwith proper props forwarding,data-slotattributes, and Tailwind styling. However, the filename uses lowercase (switch.tsx) instead of PascalCase (Switch.tsx).As per coding guidelines: "Use PascalCase for React component filenames in the
components/directory."kits/agentic/mockai/components/ui/kbd.tsx (1)
1-1: Rename lowercase component files incomponents/uito PascalCase.This PR introduces lowercase component filenames (
kbd.tsx,resizable.tsx,button.tsx,alert.tsx,calendar.tsx,scroll-area.tsx). Please rename them to PascalCase to align with kit conventions.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/tsconfig.json (1)
37-38: Remove duplicatedincludeglob entry.
".next\\dev/types/**/*.ts"is listed twice; dropping the duplicate keeps the config cleaner.Proposed fix
"include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", - ".next\\dev/types/**/*.ts", ".next\\dev/types/**/*.ts" ],kits/agentic/mockai/components/ui/toggle-group.tsx (1)
1-73: Rename the new UI component files to PascalCase.This file—and the other newly added
components/ui/*.tsxwrappers in this PR—uses lowercase/kebab-case filenames, which diverges from the repo convention for React component files and will keep imports inconsistent across kits.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/pagination.tsx (1)
9-9: Unused importButton.Only
buttonVariantsis used in this file;Buttonis imported but never referenced.♻️ Proposed fix
-import { Button, buttonVariants } from '@/components/ui/button' +import { buttonVariants } from '@/components/ui/button'kits/agentic/mockai/components/ui/avatar.tsx (1)
1-53: Rename this file to PascalCase.Please rename
avatar.tsxtoAvatar.tsxto match the kit component filename convention.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/sheet.tsx (1)
1-139: Rename this file to PascalCase.Please rename
sheet.tsxtoSheet.tsxto align with the component filename rule.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/alert-dialog.tsx (1)
1-157: Rename this file to PascalCase.Please rename
alert-dialog.tsxtoAlertDialog.tsxfor consistency with kit component naming standards.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/card.tsx (1)
1-92: Rename this file to PascalCase.Please rename
card.tsxtoCard.tsxto satisfy the components directory naming convention.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/input-group.tsx (1)
1-169: Rename this file to PascalCase.Please rename
input-group.tsxtoInputGroup.tsxto comply with the kit naming convention.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/breadcrumb.tsx (1)
1-109: Rename this file to PascalCase.Please rename
breadcrumb.tsxtoBreadcrumb.tsxto follow the required components naming style.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/navigation-menu.tsx (1)
1-166: Rename this file to PascalCase.Please rename
navigation-menu.tsxtoNavigationMenu.tsxto match the enforced naming convention.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/drawer.tsx (1)
1-135: Rename this file to PascalCase.Please rename
drawer.tsxtoDrawer.tsxto adhere to the component filename rule in kits.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/ui/context-menu.tsx (1)
1-252: Rename these new UI primitive files to PascalCase.This file is being added under
components/ascontext-menu.tsx, and the same kebab-case pattern shows up in the sibling UI primitives in this PR. That diverges from the kit naming convention and will make imports inconsistent.As per coding guidelines, "Use PascalCase for React component filenames in the
components/directory".kits/agentic/mockai/components/theme-provider.tsx (1)
1-11: Rename file to PascalCase.The filename
theme-provider.tsxshould beThemeProvider.tsxto comply with the project's component naming conventions. As per coding guidelines: "Use PascalCase for React component filenames in thecomponents/directory".kits/agentic/mockai/flows/feedback-flow/meta.json (1)
1-9: Consider adding a description for discoverability.The
descriptionandtagsfields are empty. Adding a brief description (e.g., "Evaluates candidate interview responses and provides structured feedback with ratings") would improve documentation and flow discoverability.kits/agentic/mockai/components/header.tsx (1)
1-24: Rename file to PascalCase.The filename
header.tsxshould beHeader.tsxto comply with the project's component naming conventions. The component implementation itself is clean and correctly useslucide-reactfor icons. As per coding guidelines: "Use PascalCase for React component filenames in thecomponents/directory".kits/agentic/mockai/flows/agentic-generate-content/meta.json (1)
1-12: Flow metadata seems misaligned with mockai kit purpose.This flow is named "Agentic Generation - Generate Content" with a test input for "write me a poem on AI", but the mockai kit is an interview preparation tool. Consider renaming to reflect the actual interview question generation use case, and adding a relevant
description.kits/agentic/mockai/flows/question-flow/config.json (1)
44-46: Remove the scaffolded user prompt.Line 46 still sends
Write your prompt hereto the model. That placeholder becomes part of the real request, so either replace it with the interview-generation prompt or drop the extra user turn.kits/agentic/mockai/components/ui/toast.tsx (1)
1-1: Rename this component file to PascalCase.
toast.tsxis a React component module undercomponents/, so the filename misses the kit convention.As per coding guidelines,
Use PascalCase for React component filenames in the components/ directory.kits/agentic/mockai/components/ui/chart.tsx (1)
1-1: Rename this component file to PascalCase.
chart.tsxis a React component module undercomponents/, so the filename misses the kit convention.As per coding guidelines,
Use PascalCase for React component filenames in the components/ directory.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c2a95e0f-8071-4117-862c-474c3e77a616
⛔ Files ignored due to path filters (11)
kits/agentic/mockai/package-lock.jsonis excluded by!**/package-lock.jsonkits/agentic/mockai/public/apple-icon.pngis excluded by!**/*.pngkits/agentic/mockai/public/icon-dark-32x32.pngis excluded by!**/*.pngkits/agentic/mockai/public/icon-light-32x32.pngis excluded by!**/*.pngkits/agentic/mockai/public/icon.svgis excluded by!**/*.svgkits/agentic/mockai/public/lamatic-logo.pngis excluded by!**/*.pngkits/agentic/mockai/public/placeholder-logo.pngis excluded by!**/*.pngkits/agentic/mockai/public/placeholder-logo.svgis excluded by!**/*.svgkits/agentic/mockai/public/placeholder-user.jpgis excluded by!**/*.jpgkits/agentic/mockai/public/placeholder.jpgis excluded by!**/*.jpgkits/agentic/mockai/public/placeholder.svgis excluded by!**/*.svg
📒 Files selected for processing (90)
kits/agentic/mockai/.env.examplekits/agentic/mockai/.gitignorekits/agentic/mockai/README.mdkits/agentic/mockai/actions/orchestrate.tskits/agentic/mockai/app/globals.csskits/agentic/mockai/app/layout.tsxkits/agentic/mockai/app/page.tsxkits/agentic/mockai/components.jsonkits/agentic/mockai/components/header.tsxkits/agentic/mockai/components/theme-provider.tsxkits/agentic/mockai/components/ui/accordion.tsxkits/agentic/mockai/components/ui/alert-dialog.tsxkits/agentic/mockai/components/ui/alert.tsxkits/agentic/mockai/components/ui/aspect-ratio.tsxkits/agentic/mockai/components/ui/avatar.tsxkits/agentic/mockai/components/ui/badge.tsxkits/agentic/mockai/components/ui/breadcrumb.tsxkits/agentic/mockai/components/ui/button-group.tsxkits/agentic/mockai/components/ui/button.tsxkits/agentic/mockai/components/ui/calendar.tsxkits/agentic/mockai/components/ui/card.tsxkits/agentic/mockai/components/ui/carousel.tsxkits/agentic/mockai/components/ui/chart.tsxkits/agentic/mockai/components/ui/checkbox.tsxkits/agentic/mockai/components/ui/collapsible.tsxkits/agentic/mockai/components/ui/command.tsxkits/agentic/mockai/components/ui/context-menu.tsxkits/agentic/mockai/components/ui/dialog.tsxkits/agentic/mockai/components/ui/drawer.tsxkits/agentic/mockai/components/ui/dropdown-menu.tsxkits/agentic/mockai/components/ui/empty.tsxkits/agentic/mockai/components/ui/field.tsxkits/agentic/mockai/components/ui/form.tsxkits/agentic/mockai/components/ui/hover-card.tsxkits/agentic/mockai/components/ui/input-group.tsxkits/agentic/mockai/components/ui/input-otp.tsxkits/agentic/mockai/components/ui/input.tsxkits/agentic/mockai/components/ui/item.tsxkits/agentic/mockai/components/ui/kbd.tsxkits/agentic/mockai/components/ui/label.tsxkits/agentic/mockai/components/ui/menubar.tsxkits/agentic/mockai/components/ui/navigation-menu.tsxkits/agentic/mockai/components/ui/pagination.tsxkits/agentic/mockai/components/ui/popover.tsxkits/agentic/mockai/components/ui/progress.tsxkits/agentic/mockai/components/ui/radio-group.tsxkits/agentic/mockai/components/ui/resizable.tsxkits/agentic/mockai/components/ui/scroll-area.tsxkits/agentic/mockai/components/ui/select.tsxkits/agentic/mockai/components/ui/separator.tsxkits/agentic/mockai/components/ui/sheet.tsxkits/agentic/mockai/components/ui/sidebar.tsxkits/agentic/mockai/components/ui/skeleton.tsxkits/agentic/mockai/components/ui/slider.tsxkits/agentic/mockai/components/ui/sonner.tsxkits/agentic/mockai/components/ui/spinner.tsxkits/agentic/mockai/components/ui/switch.tsxkits/agentic/mockai/components/ui/table.tsxkits/agentic/mockai/components/ui/tabs.tsxkits/agentic/mockai/components/ui/textarea.tsxkits/agentic/mockai/components/ui/toast.tsxkits/agentic/mockai/components/ui/toaster.tsxkits/agentic/mockai/components/ui/toggle-group.tsxkits/agentic/mockai/components/ui/toggle.tsxkits/agentic/mockai/components/ui/tooltip.tsxkits/agentic/mockai/components/ui/use-mobile.tsxkits/agentic/mockai/components/ui/use-toast.tskits/agentic/mockai/config.jsonkits/agentic/mockai/flows/agentic-generate-content/README.mdkits/agentic/mockai/flows/agentic-generate-content/config.jsonkits/agentic/mockai/flows/agentic-generate-content/inputs.jsonkits/agentic/mockai/flows/agentic-generate-content/meta.jsonkits/agentic/mockai/flows/feedback-flow/README.mdkits/agentic/mockai/flows/feedback-flow/config.jsonkits/agentic/mockai/flows/feedback-flow/inputs.jsonkits/agentic/mockai/flows/feedback-flow/meta.jsonkits/agentic/mockai/flows/question-flow/README.mdkits/agentic/mockai/flows/question-flow/config.jsonkits/agentic/mockai/flows/question-flow/inputs.jsonkits/agentic/mockai/flows/question-flow/meta.jsonkits/agentic/mockai/hooks/use-mobile.tskits/agentic/mockai/hooks/use-toast.tskits/agentic/mockai/lib/lamatic-client.tskits/agentic/mockai/lib/utils.tskits/agentic/mockai/next.config.mjskits/agentic/mockai/orchestrate.jskits/agentic/mockai/package.jsonkits/agentic/mockai/postcss.config.mjskits/agentic/mockai/styles/globals.csskits/agentic/mockai/tsconfig.json
| error?: string | ||
| }> { | ||
| try { | ||
| console.log("[v0] Generating questions with:", { jobTitle, yearsOfExp, jobDesc }) |
There was a problem hiding this comment.
Remove raw interview payload logging from these server actions.
These logs persist job descriptions, candidate answers, and full Lamatic responses on the server. That's avoidable sensitive-data retention for an interview product; keep only metadata such as flow name, counts, and status.
Also applies to: 30-33, 74-74, 87-90
| const inputs = { | ||
| jobTitle, | ||
| yearsOfExp: parseInt(yearsOfExp.toString()), | ||
| jobDesc | ||
| } |
There was a problem hiding this comment.
Schema-validate both sides of the Lamatic call.
Client-side checks in page.tsx are not a boundary, so malformed payloads can still hit executeFlow here. On the way back, positives and negatives are defaulted but not type-checked, so a truthy non-array will reach the feedback page and blow up when the UI calls .map(...). Validate the request and response shapes before returning success: true.
Also applies to: 35-43, 82-104
| 'use client' | ||
|
|
||
| import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio' | ||
|
|
||
| function AspectRatio({ | ||
| ...props | ||
| }: React.ComponentProps<typeof AspectRatioPrimitive.Root>) { | ||
| return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} /> | ||
| } | ||
|
|
||
| export { AspectRatio } |
There was a problem hiding this comment.
Rename this component file to PascalCase.
aspect-ratio.tsx violates the kit naming convention for files under components/. Please rename to AspectRatio.tsx (and update imports accordingly).
As per coding guidelines: Use PascalCase for React component filenames in the components/ directory.
| function Collapsible({ | ||
| ...props | ||
| }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) { | ||
| return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} /> | ||
| } | ||
|
|
||
| function CollapsibleTrigger({ | ||
| ...props | ||
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) { | ||
| return ( | ||
| <CollapsiblePrimitive.CollapsibleTrigger | ||
| data-slot="collapsible-trigger" | ||
| {...props} | ||
| /> | ||
| ) | ||
| } | ||
|
|
||
| function CollapsibleContent({ | ||
| ...props | ||
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) { |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For current TypeScript + Next.js setups, is React.ComponentPropsvalid withoutimport type * as React from "react"?
💡 Result:
No, React.ComponentProps is not valid without importing React types in current TypeScript + Next.js setups. You must import it explicitly, typically as import type { ComponentProps } from "react"; or via import * as React from "react"; to access React.ComponentProps. All authoritative sources (React TypeScript Cheatsheet, Total TypeScript, @types/react definitions, Next.js docs) show examples requiring an import from "react" to use ComponentProps. The React namespace is provided by @types/react but is not globally available without importing the module—TypeScript module resolution requires explicit imports for namespace access in modern ESM setups used by Next.js. Next.js configures TypeScript with next-env.d.ts for its own types, but React types still need standard imports. No sources indicate global availability without import, and code examples consistently import first.
Citations:
- 1: https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops/
- 2: https://www.totaltypescript.com/react-component-props-type-helper
- 3: https://medium.com/@zong8498/mastering-react-componentprops-a-typescript-developers-guide-to-component-type-extraction-e52077be3872
- 4: https://nextjs.org/docs/basic-features/typescript
- 5: https://www.components.build/types
- 6: https://react-typescript-cheatsheet.netlify.app/docs/react-types/componentprops
- 7: https://react-typescript-cheatsheet.netlify.app/docs/advanced/types_react_api
- 8: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts
- 9: https://totaltypescript.com/concepts/react-componentprops-type-helper
- 10: https://react.dev/learn/typescript
🏁 Script executed:
# Check the file and its imports
cd kits/agentic/mockai/components/ui && cat -n collapsible.tsx | head -30Repository: Lamatic/AgentKit
Length of output: 1003
Import React namespace to use React.ComponentProps
Lines 7, 13, and 24 use React.ComponentProps without importing the React namespace. This will cause a TypeScript type-checking error: "Cannot find namespace 'React'".
Proposed fix
'use client'
+import type * as React from 'react'
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'📝 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.
| function Collapsible({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) { | |
| return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} /> | |
| } | |
| function CollapsibleTrigger({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) { | |
| return ( | |
| <CollapsiblePrimitive.CollapsibleTrigger | |
| data-slot="collapsible-trigger" | |
| {...props} | |
| /> | |
| ) | |
| } | |
| function CollapsibleContent({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) { | |
| 'use client' | |
| import type * as React from 'react' | |
| import * as CollapsiblePrimitive from '@radix-ui/react-collapsible' | |
| function Collapsible({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) { | |
| return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} /> | |
| } | |
| function CollapsibleTrigger({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) { | |
| return ( | |
| <CollapsiblePrimitive.CollapsibleTrigger | |
| data-slot="collapsible-trigger" | |
| {...props} | |
| /> | |
| ) | |
| } | |
| function CollapsibleContent({ | |
| ...props | |
| }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) { |
| "id": "triggerNode_1", | ||
| "nodeName": "API Request", | ||
| "responeType": "realtime", | ||
| "advance_schema": "{\n \"candidateResponses\": [\n {\n \"question\": \"string\",\n \"answers\": \"string\"\n }\n ]\n}" |
There was a problem hiding this comment.
The feedback prompt reads a field the trigger never exposes.
Line 12 defines candidateResponses, but Line 41 interpolates triggerNode_1.output.answers. One side of that contract is wrong, and as written the evaluator will receive undefined instead of the interview transcript.
🔧 Minimal fix
-{{triggerNode_1.output.answers}}
+{{triggerNode_1.output.candidateResponses}}Also applies to: 41-41
| import {config} from '../orchestrate.js' | ||
|
|
||
| if (!process.env.AGENTIC_QUESTION_FLOW_ID || !process.env.AGENTIC_FEEDBACK_FLOW_ID) { | ||
| console.warn( | ||
| "Warning: AGENTIC_QUESTION_FLOW_ID or AGENTIC_FEEDBACK_FLOW_ID environment variables are not set. Please ensure they are added in your deployment environment." | ||
| ); | ||
| } | ||
|
|
||
| if (!process.env.LAMATIC_API_URL || !process.env.LAMATIC_PROJECT_ID || !process.env.LAMATIC_API_KEY) { | ||
| console.warn( | ||
| "Warning: API Credentials environment variables are not set. Please ensure they are added in your deployment environment." | ||
| ); | ||
| } | ||
|
|
||
| export const lamaticClient = new Lamatic({ | ||
| endpoint: config.api.endpoint ?? "", | ||
| projectId: config.api.projectId ?? null, | ||
| apiKey: config.api.apiKey ?? "" | ||
| }); No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Check if the file exists and view its actual contents
cat -n kits/agentic/mockai/lib/lamatic-client.tsRepository: Lamatic/AgentKit
Length of output: 967
🏁 Script executed:
# Check the orchestrate.js file to understand the config import
cat -n kits/agentic/mockai/orchestrate.jsRepository: Lamatic/AgentKit
Length of output: 1742
🏁 Script executed:
# Find server action files in the agentic/mockai kit
find kits/agentic/mockai/actions -type f -name "*.ts" -o -name "*.js"Repository: Lamatic/AgentKit
Length of output: 102
🏁 Script executed:
# Check how flow IDs are used in server actions
find kits/agentic/mockai/actions -type f \( -name "*.ts" -o -name "*.js" \) -exec grep -l "FLOW_ID" {} \;Repository: Lamatic/AgentKit
Length of output: 42
🏁 Script executed:
# View the server action file to see how it handles flow IDs
cat -n kits/agentic/mockai/actions/orchestrate.tsRepository: Lamatic/AgentKit
Length of output: 4331
🏁 Script executed:
# Search for where flow IDs are actually used in the entire kit
rg "AGENTIC_QUESTION_FLOW_ID|AGENTIC_FEEDBACK_FLOW_ID" kits/agentic/mockai/ -A 2 -B 2Repository: Lamatic/AgentKit
Length of output: 1547
🏁 Script executed:
# Check if there are other lib files in this kit that might read env vars
find kits/agentic/mockai/lib -type f -name "*.ts" -o -name "*.js"Repository: Lamatic/AgentKit
Length of output: 134
🏁 Script executed:
# Check if there are other kits with lamatic-client.ts to see the correct pattern
find kits -name "lamatic-client.ts" -type fRepository: Lamatic/AgentKit
Length of output: 464
🏁 Script executed:
# Check if any other kit server actions read env vars directly for flow IDs
rg "process\.env\.[A-Z_]*FLOW" kits --type ts -A 2 -B 2 | head -50Repository: Lamatic/AgentKit
Length of output: 577
🏁 Script executed:
# Compare with another kit's lamatic-client.ts to see the correct pattern
cat -n kits/agentic/deep-search/lib/lamatic-client.tsRepository: Lamatic/AgentKit
Length of output: 981
🏁 Script executed:
# Check if that kit has an orchestrate.js and what it contains
cat -n kits/agentic/deep-search/orchestrate.js 2>/dev/null || echo "File not found"Repository: Lamatic/AgentKit
Length of output: 2710
🏁 Script executed:
# Check the server actions in deep-search to see how they handle flow IDs
cat -n kits/agentic/deep-search/actions/orchestrate.ts 2>/dev/null | head -50Repository: Lamatic/AgentKit
Length of output: 1449
Initialize the Lamatic SDK directly from environment variables, not via the config object.
This module validates flow IDs even though it only needs Lamatic API credentials. Reading LAMATIC_API_URL, LAMATIC_PROJECT_ID, and LAMATIC_API_KEY indirectly through config.api.* couples the SDK wrapper to orchestration concerns and creates a secondary configuration path. Flow ID validation belongs with server actions that execute the flows, not the Lamatic client wrapper. Initialize the client directly:
export const lamaticClient = new Lamatic({
endpoint: process.env.LAMATIC_API_URL ?? "",
projectId: process.env.LAMATIC_PROJECT_ID ?? null,
apiKey: process.env.LAMATIC_API_KEY ?? ""
});Move the flow ID validation to the server action that calls them.
| "@hookform/resolvers": "^3.10.0", | ||
| "@radix-ui/react-accordion": "1.2.2", | ||
| "@radix-ui/react-alert-dialog": "1.1.4", | ||
| "@radix-ui/react-aspect-ratio": "1.1.1", | ||
| "@radix-ui/react-avatar": "1.1.2", | ||
| "@radix-ui/react-checkbox": "1.1.3", | ||
| "@radix-ui/react-collapsible": "1.1.2", | ||
| "@radix-ui/react-context-menu": "2.2.4", | ||
| "@radix-ui/react-dialog": "1.1.4", | ||
| "@radix-ui/react-dropdown-menu": "2.1.4", | ||
| "@radix-ui/react-hover-card": "1.1.4", | ||
| "@radix-ui/react-label": "2.1.1", | ||
| "@radix-ui/react-menubar": "1.1.4", | ||
| "@radix-ui/react-navigation-menu": "1.2.3", | ||
| "@radix-ui/react-popover": "1.1.4", | ||
| "@radix-ui/react-progress": "1.1.1", | ||
| "@radix-ui/react-radio-group": "1.2.2", | ||
| "@radix-ui/react-scroll-area": "1.2.2", | ||
| "@radix-ui/react-select": "2.1.4", | ||
| "@radix-ui/react-separator": "1.1.1", | ||
| "@radix-ui/react-slider": "1.2.2", | ||
| "@radix-ui/react-slot": "1.1.1", | ||
| "@radix-ui/react-switch": "1.1.2", | ||
| "@radix-ui/react-tabs": "1.1.2", | ||
| "@radix-ui/react-toast": "1.2.4", | ||
| "@radix-ui/react-toggle": "1.1.1", | ||
| "@radix-ui/react-toggle-group": "1.1.1", | ||
| "@radix-ui/react-tooltip": "1.1.6", | ||
| "@vercel/analytics": "1.3.1", | ||
| "autoprefixer": "^10.4.20", | ||
| "class-variance-authority": "^0.7.1", | ||
| "clsx": "^2.1.1", | ||
| "cmdk": "1.0.4", | ||
| "date-fns": "4.1.0", | ||
| "embla-carousel-react": "8.5.1", | ||
| "input-otp": "1.4.1", | ||
| "lamatic": "latest", | ||
| "lucide-react": "^0.454.0", | ||
| "next": "^16.2.1", | ||
| "next-themes": "^0.4.6", | ||
| "react": "^19.2.4", | ||
| "react-day-picker": "9.8.0", | ||
| "react-dom": "^19.2.4", | ||
| "react-hook-form": "^7.60.0", | ||
| "react-markdown": "latest", | ||
| "react-resizable-panels": "^2.1.7", | ||
| "react-speech-recognition": "^4.0.1", | ||
| "recharts": "2.15.4", | ||
| "regenerator-runtime": "^0.14.1", | ||
| "sonner": "^1.7.4", | ||
| "tailwind-merge": "^2.5.5", | ||
| "tailwindcss-animate": "^1.0.7", | ||
| "vaul": "^0.9.9", | ||
| "zod": "3.25.76" | ||
| }, | ||
| "devDependencies": { | ||
| "@tailwindcss/postcss": "^4.1.9", | ||
| "@types/node": "^22", | ||
| "@types/react": "^19", | ||
| "@types/react-dom": "^19", | ||
| "@types/react-speech-recognition": "^3.9.6", | ||
| "postcss": "^8.5", | ||
| "tailwindcss": "^4.1.9", | ||
| "tw-animate-css": "1.3.3", | ||
| "typescript": "^5" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify non-pinned dependency specifiers in this kit package.json.
jq -r '
(.dependencies // {}) + (.devDependencies // {})
| to_entries[]
| select(.value | test("^(\\^|~|>|<|=|latest|next|workspace:|\\*)"))
| "\(.key): \(.value)"
' kits/agentic/mockai/package.jsonRepository: Lamatic/AgentKit
Length of output: 659
Pin all dependency versions exactly in this kit's package.json.
25 dependencies have non-pinned version specifiers (^ and latest), breaking reproducible builds: @hookform/resolvers, autoprefixer, class-variance-authority, clsx, lamatic, lucide-react, next, next-themes, react, react-dom, react-hook-form, react-markdown, react-resizable-panels, react-speech-recognition, regenerator-runtime, sonner, tailwind-merge, tailwindcss-animate, vaul, @tailwindcss/postcss, @types/node, @types/react, @types/react-dom, @types/react-speech-recognition, postcss, tailwindcss, typescript. Replace all caret ranges and latest tags with exact versions (e.g., "react": "19.2.4" instead of "react": "^19.2.4").
| # Agent Kit Generation by Lamatic.ai | ||
| <p align="center"> | ||
| <img src="https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExYnl0MGoxN203ZDczams4NzN6MGkxaXRham95N2NrejluZnU1N2NhMCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/TcZYytytvZBLODohJb/giphy.gif"/> | ||
| </p> | ||
|
|
||
| <p align="center"> | ||
| <a href="https://agent-kit-generation.vercel.app" target="_blank"> | ||
| <img src="https://img.shields.io/badge/Live%20Demo-black?style=for-the-badge" alt="Live Demo" /> | ||
| </a> | ||
| </p> | ||
|
|
||
|
|
||
| **Agent Kit Generation** is an AI-powered content generation system built with [Lamatic.ai](https://lamatic.ai). It uses intelligent workflows to generate text, images, and JSON content through a modern Next.js interface with markdown rendering support. | ||
|
|
||
| [](https://vercel.com/new/clone?repository-url=https://github.com/Lamatic/AgentKit&root-directory=kits/agentic/generation&env=AGENTIC_GENERATE_CONTENT,LAMATIC_API_URL,LAMATIC_PROJECT_ID,LAMATIC_API_KEY&envDescription=Your%20Lamatic%20Generation%20keys%20are%20required.&envLink=https://lamatic.ai/templates/agentkits/agentic/agent-kit-generation) |
There was a problem hiding this comment.
Rewrite this README for Mockai instead of the generation sample.
Lines 1-15 still brand this as “Agent Kit Generation,” and Line 15’s deploy button points to kits/agentic/generation. The repo-structure section also describes a generation UI rather than the mock interviewer in this PR. As per coding guidelines, every kit must have a README.md that documents setup, environment variables, and usage.
Also applies to: 80-97
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 3-3: Images should have alternate text (alt text)
(MD045, no-alt-text)
| Create `.env.local` with: | ||
|
|
||
| ```bash | ||
| # Lamatic | ||
| AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID" | ||
| LAMATIC_API_URL = "LAMATIC_API_URL" | ||
| LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID" | ||
| LAMATIC_API_KEY = "LAMATIC_API_KEY" | ||
| ``` |
There was a problem hiding this comment.
Document the flow IDs this kit actually requires.
The runtime checks AGENTIC_QUESTION_FLOW_ID and AGENTIC_FEEDBACK_FLOW_ID, but this snippet only tells users to set AGENTIC_GENERATE_CONTENT. Following the current instructions leaves the app without the two flow IDs it needs.
📝 Suggested doc fix
-AGENTIC_GENERATE_CONTENT = "AGENTIC_GENERATE_CONTENT Flow ID"
-LAMATIC_API_URL = "LAMATIC_API_URL"
-LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID"
-LAMATIC_API_KEY = "LAMATIC_API_KEY"
+AGENTIC_QUESTION_FLOW_ID="Question Flow ID"
+AGENTIC_FEEDBACK_FLOW_ID="Feedback Flow ID"
+LAMATIC_API_URL="LAMATIC_API_URL"
+LAMATIC_PROJECT_ID="LAMATIC_PROJECT_ID"
+LAMATIC_API_KEY="LAMATIC_API_KEY"As per coding guidelines, every kit must have a README.md that documents setup, environment variables, and usage.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
kits/agentic/mockai/app/page.tsx (1)
374-375: Remove unusedvisualizerScalecomputation.
visualizerScaleis computed on line 375 but never used in the rendered JSX. This appears to be leftover code from when the audio visualizer UI was present.🧹 Proposed fix
const isLastQuestion = currentQuestionIndex === questions.length - 1 const displayAnswer = currentAnswer + (interimResult ? (currentAnswer.endsWith(" ") ? "" : " ") + interimResult : "") - - // Calculate a dynamic scale for the visualizer pulse (1 to 1.5 roughly) - const visualizerScale = 1 + Math.min(volume / 50, 0.5)
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8cddd5c6-76ee-4267-9402-e9c24968e6a0
📒 Files selected for processing (1)
kits/agentic/mockai/app/page.tsx
What This Kit Does
Mockai is an AI-powered mock interviewer that helps users practice for tailored job interviews. It conducts dynamic, interactive interviews using real-time speech-to-text and provides instant, AI-generated feedback on your performance.
Providers & Prerequisites
How to Run Locally
cd kits/agentic/mockainpm installcp .env.example .envand fill in valuesnpm run devLive Preview
https://mockai-mscr.vercel.app/
Lamatic Flow
9f64b62e-6e02-4de5-afa9-677970913e007a20f813-2e7a-4597-804f-427b9b702d88Mockai: AI-Powered Mock Interviewer