feat: Add Startup-Research AgentKit [agentkit-challenge]#93
feat: Add Startup-Research AgentKit [agentkit-challenge]#93cyber-turtle wants to merge 20 commits intoLamatic:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new "Founder Lens" agent kit: a Next.js app with UI components, Lamatic client and server actions, plus two Lamatic workflows (analyze and chat) implementing multi-query web research, contrarian VC analysis, vector indexing, RAG retrieval, and semantic memory integration. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI as Founder Lens UI
participant Server as Server Actions
participant Lamatic as Lamatic Workflows
participant Exa as Exa.ai
participant LLM as LLM Services
participant Weaviate as Vector DB
participant Memory as Semantic Memory
User->>UI: Submit startup idea
UI->>Server: analyzeIdea(idea, userId, sessionId)
Server->>Lamatic: Trigger Analyze Flow
Lamatic->>LLM: Decompose idea -> generate queries
Lamatic->>Exa: Run multiple parallel web searches
Exa-->>Lamatic: Return search results
Lamatic->>LLM: Contrarian analysis + Final synthesis
LLM-->>Lamatic: Return Brief JSON
Lamatic->>Weaviate: Vectorize & index facts
Lamatic->>Memory: Store analysis record
Lamatic-->>Server: Return brief + decomposition
Server-->>UI: Return success & brief
UI->>User: Display brief
User->>UI: Ask question
UI->>Server: chatWithBrief(message, userId, sessionId)
Server->>Lamatic: Trigger Chat Flow
Lamatic->>Memory: Retrieve conversation history
Lamatic->>Weaviate: RAG retrieve brief sections
Lamatic->>LLM: Generate answer using brief + history
Lamatic->>Memory: Persist exchange
Lamatic-->>Server: Return answer
Server-->>UI: Deliver answer
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 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: 7
🧹 Nitpick comments (9)
kits/agentic/founder-lens/.env.example (1)
1-5: Minor style improvements for.env.example.Static analysis flagged a few style issues:
- Quote characters around placeholder values may be parsed literally by some tools.
- Missing trailing newline.
These are minor but worth addressing for consistency.
✨ Proposed fix
-FOUNDER_LENS_ANALYZE_FLOW_ID="YOUR_ANALYZE_FLOW_ID" -FOUNDER_LENS_CHAT_FLOW_ID="YOUR_CHAT_FLOW_ID" -LAMATIC_API_URL="YOUR_API_ENDPOINT" -LAMATIC_PROJECT_ID="YOUR_PROJECT_ID" -LAMATIC_API_KEY="YOUR_API_KEY" +FOUNDER_LENS_ANALYZE_FLOW_ID= +FOUNDER_LENS_CHAT_FLOW_ID= +LAMATIC_API_KEY= +LAMATIC_API_URL= +LAMATIC_PROJECT_ID=kits/agentic/founder-lens/orchestrate.js (1)
1-6: Consider adding validation for required environment variables.The config silently defaults to empty strings when environment variables are missing. This allows the app to start but will cause confusing runtime failures when flows are executed. Fail-fast validation would improve developer experience.
💡 Example validation approach
const requiredEnvVars = [ 'LAMATIC_API_URL', 'LAMATIC_PROJECT_ID', 'LAMATIC_API_KEY', 'FOUNDER_LENS_ANALYZE_FLOW_ID', 'FOUNDER_LENS_CHAT_FLOW_ID', ]; const missing = requiredEnvVars.filter((key) => !process.env[key]); if (missing.length > 0) { console.warn(`[founder-lens] Missing environment variables: ${missing.join(', ')}`); } export const config = { // ... rest of config };kits/agentic/founder-lens/app/layout.tsx (1)
1-2: Consider usingnext/fontfor optimized font loading.The
globals.cssuses@import url()to load Google Sans from googleapis.com, which bypasses Next.js font optimization (automatic self-hosting, subsetting, and preloading). For better performance, consider usingnext/font/google:import { Inter } from "next/font/google"; // or for Google Sans (if available), use a similar approach const font = Inter({ subsets: ["latin"] }); // Then apply: <body className={font.className}>This eliminates the external network request and improves Core Web Vitals.
kits/agentic/founder-lens/package.json (1)
15-15: Pinlamaticto a specific version for reproducible builds.Using
"latest"can cause inconsistent builds across environments and may introduce breaking changes unexpectedly. Consider pinning to a specific version (e.g.,"lamatic": "^0.3.2").kits/agentic/founder-lens/components/ChatInterface.tsx (1)
101-109: Consider adding disabled styling to suggested question buttons.The suggested question buttons check
!loadingbefore callingonSendMessage, but they don't visually indicate the disabled state. Users may not realize the buttons are inactive during loading.♻️ Proposed improvement
{SUGGESTED_QUESTIONS.map((q, i) => ( <button key={i} onClick={() => !loading && onSendMessage(q)} - className="w-full text-left p-3.5 rounded-xl text-[12px] font-medium text-white/70 bg-white/5 border border-white/5 hover:bg-white/10 hover:text-white transition-all duration-300" + disabled={loading} + className="w-full text-left p-3.5 rounded-xl text-[12px] font-medium text-white/70 bg-white/5 border border-white/5 hover:bg-white/10 hover:text-white transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-white/5 disabled:hover:text-white/70" > {q} </button> ))}kits/agentic/founder-lens/components/AuroraBackground.tsx (1)
7-21:mousePositionstate is set but never used.The
mousePositionstate is updated on every mouse move but is never consumed in the render output. This causes unnecessary re-renders on every mouse movement. If the aurora gradient tracking was intended but not implemented, consider removing this dead code or implementing the intended feature.♻️ Proposed fix - remove unused state and effect
export function AuroraBackground({ children }: { children: React.ReactNode }) { const canvasRef = useRef<HTMLCanvasElement>(null); - const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 }); - - // Handle the fluid aurora gradient tracking - useEffect(() => { - const handleMouseMove = (e: MouseEvent) => { - const x = (e.clientX / window.innerWidth) * 100; - const y = (e.clientY / window.innerHeight) * 100; - const limitedX = 20 + (x * 0.6); - const limitedY = 20 + (y * 0.6); - setMousePosition({ x: limitedX, y: limitedY }); - }; - - window.addEventListener("mousemove", handleMouseMove); - return () => window.removeEventListener("mousemove", handleMouseMove); - }, []);kits/agentic/founder-lens/actions/orchestrate.ts (1)
6-21: Consider basic input validation for server action parameters.The server action accepts user-provided strings (
idea,userId,sessionId) without validation. While the Lamatic SDK likely handles this, adding basic checks would provide better error messages and prevent unnecessary API calls.♻️ Optional: Add input validation
export async function analyzeIdea( idea: string, userId: string, sessionId: string ): Promise<{ success: boolean; brief?: string; decomposition?: string; error?: string }> { try { + if (!idea?.trim()) { + return { success: false, error: "Idea cannot be empty" }; + } + if (!userId || !sessionId) { + return { success: false, error: "Missing user or session identifier" }; + } const flow = config.flows.analyze;kits/agentic/founder-lens/app/page.tsx (1)
128-136:localStorage.removeItemshould be wrapped in try/catch for consistency.The persist effect wraps
localStorage.setItemin try/catch, buthandleResetcallslocalStorage.removeItemwithout error handling. This could throw in storage-restricted environments.♻️ Proposed fix
const handleReset = () => { setAppState("idle"); setBrief(""); setDecomposition(""); setMessages([]); setError(""); setCurrentIdea(""); - localStorage.removeItem("founder-lens-session"); + try { + localStorage.removeItem("founder-lens-session"); + } catch { + // localStorage unavailable — gracefully ignore + } };kits/agentic/founder-lens/flows/analyze/config.json (1)
140-170: No retry configuration for external Exa.ai API calls.All 9 Exa.ai search nodes have
"retries": "0", meaning any transient API failure will fail the entire analysis flow. Given that 9 parallel external API calls are made, the probability of at least one failing is non-trivial.Consider:
- Setting
retriesto 1-2 with appropriate delay for resilience- Adding error handling in the consolidation node to gracefully handle partial failures (empty results from some searches)
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3a4191e1-4d05-487d-af1f-faef6d465d20
⛔ Files ignored due to path filters (3)
kits/agentic/founder-lens/app/icon.svgis excluded by!**/*.svgkits/agentic/founder-lens/package-lock.jsonis excluded by!**/package-lock.jsonkits/agentic/founder-lens/public/ui-notification.mp3is excluded by!**/*.mp3
📒 Files selected for processing (31)
kits/agentic/founder-lens/.env.examplekits/agentic/founder-lens/.gitignorekits/agentic/founder-lens/README.mdkits/agentic/founder-lens/actions/orchestrate.tskits/agentic/founder-lens/app/globals.csskits/agentic/founder-lens/app/layout.tsxkits/agentic/founder-lens/app/page.tsxkits/agentic/founder-lens/components/AuroraBackground.tsxkits/agentic/founder-lens/components/BriefDisplay.tsxkits/agentic/founder-lens/components/ChatInterface.tsxkits/agentic/founder-lens/components/Icons.tsxkits/agentic/founder-lens/components/IdeaForm.tsxkits/agentic/founder-lens/components/PhaseTracker.tsxkits/agentic/founder-lens/config.jsonkits/agentic/founder-lens/flows/analyze/README.mdkits/agentic/founder-lens/flows/analyze/config.jsonkits/agentic/founder-lens/flows/analyze/inputs.jsonkits/agentic/founder-lens/flows/analyze/meta.jsonkits/agentic/founder-lens/flows/chat/README.mdkits/agentic/founder-lens/flows/chat/config.jsonkits/agentic/founder-lens/flows/chat/inputs.jsonkits/agentic/founder-lens/flows/chat/meta.jsonkits/agentic/founder-lens/lib/lamatic-client.tskits/agentic/founder-lens/lib/utils.tskits/agentic/founder-lens/next-env.d.tskits/agentic/founder-lens/next.config.jskits/agentic/founder-lens/orchestrate.jskits/agentic/founder-lens/package.jsonkits/agentic/founder-lens/postcss.config.jskits/agentic/founder-lens/tailwind.config.jskits/agentic/founder-lens/tsconfig.json
…ut + retry, BriefDisplay schema fix, model quality disclaimer
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
kits/agentic/founder-lens/components/ChatInterface.tsx (2)
29-49: Markdown renderer doesn't handle edge cases properly.The
renderMarkdownfunction has a few issues:
- Lines 33-38: The order of header checks is wrong —
##is checked before#, but if a line starts with##, it will never match#. This works by accident but is confusing. More importantly, a line like###(h3) will fall through to the bold/paragraph logic.- Line 40: The bold regex
(\*\*[^*]+\*\*)doesn't handle nested asterisks or empty bold (****).- Empty lines become empty
<p>tags with margin, creating inconsistent spacing.♻️ Suggested improvement for edge cases
function renderMarkdown(text: string): React.ReactNode { const lines = text.split("\n"); return lines.map((line, i) => { + // Skip empty lines + if (!line.trim()) { + return <br key={i} />; + } // Headers - if (line.startsWith("## ")) { - return <h2 key={i} className="text-[14px] font-medium mt-5 mb-2 text-white">{line.slice(3)}</h2>; - } if (line.startsWith("# ")) { return <h1 key={i} className="text-[16px] font-medium mt-5 mb-2 text-white">{line.slice(2)}</h1>; } + if (line.startsWith("## ")) { + return <h2 key={i} className="text-[14px] font-medium mt-5 mb-2 text-white">{line.slice(3)}</h2>; + }
168-175: Consider usingtype="submit"for the send button.The button uses
type="button"and manually callshandleSubmit(), but it's inside a<form>. Usingtype="submit"would be more semantic and consistent with the form's existingonSubmithandler.♻️ Proposed change
<button - type="button" - onClick={() => handleSubmit()} + type="submit" disabled={!input.trim() || loading}kits/agentic/founder-lens/actions/orchestrate.ts (2)
15-20:withTimeoutcreates a timer that leaks if the promise resolves first.The timeout is never cleared when the original promise wins the race. While this won't cause functional issues for short-lived server actions, it's a resource leak pattern.
♻️ Proposed fix with cleanup
async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, errorMessage: string): Promise<T> { + let timeoutId: NodeJS.Timeout; const timeoutPromise = new Promise<never>((_, reject) => { - setTimeout(() => reject(new Error(errorMessage)), timeoutMs); + timeoutId = setTimeout(() => reject(new Error(errorMessage)), timeoutMs); }); - return Promise.race([promise, timeoutPromise]); + return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timeoutId)); }
39-47: Define explicit response type and pin Lamatic SDK version to prevent fragility from type loss and unexpected breaking changes.The
resData: anytyping bypasses TypeScript protections, and the unpinned"lamatic": "latest"dependency means the assumed response shape (result.brief,result.decomposition) could silently break on SDK updates. Consider defining an explicit response interface and pinning the SDK to a specific version.♻️ Define an explicit response type
+interface AnalyzeFlowResponse { + result?: { + brief?: string; + decomposition?: string; + }; +} - const resData: any = await withTimeout( + const resData = await withTimeout<AnalyzeFlowResponse>( lamaticClient.executeFlow(flow.workflowId, { idea, userId, sessionId }),Also consider pinning the Lamatic SDK version in
package.jsonfrom"latest"to a specific version (e.g.,"^0.x.x") to prevent unexpected breaking changes.kits/agentic/founder-lens/app/page.tsx (1)
132-140:handleResetshould wrap localStorage access in try-catch for consistency.The persist effect (lines 78-79) gracefully handles localStorage errors, but
handleResetdoesn't. While unlikely to fail, this is inconsistent.♻️ Proposed fix
const handleReset = () => { setAppState("idle"); setBrief(""); setDecomposition(""); setMessages([]); setError(""); setCurrentIdea(""); - localStorage.removeItem("founder-lens-session"); + try { + localStorage.removeItem("founder-lens-session"); + } catch { + // localStorage unavailable — gracefully ignore + } };
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 15e59be5-221e-4dc3-9809-3958892d38c2
📒 Files selected for processing (7)
kits/agentic/founder-lens/actions/orchestrate.tskits/agentic/founder-lens/app/page.tsxkits/agentic/founder-lens/components/BriefDisplay.tsxkits/agentic/founder-lens/components/ChatInterface.tsxkits/agentic/founder-lens/components/IdeaForm.tsxkits/agentic/founder-lens/components/PhaseTracker.tsxkits/agentic/founder-lens/lib/utils.ts
✅ Files skipped from review due to trivial changes (1)
- kits/agentic/founder-lens/lib/utils.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- kits/agentic/founder-lens/components/PhaseTracker.tsx
- kits/agentic/founder-lens/components/IdeaForm.tsx
- kits/agentic/founder-lens/components/BriefDisplay.tsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 3
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3a623deb-58cd-4c67-a70a-ad579f0976d2
📒 Files selected for processing (1)
kits/agentic/founder-lens/components/IdeaForm.tsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This reverts commit 86bd0cc.
… usual' UI message
What This Kit Does
Founder Lens is a 7-phase autonomous startup research agent designed to save non-technical founders weeks of manual research.
Users submit a startup idea, and the agent fires 9 highly targeted parallel Exa.ai web searches to gather TAM/SAM/SOM data, Crunchbase VC trends, direct competitors, failed startup postmortems, and verbatim customer complaints from Reddit and G2. A Contrarian VC persona then analyzes the data to find the fatal flaw.
The brief is synthesized, stored in Lamatic Semantic Memory (via Weaviate vector DB), and retrieved via RAG, allowing the founder to interactively chat with their analysis.
Providers & Prerequisites
x-api-keyfield (as a key-value pair).How to Run Locally
cd kits/agentic/founder-lensnpm installcp .env.example .env.localand fill in the 5 Lamatic credential valuesnpm run devLive Preview
Live App: https://founder-lens-agentkit.vercel.app/
Lamatic Flow
Analyze Flow ID:
54151a7e-99eb-4150-91eb-38f21cfeb8f8Chat Flow ID:
0b0a3ee0-757d-4e85-a606-9ddb51fb0d40npm run dev.env.examplehas no secrets, only placeholdersREADME.mddocuments setup and usagekits/<category>/<kit-name>/config.jsonis present and validflows/folder