Feat/luminaweb agent#221
Conversation
Create src/agents/luminaweb/ with AgentPlan/ResearchArtifact/ReviewArtifact types, JSON extraction utilities, and ported luminaweb prompts (planner/repo-research/exa-research/review/enhance) adapted for zapdev. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add runPlanner (JSON plan via kimi-k2.5:nitro) and runEnhancer, plus three workers adapted for zapdev's E2B-first model: runRepoResearch accepts a projectFiles map (decoupled from Convex), runExaResearch does parallel web search via Exa, and runReview audits the generated file set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add context-builder that layers research + plan into the system prompt, plus a two-step orchestrator API: runPreflight (enhance → plan → parallel research → enriched prompt) and runPostReview (skipped for simple tasks). Export a clean public API from the luminaweb index. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace bespoke runPlanningAgent/runResearchAgent with runPreflight (enhance → plan → parallel repo/exa research → enriched system prompt) and runPostReview (skipped for simple tasks). Use plan.complexity to drive the E2B coding-agent's maxIter budget. Review findings are appended to the final summary when quality='critical_issues'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Delete code-agent.ts, subagent.ts, brave-tools.ts, rate-limit.ts,
tools.ts, index.ts and the unused prompts/{planning,research}.ts.
Their responsibilities are now owned by the luminaweb orchestrator.
Update AGENTS.md to reflect the new layout.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New coverage for the pure-logic surface of the luminaweb port: - utils: extractJSONFromMarkdown, safeParseAIJSON, truncate - prompts: isUIGenerationRequest keyword detection - context-builder: plan + research layering and the exa-skip sentinel - orchestrator: appendReviewNotes gating by quality - planner: runPlanner JSON parsing, fallback paths, and runEnhancer gating Also removes glm-subagent-system.test.ts and gateway-fallback.test.ts, which tested modules (subagent.ts, rate-limit.ts) that were deleted in phase 6. Full suite: 14 passed, 188 tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AgentKit's Message union covers tool-call/tool-output shapes that do not have a .content field. Filter by type:"text" before reading .content to satisfy the compiler. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vidoc Security ReportNote Currently processing new changes in this PR. This may take a few minutes, please wait... |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (11)
📝 WalkthroughWalkthroughReplaces legacy agent/subagent tooling and many documentation files with a new "zapdev" orchestration pipeline. Removes Brave search tools, streaming/event types, rate-limit and subagent modules; adds zapdev planner/orchestrator/context-builder, types, prompts, utils, research/review workers, tests, and a new Convex query. Updates AGENTS.md and dependency version. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Enhancer as Enhancer
participant Planner as Planner
participant Repo as RepoResearch
participant Exa as ExaResearch
participant Builder as ContextBuilder
participant CodeAgent as Code Generation
participant Reviewer as Review Worker
User->>Enhancer: userMessage
alt isUIGenerationRequest
Enhancer-->>Planner: enhancedPrompt
else
Enhancer-->>Planner: userMessage
end
Planner->>Planner: generateText -> parse AgentPlan
Planner-->>User: AgentPlan
alt plan.needsResearch
par Repo research
Planner->>Repo: focusAreas + projectFiles
Repo-->>Planner: ResearchArtifact
and Exa research
Planner->>Exa: searchQueries
Exa-->>Planner: ResearchArtifact
end
else
Planner-->>Planner: repoResearch=null, exaResearch=null
end
Planner->>Builder: basePrompt + plan + research
Builder-->>CodeAgent: enrichedSystemPrompt
CodeAgent->>CodeAgent: generate implementationSummary
alt plan.complexity !== "simple"
CodeAgent->>Reviewer: implementationSummary + files
Reviewer-->>CodeAgent: ReviewArtifact
else
Reviewer-->>CodeAgent: null
end
CodeAgent-->>User: Final output (+ review notes)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 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: 12
🧹 Nitpick comments (3)
src/agents/luminaweb/index.ts (1)
2-4: Keep worker runners off the public Luminaweb barrel.Exporting
runRepoResearch,runExaResearch, andrunReviewfrom the consolidated entrypoint makes the forbidden UI-route usage path easy to import. Prefer exposing orchestration APIs here and importing workers by direct internal paths where needed.♻️ Proposed public surface trim
export { runPlanner, runEnhancer, FALLBACK_PLAN } from "./planner"; -export { runRepoResearch } from "./workers/repo-research"; -export { runExaResearch } from "./workers/exa-research"; -export { runReview } from "./workers/review"; export { buildEnrichedSystemPrompt } from "./context-builder";Based on learnings, Never call workers directly from UI routes; they belong to Inngest functions or downstream server actions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/luminaweb/index.ts` around lines 2 - 4, Remove the public exports of runRepoResearch, runExaResearch, and runReview from the module barrel so UI code cannot import workers via the consolidated entrypoint; instead, keep only orchestration-level APIs here and update any callers to import the worker implementations directly from their internal worker modules (e.g., "./workers/repo-research", "./workers/exa-research", "./workers/review") or, even better, call them only from Inngest/server-action orchestration layers—delete the three export lines (export { runRepoResearch }, export { runExaResearch }, export { runReview }) and ensure callers reference the worker files by their internal paths or use the exposed orchestration functions instead.src/agents/luminaweb/types.ts (2)
40-40: Consider more descriptive typing for thefilesRecord.The
files: Record<string, string>type is generic and doesn't convey what the keys and values represent. Based on the context, this appears to be a mapping of file paths to file contents. Adding a type alias or JSDoc would improve clarity.♻️ Proposed refactor options
Option 1: Type alias
+/** Maps file paths to their contents */ +export type FileContents = Record<string, string>; + export interface ReviewInput extends WorkerInput { implementationSummary: string; - files: Record<string, string>; + files: FileContents; }Option 2: JSDoc only
export interface ReviewInput extends WorkerInput { implementationSummary: string; + /** Maps file paths to their contents */ files: Record<string, string>; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/luminaweb/types.ts` at line 40, The current property files: Record<string, string> in src/agents/luminaweb/types.ts is too generic; replace it with a descriptive type alias (e.g., FileMap or FileContents) that documents that keys are file paths and values are file contents, then update the property to use that alias (referencing the files property and the new FileMap/FileContents type) or, if you prefer minimal change, add a JSDoc comment above files explaining "key = file path, value = file contents"; ensure all references to files in this module use the new alias or keep the JSDoc so the intent is clear.
14-15: Consider extracting inline types for better maintainability.The inline object types for
relevantFilesandcitationscould be extracted as named interfaces to improve reusability and maintainability, especially if these shapes are referenced elsewhere in the codebase.♻️ Proposed refactor to extract inline types
+export interface RelevantFile { + name: string; + snippet: string; +} + +export interface Citation { + url: string; + title: string; + content: string; +} + export interface ResearchArtifact { summary: string; - relevantFiles?: { name: string; snippet: string }[]; - citations?: { url: string; title: string; content: string }[]; + relevantFiles?: RelevantFile[]; + citations?: Citation[]; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/luminaweb/types.ts` around lines 14 - 15, The inline object types for the optional properties relevantFiles and citations should be pulled out as named interfaces to improve reuse and clarity: create interfaces (e.g., RelevantFile { name: string; snippet: string } and Citation { url: string; title: string; content: string }) in the same module and replace the inline annotations with relevantFiles?: RelevantFile[] and citations?: Citation[] in the exported type declarations so callers can import/reuse those shapes elsewhere (update any references to these inline shapes to use the new interface names).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/agents/luminaweb/planner.ts`:
- Around line 34-44: The parsed AgentPlan from safeParseAIJSON is untrusted and
may have wrong types (e.g., "false" string, "easy" text, or non-array
focusAreas) so normalize and validate fields before returning: in the return
path that merges with FALLBACK_PLAN, coerce needsResearch to a boolean (e.g.,
treat "true"/true/1 as true else false), clamp complexity to the allowed enum
values (normalize strings to one of 'simple'|'moderate'|'complex' and default to
FALLBACK_PLAN.complexity if unknown), ensure searchQueries, focusAreas, steps,
potentialIssues, and filesToModify are arrays (replace non-arrays with []), and
ensure any other plan gates consult the normalized needsResearch and complexity
values (e.g., research stage only if normalized needsResearch === true; review
stage only if normalized complexity !== 'simple'). Use the parsed variable,
AgentPlan shape, and FALLBACK_PLAN when implementing these normalizations.
In `@src/agents/luminaweb/prompts.ts`:
- Around line 54-67: The current isUIGenerationRequest uses broad substrings in
UI_KEYWORDS, causing false positives (e.g., "app", "application", "component",
"form", "login", "site"); tighten detection by replacing substring matching with
stricter checks: remove or narrow ambiguous tokens from UI_KEYWORDS, use
word-boundary / whole-word matching (e.g., regex with \b) and/or require either
(a) a UI-specific keyword plus a design qualifier
("design","layout","ui","ux","figma","tailwind") or (b) two or more UI keywords
present; update the isUIGenerationRequest function to perform tokenized/regex
matching against UI_KEYWORDS_STRICT and the design qualifier set instead of
simple lower.includes checks to avoid routing backend prompts through the
enhancer.
- Around line 13-16: The mapping that ties needsResearch to complexity must be
removed so Planner sets both independently: update the Complexity definition
(the object/enum named Complexity) and the planner code that currently derives
needsResearch from complexity to instead accept/compute a separate
plan.needsResearch flag; ensure the preflight/research invocation checks only
plan.needsResearch before running research, and the review step checks
plan.complexity !== 'simple' to trigger review. Locate and modify the places
referencing Complexity and plan.needsResearch/plan.complexity in this file
(prompts.ts) and any Planner method that constructs the plan so complexity and
needsResearch are decided independently.
- Around line 45-52: The ENHANCE_SYSTEM_PROMPT currently hardcodes "React
19.2.4" and runEnhancer only accepts userMessage, causing framework bias; change
runEnhancer to accept an additional framework/context argument (derived from
projectFiles or contextSummary) and update all callers to pass that inferred
framework, then parameterize ENHANCE_SYSTEM_PROMPT (e.g., include a {framework}
placeholder) so the prompt inserts the target framework dynamically instead of
"React 19.2.4", while preserving the RULES block (including the stable-version
constraint) and updating any references to runEnhancer and ENHANCE_SYSTEM_PROMPT
to use the new signature and placeholder.
In `@src/agents/luminaweb/utils.ts`:
- Around line 1-17: The regex MARKDOWN_JSON_REGEX in extractJSONFromMarkdown
only matches unlabeled or lowercase "json" fences and misses labeled/uppercase
fences; replace it with a more general MARKDOWN_CODE_FENCE_REGEX (e.g. /```[
\t]*([^\r\n`]*)\r?\n([\s\S]*?)```/g), then change the matches handling to map
each match to { language: match[1]?.trim().toLowerCase(), content:
match[2]?.trim() }, iterate over these objects and return the first content that
starts with "{" or "["; finally update the fallback to return
matches[0]?.content ?? text.trim() and remove reliance on match[1] indexing so
labeled/uppercase fences like ```JSON are correctly recognized by
extractJSONFromMarkdown.
In `@src/agents/luminaweb/workers/exa-research.ts`:
- Around line 26-42: The current error logging in the for loop that iterates
over searchQueries (in the block using exa.searchAndContents and pushing to
allResults) prints raw query text which may leak sensitive planner-generated
content; change the catch handler to log only the query index (e.g., use the
loop index from searchQueries.slice(0, 3) or enumerate searchQueries) and/or a
redacted placeholder instead of the full query string when logging errors from
exa.searchAndContents, while keeping the existing error object for debugging
(e.g., log `[EXA] search failed for query #${index}` and the error).
- Around line 67-76: The code returns parsed.citations without ensuring it is an
array, which can break downstream rendering; in the block using
safeParseAIJSON<ResearchArtifact> and variables parsed and allResults, validate
that parsed.citations is an actual array (Array.isArray) and that each item
matches the expected citation shape before returning; if validation fails, fall
back to constructing citations from allResults (url, title, content) so the
returned object always conforms to the ResearchArtifact/AgentPlan artifact shape
expected by context-builder.
In `@src/agents/luminaweb/workers/repo-research.ts`:
- Around line 47-52: The parsed artifact from safeParseAIJSON<ResearchArtifact>
may contain relevantFiles as a string or object which will break callers
expecting an array; in the repo-research.ts return path normalize and validate
relevantFiles: if parsed.relevantFiles is an Array, filter to the expected item
type (e.g., strings or objects matching ResearchArtifact file shape), if it is a
string attempt to JSON.parse it to an array (fall back to wrapping the string as
a single-item array), if it is an object wrap it into a single-item array or
extract the expected file entries, and otherwise default to an empty array;
return summary and this normalized relevantFiles so callers (like
context-builder) can safely call .map.
- Around line 21-25: The code currently uses Object.entries(projectFiles) then
maps to fileTree and keySnippets, which can leak hidden or sensitive files;
before building fileTree and keySnippets, filter fileEntries by excluding path
segments like leading dotfiles (names starting with '.'), '.git',
'node_modules', 'vendor', any env/config filenames (e.g., '.env', 'env',
'config', 'credentials'), and other sensitive directories; apply that same
filtered list to both fileTree and keySnippets (when slicing for the top 8
snippets) so only allowed files are included; update the code around
projectFiles/fileEntries/fileTree/keySnippets (and keep MAX_SNIPPET usage) to
operate on the filtered entries.
In `@src/agents/luminaweb/workers/review.ts`:
- Around line 46-52: The parsed ReviewArtifact from
safeParseAIJSON<ReviewArtifact>(text) may return issues or suggestions as a
string or object; normalize both before returning so callers like
appendReviewNotes can safely call .map. Update the return branch that reads
parsed?.quality to coerce parsed.issues and parsed.suggestions into arrays: if
null/undefined => [], if Array => use as-is, if single string/object => wrap in
[value], and optionally filter out non-truthy entries; keep quality as
parsed.quality and preserve types declared by ReviewArtifact to ensure the
returned artifact matches the expected AgentPlan shape.
- Around line 19-22: The filter for sourceEntries currently only rejects names
that start with "." but allows nested hidden path segments (e.g.,
"src/.config/file") to pass; update the predicate used when filtering
Object.entries(files) so it rejects any path that contains a path segment
starting with "." or contains "node_modules" anywhere: split or normalize the
file path (use name.split(/[/\\]/) or similar) and return false if any
segment.startsWith(".") or segment === "node_modules", otherwise keep the
existing REVIEWABLE_EXTENSIONS.some(name.endsWith(ext)) check; reference the
sourceEntries variable, the files input, and REVIEWABLE_EXTENSIONS when applying
this change.
In `@src/inngest/functions.ts`:
- Around line 463-472: The current code always calls runPostReview and appends
its result via appendReviewNotes even for simple plans; change the flow in the
function handling e2bResult (where runPostReview and appendReviewNotes are
invoked) to only call runPostReview when plan.complexity !== 'simple' (and
ensure research logic still only triggers when plan.needsResearch === true),
i.e., guard the runPostReview(...) call with a conditional based on
plan.complexity and only call appendReviewNotes(e2bResult.summary, review) when
a review was actually produced.
---
Nitpick comments:
In `@src/agents/luminaweb/index.ts`:
- Around line 2-4: Remove the public exports of runRepoResearch, runExaResearch,
and runReview from the module barrel so UI code cannot import workers via the
consolidated entrypoint; instead, keep only orchestration-level APIs here and
update any callers to import the worker implementations directly from their
internal worker modules (e.g., "./workers/repo-research",
"./workers/exa-research", "./workers/review") or, even better, call them only
from Inngest/server-action orchestration layers—delete the three export lines
(export { runRepoResearch }, export { runExaResearch }, export { runReview })
and ensure callers reference the worker files by their internal paths or use the
exposed orchestration functions instead.
In `@src/agents/luminaweb/types.ts`:
- Line 40: The current property files: Record<string, string> in
src/agents/luminaweb/types.ts is too generic; replace it with a descriptive type
alias (e.g., FileMap or FileContents) that documents that keys are file paths
and values are file contents, then update the property to use that alias
(referencing the files property and the new FileMap/FileContents type) or, if
you prefer minimal change, add a JSDoc comment above files explaining "key =
file path, value = file contents"; ensure all references to files in this module
use the new alias or keep the JSDoc so the intent is clear.
- Around line 14-15: The inline object types for the optional properties
relevantFiles and citations should be pulled out as named interfaces to improve
reuse and clarity: create interfaces (e.g., RelevantFile { name: string;
snippet: string } and Citation { url: string; title: string; content: string })
in the same module and replace the inline annotations with relevantFiles?:
RelevantFile[] and citations?: Citation[] in the exported type declarations so
callers can import/reuse those shapes elsewhere (update any references to these
inline shapes to use the new interface names).
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 425fe8ef-91fb-46f2-8eef-11d5c1c2a9ea
📒 Files selected for processing (27)
src/agents/AGENTS.mdsrc/agents/brave-tools.tssrc/agents/code-agent.tssrc/agents/index.tssrc/agents/luminaweb/context-builder.tssrc/agents/luminaweb/index.tssrc/agents/luminaweb/orchestrator.tssrc/agents/luminaweb/planner.tssrc/agents/luminaweb/prompts.tssrc/agents/luminaweb/types.tssrc/agents/luminaweb/utils.tssrc/agents/luminaweb/workers/exa-research.tssrc/agents/luminaweb/workers/repo-research.tssrc/agents/luminaweb/workers/review.tssrc/agents/rate-limit.tssrc/agents/subagent.tssrc/agents/tools.tssrc/inngest/functions.tssrc/prompts/planning.tssrc/prompts/research.tstests/gateway-fallback.test.tstests/glm-subagent-system.test.tstests/luminaweb-context-builder.test.tstests/luminaweb-orchestrator.test.tstests/luminaweb-planner.test.tstests/luminaweb-prompts.test.tstests/luminaweb-utils.test.ts
💤 Files with no reviewable changes (10)
- src/prompts/research.ts
- tests/glm-subagent-system.test.ts
- src/prompts/planning.ts
- tests/gateway-fallback.test.ts
- src/agents/tools.ts
- src/agents/index.ts
- src/agents/code-agent.ts
- src/agents/subagent.ts
- src/agents/rate-limit.ts
- src/agents/brave-tools.ts
|
@cubic-dev-ai review |
@Jackson57279 Sorry, I encountered an error while trying to start the review. Please try again later. |
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
src/agents/zapdev/prompts.ts (3)
13-16:⚠️ Potential issue | 🟠 MajorKeep
needsResearchindependent from complexity.Lines 15-16 still instruct the planner to set
needsResearch=truefor every moderate/complex task, which forces the research path even when no research is needed.Proposed prompt adjustment
Complexity: - "simple": single-file cosmetic changes. Steps 1-3. needsResearch=false. -- "moderate": new component, small feature, refactor. Steps 3-6. needsResearch=true. -- "complex": multi-file feature, integration, major refactor. Steps 6-10+. needsResearch=true. +- "moderate": new component, small feature, refactor. Steps 3-6. +- "complex": multi-file feature, integration, major refactor. Steps 6-10+. + +Research: +- Set needsResearch=true only when external documentation or project inspection would materially improve correctness. +- Set needsResearch=false when the task can be implemented confidently from the request and existing context.Based on learnings, Pipeline execution order in Zapdev orchestration: Planner decides
needsResearchandcomplexity. Research only fires whenneedsResearch=true. Review only fires whencomplexity !== "simple".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/prompts.ts` around lines 13 - 16, Update the planner prompt in src/agents/zapdev/prompts.ts so that needsResearch is not implicitly tied to complexity: remove or change the lines that force needsResearch=true for "moderate"/"complex" tasks and instead instruct the planner (in the plannerPrompt / PlannerPrompt constant) to decide needsResearch independently based on whether external research is actually required, while leaving the complexity assignment unchanged and ensuring downstream notes that Research only runs when needsResearch===true and Review runs when complexity!=="simple".
54-67:⚠️ Potential issue | 🟠 MajorTighten UI request detection to avoid backend false positives.
The substring matcher still treats broad tokens like
app,application,component,form,login, andsiteas UI signals. Prompts such as “fix application logs” or “add login API endpoint” can be incorrectly enhanced as design briefs.Proposed matcher direction
-const UI_KEYWORDS = [ +const UI_KEYWORD_PATTERNS = [ + /\blanding page\b/i, + /\bwebsite\b/i, + /\bhomepage\b/i, + /\bhero section\b/i, + /\bnavbar\b/i, + /\bdashboard\b/i, + /\b(?:ui|ux|frontend|front-end)\b/i, + /\b(?:responsive|mobile|tailwind|figma)\b/i, + /\b(?:dark mode|theme|interface|prototype)\b/i, + /\b(?:beautiful|modern|sleek|premium|minimalist|clean)\b/i, + /\b(?:web app|web page|webpage)\b/i, - "landing page", "website", "homepage", "hero section", "navbar", "navigation", - "dashboard", "ui", "ux", "design", "layout", "frontend", "front-end", - "component", "button", "card", "modal", "sidebar", "header", "footer", - "form", "signup", "sign-up", "login", "pricing", "portfolio", "blog", - "saas", "app", "application", "responsive", "mobile", "tailwind", - "styled", "css", "animation", "dark mode", "theme", "figma", - "beautiful", "modern", "sleek", "premium", "minimalist", "clean", - "web app", "web page", "webpage", "site", "interface", "prototype", ]; export function isUIGenerationRequest(message: string): boolean { - const lower = message.toLowerCase(); - return UI_KEYWORDS.some((kw) => lower.includes(kw)); + return UI_KEYWORD_PATTERNS.some((pattern) => pattern.test(message)); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/prompts.ts` around lines 54 - 67, The current substring matching in UI_KEYWORDS causes false positives (e.g., "app", "component", "login") — update isUIGenerationRequest to use whole-word/phrase matching and explicit negative checks: convert UI_KEYWORDS into canonical phrases and perform a regex-based match with word-boundaries (e.g., /\b(?:landing page|website|login|...)\b/i) in isUIGenerationRequest, and also add a short list of backend-negative tokens (e.g., "api", "endpoint", "log", "logs", "server", "backend") to early-return false when present; reference UI_KEYWORDS and isUIGenerationRequest when making these changes.
45-52:⚠️ Potential issue | 🟠 MajorRemove the framework-specific React version from the generic enhancer prompt.
Line 47 steers every UI enhancement toward React/Tailwind even though this pipeline supports multiple frameworks. Make the enhancer prompt framework-neutral or parameterize it with the selected project framework.
Proposed prompt adjustment
-Expand: design system (color palette with hex codes, typography, spacing), component architecture by section (Navbar, Hero, Features, Footer…), animations/micro-interactions, technical stack (React 19.2.4, Tailwind, specific libraries), and creative concept. +Expand: design system (color palette with hex codes, typography, spacing), component architecture by section (Navbar, Hero, Features, Footer…), animations/micro-interactions, technical stack aligned with the target project/framework, and creative concept.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/prompts.ts` around lines 45 - 52, ENHANCE_SYSTEM_PROMPT currently hardcodes "React 19.2.4, Tailwind" which forces a React/Tailwind bias; update the prompt string (ENHANCE_SYSTEM_PROMPT) to be framework-neutral or parameterized by replacing the explicit "React 19.2.4, Tailwind" text with either a generic "a frontend framework and styling system (e.g., React, Vue, Svelte; Tailwind, CSS-in-JS)" or a placeholder token (e.g., {framework}, {styling}) that the pipeline will substitute based on the selected project framework; ensure the RULES and other wording remain intact and that no release-candidate tags are included.src/inngest/functions.ts (1)
463-472:⚠️ Potential issue | 🟠 MajorSkip creating the review step for simple plans.
runPostReviewreturnsnullfor simple plans, but thezapdev-reviewInngest step still fires for every run. Guard the step so simple tasks follow the intended orchestration path.Proposed guard
- const review = await step.run("zapdev-review", () => - runPostReview({ - plan, - userMessage: workingMessage, - implementationSummary: e2bResult.summary, - files: e2bResult.files, - }) - ); + const review = + plan.complexity === "simple" + ? null + : await step.run("zapdev-review", () => + runPostReview({ + plan, + userMessage: workingMessage, + implementationSummary: e2bResult.summary, + files: e2bResult.files, + }) + ); e2bResult.summary = appendReviewNotes(e2bResult.summary, review);Based on learnings, Pipeline execution order in Zapdev orchestration: Planner decides
needsResearchandcomplexity. Research only fires whenneedsResearch=true. Review only fires whencomplexity !== "simple".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/inngest/functions.ts` around lines 463 - 472, The zapdev-review step is being executed even for simple plans because runPostReview returns null for those cases; update the code around the step.run("zapdev-review", ...) to guard it—either check plan.complexity !== "simple" (or plan.needsResearch logic) before invoking step.run("zapdev-review", ...) or first call runPostReview and only create the step when the returned review is non-null, then call appendReviewNotes(e2bResult.summary, review) only when review exists; reference symbols: plan, runPostReview, step.run("zapdev-review", ...), appendReviewNotes, and e2bResult.summary.
🧹 Nitpick comments (2)
src/agents/zapdev/context-builder.ts (1)
3-7: Fragile string coupling withexa-research.tsfallbacks.The
SKIP_EXA_SUMMARIESset relies on exact-match summary strings produced byrunExaResearch(e.g."No external research performed.","External search returned no results.","External research synthesis failed."). If any of those literals are changed inworkers/exa-research.ts, those fallback summaries will silently leak into the enriched system prompt without warning.Consider exporting the sentinel strings from
workers/exa-research.ts(or adding an explicitskip: trueflag / discriminated union onResearchArtifact) so both modules share a single source of truth.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/context-builder.ts` around lines 3 - 7, The SKIP_EXA_SUMMARIES set in context-builder.ts is brittle because it depends on exact literal summaries emitted by runExaResearch in workers/exa-research.ts; update the code so both modules share a single source of truth: export the sentinel strings (or better, a discriminant like a skip boolean or union variant) from workers/exa-research.ts and import them into context-builder.ts (or add a skip: true on ResearchArtifact returned by runExaResearch and check that flag instead of string-matching SKIP_EXA_SUMMARIES) so SKIP_EXA_SUMMARIES and runExaResearch/ResearchArtifact use the same identifier and avoid silent mismatches.src/agents/zapdev/orchestrator.ts (1)
107-113:appendReviewNotessilently discardsneeds_improvementand suggestions.Only
quality === "critical_issues"with non-emptyissuessurfaces anything downstream — review output forneeds_improvement, and allsuggestionsregardless of quality, are dropped. If that is intentional (critical-only surfacing), consider a short doc comment to make the contract explicit; otherwise, surfacingneeds_improvementissues and/or suggestions as a secondary section would make the review stage's output actionable.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/orchestrator.ts` around lines 107 - 113, The current appendReviewNotes logic only returns notes when review.quality === "critical_issues" and review.issues.length > 0, which drops "needs_improvement" outputs and any suggestions; update the logic in orchestrator.ts (the code handling summary, review, review.quality, review.issues, and review.suggestions) to always append a Review Notes section when review exists, include a "Critical Issues" subsection for review.quality === "critical_issues" and review.issues, a "Needs Improvement" subsection when review.quality === "needs_improvement" or when review.issues contains non-critical items, and an additional "Suggestions" subsection that lists review.suggestions (if any); keep the existing formatting and ordering but ensure empty arrays are skipped and add a short doc comment above the function to state the contract for what review qualities are surfaced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/inngest/functions.ts`:
- Around line 408-416: The preflight call to runPreflight is missing
projectFiles so repo research (runRepoResearch) cannot inspect the repo; fetch
the latest project files with convex.query(api.webcontainerFiles.getLatestFiles,
{ projectId: event.data.projectId as Id<"projects"> }) (or the existing API
wrapper used in this file) and include the returned files as projectFiles in the
runPreflight call inside step.run so runPreflight can forward them to
runRepoResearch when plan.needsResearch is true.
---
Duplicate comments:
In `@src/agents/zapdev/prompts.ts`:
- Around line 13-16: Update the planner prompt in src/agents/zapdev/prompts.ts
so that needsResearch is not implicitly tied to complexity: remove or change the
lines that force needsResearch=true for "moderate"/"complex" tasks and instead
instruct the planner (in the plannerPrompt / PlannerPrompt constant) to decide
needsResearch independently based on whether external research is actually
required, while leaving the complexity assignment unchanged and ensuring
downstream notes that Research only runs when needsResearch===true and Review
runs when complexity!=="simple".
- Around line 54-67: The current substring matching in UI_KEYWORDS causes false
positives (e.g., "app", "component", "login") — update isUIGenerationRequest to
use whole-word/phrase matching and explicit negative checks: convert UI_KEYWORDS
into canonical phrases and perform a regex-based match with word-boundaries
(e.g., /\b(?:landing page|website|login|...)\b/i) in isUIGenerationRequest, and
also add a short list of backend-negative tokens (e.g., "api", "endpoint",
"log", "logs", "server", "backend") to early-return false when present;
reference UI_KEYWORDS and isUIGenerationRequest when making these changes.
- Around line 45-52: ENHANCE_SYSTEM_PROMPT currently hardcodes "React 19.2.4,
Tailwind" which forces a React/Tailwind bias; update the prompt string
(ENHANCE_SYSTEM_PROMPT) to be framework-neutral or parameterized by replacing
the explicit "React 19.2.4, Tailwind" text with either a generic "a frontend
framework and styling system (e.g., React, Vue, Svelte; Tailwind, CSS-in-JS)" or
a placeholder token (e.g., {framework}, {styling}) that the pipeline will
substitute based on the selected project framework; ensure the RULES and other
wording remain intact and that no release-candidate tags are included.
In `@src/inngest/functions.ts`:
- Around line 463-472: The zapdev-review step is being executed even for simple
plans because runPostReview returns null for those cases; update the code around
the step.run("zapdev-review", ...) to guard it—either check plan.complexity !==
"simple" (or plan.needsResearch logic) before invoking step.run("zapdev-review",
...) or first call runPostReview and only create the step when the returned
review is non-null, then call appendReviewNotes(e2bResult.summary, review) only
when review exists; reference symbols: plan, runPostReview,
step.run("zapdev-review", ...), appendReviewNotes, and e2bResult.summary.
---
Nitpick comments:
In `@src/agents/zapdev/context-builder.ts`:
- Around line 3-7: The SKIP_EXA_SUMMARIES set in context-builder.ts is brittle
because it depends on exact literal summaries emitted by runExaResearch in
workers/exa-research.ts; update the code so both modules share a single source
of truth: export the sentinel strings (or better, a discriminant like a skip
boolean or union variant) from workers/exa-research.ts and import them into
context-builder.ts (or add a skip: true on ResearchArtifact returned by
runExaResearch and check that flag instead of string-matching
SKIP_EXA_SUMMARIES) so SKIP_EXA_SUMMARIES and runExaResearch/ResearchArtifact
use the same identifier and avoid silent mismatches.
In `@src/agents/zapdev/orchestrator.ts`:
- Around line 107-113: The current appendReviewNotes logic only returns notes
when review.quality === "critical_issues" and review.issues.length > 0, which
drops "needs_improvement" outputs and any suggestions; update the logic in
orchestrator.ts (the code handling summary, review, review.quality,
review.issues, and review.suggestions) to always append a Review Notes section
when review exists, include a "Critical Issues" subsection for review.quality
=== "critical_issues" and review.issues, a "Needs Improvement" subsection when
review.quality === "needs_improvement" or when review.issues contains
non-critical items, and an additional "Suggestions" subsection that lists
review.suggestions (if any); keep the existing formatting and ordering but
ensure empty arrays are skipped and add a short doc comment above the function
to state the contract for what review qualities are surfaced.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: ce63c0ef-8a2b-47ec-a7e4-7eca269e7c37
📒 Files selected for processing (17)
src/agents/AGENTS.mdsrc/agents/zapdev/context-builder.tssrc/agents/zapdev/index.tssrc/agents/zapdev/orchestrator.tssrc/agents/zapdev/planner.tssrc/agents/zapdev/prompts.tssrc/agents/zapdev/types.tssrc/agents/zapdev/utils.tssrc/agents/zapdev/workers/exa-research.tssrc/agents/zapdev/workers/repo-research.tssrc/agents/zapdev/workers/review.tssrc/inngest/functions.tstests/zapdev-context-builder.test.tstests/zapdev-orchestrator.test.tstests/zapdev-planner.test.tstests/zapdev-prompts.test.tstests/zapdev-utils.test.ts
✅ Files skipped from review due to trivial changes (1)
- src/agents/AGENTS.md
- Pass projectFiles into runPreflight so repo research can inspect files - Decouple needsResearch from complexity in planner prompt - Add whole-word/negative-token UI request matching to reduce false positives - Make ENHANCE_SYSTEM_PROMPT framework-neutral - Guard zapdev-review step for simple plans (skip when complexity==simple) - Replace brittle SKIP_EXA_SUMMARIES string set with shared skip boolean flag - Surface all review qualities (critical, needs_improvement, suggestions)
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/agents/zapdev/prompts.ts (1)
76-80: Minor: hoist the compiled regex to module scope.
new RegExp(...)is rebuilt on everyisUIGenerationRequestcall. SinceUI_KEYWORDSis static, compile once at module load.♻️ Proposed refactor
+const UI_KEYWORD_PATTERN = new RegExp( + `\\b(?:${UI_KEYWORDS.map((kw) => kw.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`, + "i" +); + export function isUIGenerationRequest(message: string): boolean { const lower = message.toLowerCase(); if (BACKEND_NEGATIVE_TOKENS.some((token) => lower.includes(token))) { return false; } - const pattern = new RegExp( - `\\b(?:${UI_KEYWORDS.map((kw) => kw.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})\\b`, - "i" - ); - return pattern.test(lower); + return UI_KEYWORD_PATTERN.test(lower); }Note: the ast-grep ReDoS warning on this regex is a false positive —
UI_KEYWORDSis a static, developer-controlled array, not user input.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/agents/zapdev/prompts.ts` around lines 76 - 80, isUIGenerationRequest currently rebuilds the regex on every call; hoist the compiled RegExp to module scope by creating a constant (e.g., UI_KEYWORDS_PATTERN) computed once from UI_KEYWORDS using the existing escaping logic, then replace the local `pattern` creation in isUIGenerationRequest with a test against that module-scoped constant; keep the same case-insensitive flag and word-boundary anchors and retain the escape implementation to avoid any change in matching semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/agents/zapdev/prompts.ts`:
- Around line 67-75: The BACKEND_NEGATIVE_TOKENS array is currently matched with
substring checks in isUIGenerationRequest which incorrectly rejects UI requests
(e.g., "login", "blog"); change the matching to whole-word checks (use
word-boundary regex like \bTOKEN\b) when testing each token against the
lowercased message, and adjust the decision logic in isUIGenerationRequest so a
single backend token does not short-circuit UI detection — for example, only
veto when a backend whole-word match exists AND no UI keyword (as detected by
UI_KEYWORDS) matches, or require backend matches to outnumber UI matches; update
references to BACKEND_NEGATIVE_TOKENS and isUIGenerationRequest accordingly.
---
Nitpick comments:
In `@src/agents/zapdev/prompts.ts`:
- Around line 76-80: isUIGenerationRequest currently rebuilds the regex on every
call; hoist the compiled RegExp to module scope by creating a constant (e.g.,
UI_KEYWORDS_PATTERN) computed once from UI_KEYWORDS using the existing escaping
logic, then replace the local `pattern` creation in isUIGenerationRequest with a
test against that module-scoped constant; keep the same case-insensitive flag
and word-boundary anchors and retain the escape implementation to avoid any
change in matching semantics.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: e7e85896-a8c5-41a8-a97b-ad1a784f2363
📒 Files selected for processing (6)
src/agents/zapdev/context-builder.tssrc/agents/zapdev/orchestrator.tssrc/agents/zapdev/prompts.tssrc/agents/zapdev/types.tssrc/agents/zapdev/workers/exa-research.tssrc/inngest/functions.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- src/agents/zapdev/workers/exa-research.ts
- src/agents/zapdev/context-builder.ts
- src/inngest/functions.ts
- src/agents/zapdev/orchestrator.ts
- src/agents/zapdev/types.ts
- Remove worker exports from zapdev barrel (index.ts) to prevent UI routes from importing them - Normalize and validate parsed AgentPlan fields (needsResearch coercion, complexity clamping, array validation) - Filter sensitive/hidden files from repo-research projectFiles (dotfiles, .git, node_modules, vendor, credentials) - Normalize relevantFiles in repo-research (handle string/object/invalid array items) - Log query index instead of full query text in exa-research error handling - Validate parsed.citations is a proper array with shape checks in exa-research - Reject nested hidden path segments in review.ts sourceEntries filter - Normalize parsed.issues and parsed.suggestions into validated string arrays in review.ts - Use word-boundary regex for BACKEND_NEGATIVE_TOKENS to avoid 'log' matching inside 'login' - Update context-builder test to set skip: true on sentinel exaResearch objects
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b6b386aab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const latestFilesDoc = await convex.query( | ||
| api.webcontainerFiles.getLatestFiles, | ||
| { projectId: event.data.projectId as Id<"projects"> } |
There was a problem hiding this comment.
Avoid auth-only query in unauthenticated Inngest preflight
This preflight now calls api.webcontainerFiles.getLatestFiles, but that Convex query requires requireAuth(ctx) (see convex/webcontainerFiles.ts), while this function uses a plain ConvexHttpClient from getConvexClient() with no setAuth/admin auth configured. In Inngest background runs this means the query throws Unauthorized, which fails zapdev-preflight before code generation starts, so jobs can fail universally instead of just skipping repo-file context.
Useful? React with 👍 / 👎.
| }); | ||
|
|
||
| const parsed = safeParseAIJSON<AgentPlan>(text); | ||
| if (parsed && typeof parsed.complexity === "string") { |
There was a problem hiding this comment.
Parse partial planner JSON even when complexity is omitted
The parser only accepts AI JSON when complexity is present, so if the model returns otherwise-usable structured output without that single field, the code drops all parsed fields and falls back to raw text in implementationHints. In that case needsResearch, steps, focusAreas, and filesToModify are lost, which can incorrectly disable research/review behavior and degrade implementation quality for malformed-but-recoverable planner outputs.
Useful? React with 👍 / 👎.
Bring back the incoming Inngest planning/research agent path, add the missing planning/research prompt modules, and keep related agent test updates aligned with the merged behavior. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a7fb0c1a41
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (basename.startsWith(".")) return true; | ||
| if (SENSITIVE_FILES.has(basename)) return true; | ||
| return segments.some((s) => SENSITIVE_SEGMENTS.has(s)); |
There was a problem hiding this comment.
Treat hidden directories as sensitive in repo research
isSensitive only checks for a leading dot on the basename plus a small fixed segment list, so files under hidden directories like .ssh/id_rsa or .config/token.json are not filtered and can be included in keySnippets sent to external LLMs. This creates an unintended secret-exposure path whenever projectFiles contains hidden-dir content; the filter should reject any path segment that starts with ..
Useful? React with 👍 / 👎.
| if (parsed?.quality) { | ||
| const toStringArray = (v: unknown): string[] => { |
There was a problem hiding this comment.
Validate review quality before propagating parsed output
This branch accepts any truthy parsed.quality and returns it as-is, but downstream rendering only handles critical_issues and needs_improvement (see appendReviewNotes), so off-schema values like "critical" can cause real issues to be dropped from the final summary. Normalizing quality to the allowed enum (or falling back) would prevent silent loss of review findings.
Useful? React with 👍 / 👎.
…/zapdev into feat/luminaweb-agent # Conflicts: # src/inngest/functions.ts # tests/gateway-fallback.test.ts # tests/glm-subagent-system.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1648f40b7d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const project = await ctx.db.get(args.projectId); | ||
| if (!project || project.userId !== args.userId) { | ||
| throw new Error("Unauthorized"); |
There was a problem hiding this comment.
Require auth context in getLatestFilesForUser
getLatestFilesForUser is exported as a public query, but it authorizes using only caller-supplied args.userId instead of requireAuth(ctx). Any client that can obtain a valid projectId and owner userId can read the latest stored files for that project by forging these args, which bypasses the auth model used by neighboring queries in this file.
Useful? React with 👍 / 👎.
| }); | ||
|
|
||
| const parsed = safeParseAIJSON<ReviewArtifact>(text); | ||
| if (parsed?.quality) { |
There was a problem hiding this comment.
Parse review payloads even when quality is omitted
The parser only accepts structured review output when parsed.quality is present; if the model returns valid JSON issues/suggestions but omits quality, this branch is skipped and the function falls back to { issues: [], quality: "good" }. That can silently drop real review findings and make downstream summaries look clean when the model actually reported problems.
Useful? React with 👍 / 👎.
Summary by cubic
Ports a zapdev-style agent pipeline (enhance → plan → repo+web research → code → review) and wires it into Inngest, replacing the legacy subagent system and restoring the planning/research path. Adds smarter planning/research, skips review for simple tasks, tightens review finding validation/surfacing, hardens parsing/file filtering, and appends critical review notes to the final summary.
inngestto4.2.4and updated the lockfile.Written for commit 1648f40. Summary will update on new commits.
Summary by CodeRabbit
New Features
Refactor
Documentation
Tests