Repository navigation
feat(api): integrate OpenRouter SDK and implement AI form generation … - #100
Conversation
📝 WalkthroughWalkthroughThe API replaces mock form generation with OpenRouter-backed JSON generation, prompt construction, schema validation, retry handling, and explicit HTTP errors. AI configuration and SDK wiring are added, the generation prompt becomes required, and a Prisma foreign key migration is made rerunnable. ChangesAI form generation
Foreign key migration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant generateForm
participant OpenRouter
participant FormDefinitionSchema
Client->>generateForm: Submit generation prompt
generateForm->>OpenRouter: Request JSON form definition
OpenRouter-->>generateForm: Return generated content
generateForm->>FormDefinitionSchema: Validate parsed definition
FormDefinitionSchema-->>generateForm: Return validation result
generateForm-->>Client: Return form or HTTP error
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/controllers/form.controller.ts`:
- Around line 304-314: Add a bounded timeout or AbortSignal to the request
constructed in the aiClient.chat.send call, using the surrounding controller’s
existing timeout configuration if available. Ensure an unresponsive AI service
causes the request to fail gracefully rather than hanging indefinitely, while
preserving the current chat payload and response format.
- Around line 298-309: Remove the duplicated user prompt from the
form-generation request: in apps/api/src/controllers/form.controller.ts lines
298-309, call buildFormGenerationPrompt without an argument while retaining the
existing user message; in apps/api/src/lib/ai/prompt.ts lines 5-39, remove the
userPrompt parameter and the appended “User request” section so the template
contains only system instructions.
- Line 343: Update the error response in the controller’s catch path to stop
returning err.message or other raw downstream details; log the actual error
server-side, then return a sanitized generic failure message in the response
while preserving the existing error status and handling flow.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 88225e88-1e35-4b71-b7ad-7d0d839b1adf
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
apps/api/.env.exampleapps/api/package.jsonapps/api/src/controllers/form.controller.tsapps/api/src/lib/ai/client.tsapps/api/src/lib/ai/prompt.tsapps/api/src/lib/env.tsapps/api/src/lib/form-schemas.tspackages/db/prisma/migrations/20260701000001_add_cloned_form_fk/migration.sql
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-06-16T07:39:18.285Z
Learnt from: Basharkhan7776
Repo: Openlabsops/Snap-form PR: 22
File: apps/api/package.json:10-10
Timestamp: 2026-06-16T07:39:18.285Z
Learning: In the Openlabsops/Snap-form monorepo (Bun workspace), internal workspace package dependencies using the `repo/*` scope must use the version specifier `"*"` (not `"workspace:*"`). Apply this consistently when reviewing all `apps/*/package.json` and `packages/*/package.json` files (e.g., `repo/typescript-config`, `repo/eslint-config`, `repo/types`): don’t restrict the check to newly added `repo/*` packages—`"*"` is the repo-wide convention.
Applied to files:
apps/api/package.json
🪛 dotenv-linter (4.0.0)
apps/api/.env.example
[warning] 11-11: [UnorderedKey] The OPENROUTER_API_KEY key should go before the PORT key
(UnorderedKey)
[warning] 12-12: [EndingBlankLine] No blank line at the end of the file
(EndingBlankLine)
[warning] 12-12: [UnorderedKey] The AI_MODEL key should go before the BETTER_AUTH_SECRET key
(UnorderedKey)
🔇 Additional comments (5)
packages/db/prisma/migrations/20260701000001_add_cloned_form_fk/migration.sql (1)
2-3: LGTM!apps/api/.env.example (1)
11-12: LGTM!apps/api/src/lib/env.ts (1)
31-34: LGTM!apps/api/src/lib/form-schemas.ts (1)
42-42: LGTM!apps/api/src/lib/ai/client.ts (1)
1-6: 🎯 Functional Correctness
@openrouter/sdkis the correct client hereThe package exists, exports
OpenRouter, and supportschat.send(...)as used in this code.> Likely an incorrect or invalid review comment.
| const systemPrompt = buildFormGenerationPrompt(prompt); | ||
|
|
||
| const MAX_RETRIES = 1; | ||
|
|
||
| for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { | ||
| try { | ||
| const result = await aiClient.chat.send({ | ||
| chatRequest: { | ||
| messages: [ | ||
| { role: "system", content: systemPrompt }, | ||
| { role: "user", content: prompt }, | ||
| ], |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
Remove duplicated user prompt.
The user's prompt is being injected into both the system message (via buildFormGenerationPrompt(prompt)) and the user message array. This duplication is redundant and wastes tokens.
apps/api/src/controllers/form.controller.ts#L298-L309: CallbuildFormGenerationPrompt()without arguments, as the user input is already provided in the{ role: "user", content: prompt }message.apps/api/src/lib/ai/prompt.ts#L5-L39: Remove theuserPromptparameter and the appended## User request:section from the template so it only defines the system instructions.
📍 Affects 2 files
apps/api/src/controllers/form.controller.ts#L298-L309(this comment)apps/api/src/lib/ai/prompt.ts#L5-L39
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/api/src/controllers/form.controller.ts` around lines 298 - 309, Remove
the duplicated user prompt from the form-generation request: in
apps/api/src/controllers/form.controller.ts lines 298-309, call
buildFormGenerationPrompt without an argument while retaining the existing user
message; in apps/api/src/lib/ai/prompt.ts lines 5-39, remove the userPrompt
parameter and the appended “User request” section so the template contains only
system instructions.
|
LGTM!! |
Basharkhan7776
left a comment
There was a problem hiding this comment.
Pretty cool work, but don't know about the performance and test. @yashraj639 and @silky-x0 we need test for this implementations.
|
@Basharkhan7776 yeah already raised issue and working on it(unit test), as for the integration test we'll check once UI is done. |
Summary
Integrates the OpenRouter SDK, sets up the prompt structure for AI form generation, and replaces the mock generation controller with a real schema-validated AI pipeline. Also resolves a database migration issue to ensure idempotency.
Changes Made
@openrouter/sdkpackage dependency toapps/api.OPENROUTER_API_KEYand configurableAI_MODELwith fallbacks insideenv.tsand.env.example.apps/api/src/lib/ai/client.tsfor unified OpenRouter client access.apps/api/src/lib/ai/prompt.tscontaining rules and schemas for element/option mapping.POST /api/v1/forms/generatewith a real AI call.responseFormat: { type: "json_object" }).FormDefinitionSchema.20260701000001_add_cloned_form_fkby addingDROP CONSTRAINT IF EXISTS.Technical Decisions
Testing
bun run testinpackages/api-testsis fully clean)Related Issues
Checklist