Skip to content

Conversation

@qubi00
Copy link
Collaborator

@qubi00 qubi00 commented Nov 10, 2025

Chatbot widgets UI and CORS policy implemented

Type of Change

  • ✨ New feature

Description

Added widgets UI with deep chat react, configured header for responses for CORS policy.

How to Test / Verification Steps

  1. Go to embed-widgets and run "npm run build", this creates an embed.js file in public/embed/
  2. Go to any other website, and insert the script inside your html file:
<script src="http://localhost:3000/embed/embed.js" data-chatbot-id="chatbot-uuid" defer> </script>

Screenshots / GIFs (if applicable)

image

Impact of Changes

Users of chatbots can prompt it externally

Summary by CodeRabbit

  • New Features

    • CORS preflight handling and consistent JSON responses for the chatbot API.
    • Host-based allowlist for secure embedded access; improved conversation flow preserving history and stable conversation IDs.
    • Upstream AI request integration updated to use a standardized HTTP call with clearer error responses.
  • Chores

    • Added a new embeddable chat widget project (tooling, configs, README, and runtime widget).
    • Removed the Assistants page and related Home page tests.

@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Walkthrough

Adds CORS preflight handling, host-based allowlist, and standardized JSON responses to the chatbot prompt API; extends the Chatbot DB query and replaces in-file OpenRouter usage with an axios-based call; introduces a new embed-widget (React + TypeScript + Vite) as an embeddable chat widget; removes the Assistants page and a Home page test file.

Changes

Cohort / File(s) Summary
API Route Enhancement
app/api/chatbots/[id]/prompt/route.ts
Adds OPTIONS handler for CORS preflight; parses/validates request origin against allowed_domains; refactors DB select to include personality and Users(...) and use typed .single<ChatbotData>(); introduces createResponse helper to standardize JSON + CORS headers; enforces host allowlist (403 if disallowed); preserves/validates conversation ownership; switches to axios-based call to OpenRouter with env key check and additional headers; returns consistent { reply, conversation_id? } payloads.
Embed Widget Project (configs + tooling)
embed-widget/.gitignore, embed-widget/README.md, embed-widget/package.json, embed-widget/vite.config.ts, embed-widget/eslint.config.js, embed-widget/tsconfig.json, embed-widget/tsconfig.app.json, embed-widget/tsconfig.node.json, embed-widget/index.html
Adds a new embed-widget project: ignore rules, README, package.json, Vite config building a UMD ChatbotWidget to ../public/embed/embed.js, ESLint config, HTML entry, and TypeScript project and node configs.
Embed Widget Source
embed-widget/src/Widget.tsx, embed-widget/src/main.tsx
Adds Widget React component and bootstrap main.tsx: floating chat button/panel, local conversationId state, chatHandler posting to /api/chatbots/{chatbotId}/prompt with conversation_id, updates conversation id from responses and emits assistant replies via signals.onResponse.
Removed UI & Tests
app/assistant/page.tsx, app/page.test.tsx
Removes the Assistants page component and the Home page test suite (deleting UI rendering, auth/db logic and tests).

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant OPTIONS as OPTIONS Handler
    participant POST as POST Handler
    participant DB as Database
    participant OpenRouter as OpenRouter API

    Note over Browser,OPTIONS: CORS preflight
    Browser->>OPTIONS: OPTIONS /api/chatbots/[id]/prompt (Origin)
    OPTIONS->>OPTIONS: Validate origin, set CORS headers
    alt Origin allowed
        OPTIONS->>Browser: 204 + CORS headers
    else Origin not allowed
        OPTIONS->>Browser: 204 + CORS headers (no allow-origin)
    end

    Note over Browser,POST: Chat message flow
    Browser->>POST: POST /api/chatbots/[id]/prompt (body incl. conversation_id)
    POST->>DB: Fetch chatbot (personality, Users, allowed_domains)
    POST->>POST: Parse origin -> requestHostname -> check allowlist
    alt Origin not allowed
        POST->>Browser: 403 JSON (createResponse)
    else Origin allowed
        POST->>OpenRouter: axios POST (body, headers: Authorization, Content-Type, Referer, X-Title)
        OpenRouter-->>POST: AI response
        POST->>DB: create/update conversation record (if applicable)
        POST->>Browser: 200 JSON { reply, conversation_id } (createResponse)
    end
Loading
sequenceDiagram
    participant Page
    participant Main as main.tsx
    participant Widget as Widget.tsx
    participant Backend as /api/chatbots/{id}/prompt
    participant DeepChat

    Page->>Main: load embed script (data-chatbot-id)
    Main->>Main: extract chatbotId, create mount node
    Main->>Widget: render Widget(chatbotId)
    Widget->>DeepChat: render UI (floating button/panel)

    DeepChat->>Widget: user sends message
    Widget->>Backend: POST message with conversation_id
    Backend-->>Widget: { reply, conversation_id }
    Widget->>DeepChat: signals.onResponse(reply)
    Widget->>Widget: update conversation_id
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • Origin parsing and allowlist logic in app/api/chatbots/[id]/prompt/route.ts (subdomain, port, header edge cases).
    • createResponse headers/status consistency for CORS and JSON responses.
    • DB selection and typed .single<ChatbotData>() usage to ensure schema alignment.
    • OpenRouter axios call: header composition, env var presence/handling, and response parsing (assistant reply extraction).
    • Embed widget: backend URL assumptions, conversation_id lifecycle, and client-side error handling.
    • Removal of app/assistant/page.tsx and app/page.test.tsx: ensure no remaining imports or references.

Possibly related PRs

  • Feature/openrouter integration #5 — Modifies the same app/api/chatbots/[id]/prompt/route.ts to extend OpenRouter-backed prompt handling; strongly related.
  • Feature/api routes #3 — Previously added the POST prompt handler for the same route; related as this PR refactors and extends that handler.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main changes: a chatbot widgets UI and CORS policy modifications, which aligns with the primary scope of this feature PR.
Description check ✅ Passed The description covers the essential sections (type of change, description, testing steps, impact) but lacks related issues, breaking changes checkbox, and developer checklist completeness.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/embedded-script

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (8)
app/api/chatbots/[id]/prompt/route.ts (1)

109-109: Consider making max_tokens configurable.

The hardcoded value of 1024 tokens may be restrictive for some use cases. Consider making this configurable per chatbot or at least adding a comment explaining the choice.

Example:

     const openrouterResponse = await axios.post(
       'https://openrouter.ai/api/v1/chat/completions',
       {
         model: 'openai/gpt-5',
         messages: messagesForAPI,
-        max_tokens: 1024,
+        max_tokens: chatbot.max_tokens || 1024, // Default to 1024 for cost control
       },
embed-widget/src/main.tsx (1)

11-13: Consider preventing multiple widget instances.

If the embed script is accidentally included multiple times, this code will create multiple chat widgets. Consider checking for an existing container or using a singleton pattern.

+ const existingContainer = document.getElementById('chatbot-embed-root');
+ if (existingContainer) {
+   console.warn('Chatbot widget already initialized');
+   return;
+ }
+
  const container = document.createElement('div');
  container.id = 'chatbot-embed-root';
  document.body.appendChild(container);
embed-widget/README.md (1)

1-73: Update README with project-specific documentation.

This README contains the default Vite template documentation. Consider replacing it with embed-widget-specific instructions, including:

  • Purpose of the widget
  • Build and deployment steps (as mentioned in the PR description)
  • How to integrate the embed script into external websites
  • Configuration options (chatbot-id attribute)
embed-widget/vite.config.ts (1)

11-23: Consider externalizing React dependencies to reduce bundle conflicts.

The current UMD build bundles React and ReactDOM into the output. If the host website also uses React, this could cause conflicts (multiple React instances, version mismatches, context issues).

Consider externalizing React:

   build: {
     outDir: '../public/embed',
     lib: {
       entry: 'src/main.tsx',
       name: 'ChatbotWidget',
       formats: ['umd'],
     },
     rollupOptions: {
+      external: ['react', 'react-dom'],
+      output: {
+        entryFileNames: 'embed.js',
+        globals: {
+          react: 'React',
+          'react-dom': 'ReactDOM',
+        },
+      },
-      output: {
-        entryFileNames: 'embed.js',
-      },
     },
   },

If externalizing, document that host pages must include React before loading the widget, or use a separate build strategy that includes React for self-contained deployment.

embed-widget/eslint.config.js (1)

19-19: Consider aligning ECMAScript version with TypeScript target.

The ecmaVersion: 2020 is older than the TypeScript targets (ES2022/ES2023). While not critical, aligning these values prevents potential parser inconsistencies.

Apply this diff to align with the TypeScript app target:

     languageOptions: {
-      ecmaVersion: 2020,
+      ecmaVersion: 2022,
       globals: globals.browser,
     },
embed-widget/src/Widget.tsx (3)

37-39: Enhance error handling with specific error messages.

The generic error message doesn't provide context about what failed. Consider extracting error details from the response to help users understand issues like invalid chatbot IDs, rate limits, or authentication failures.

Apply this diff to provide more specific error feedback:

       if (!response.ok) {
-        throw new Error('API request failed');
+        const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
+        throw new Error(errorData.error || `API request failed with status ${response.status}`);
       }

Then update the catch block to use the error message:

     } catch (error) {
       console.error(error);
       signals.onResponse({
-        error: 'Sorry, I had trouble connecting.',
+        error: error instanceof Error ? error.message : 'Sorry, I had trouble connecting.',
         role: 'assistant',
       });
     }

60-76: Add visual indicator or label to the chat button.

The button is empty (line 76) with no text, icon, or ARIA label, making it unclear to users what the button does and inaccessible to screen readers.

Apply this diff to add a chat icon and accessibility label:

         <button
           onClick={() => setIsOpen(true)}
+          aria-label="Open chat assistant"
           style={{
             width: '60px',
             height: '60px',
             borderRadius: '50%',
             backgroundColor: '#0070f3',
             color: 'white',
             border: 'none',
             fontSize: '28px',
             cursor: 'pointer',
             boxShadow: '0 4px 14px 0 rgba(0, 118, 255, 0.39)',
             display: 'flex',
             alignItems: 'center',
             justifyContent: 'center',
           }}
-        ></button>
+        >
+          💬
+        </button>

24-55: Consider adding loading state during API calls.

Users receive no feedback while waiting for the API response, which can lead to confusion or duplicate message submissions on slow connections.

Add a loading state to provide visual feedback:

 export function Widget({ chatbotId }: WidgetProps) {
   const [isOpen, setIsOpen] = useState(false);
+  const [isLoading, setIsLoading] = useState(false);

   const chatHandler = async (body: DeepChatRequestBody, signals: DeepChatResponseSignals) => {
     const userMessage = body.messages[body.messages.length - 1].text;

     try {
+      setIsLoading(true);
       const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, {
         // ... rest of the code
       });
       // ... rest of the code
     } catch (error) {
       console.error(error);
       signals.onResponse({
         error: 'Sorry, I had trouble connecting.',
         role: 'assistant',
       });
+    } finally {
+      setIsLoading(false);
     }
   };

Then pass isLoading to DeepChat or display a loading indicator in the UI.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5eeed87 and 7e839ec.

⛔ Files ignored due to path filters (8)
  • embed-widget/package-lock.json is excluded by !**/package-lock.json
  • embed-widget/public/vite.svg is excluded by !**/*.svg
  • public/embed/vite.svg is excluded by !**/*.svg
  • public/file.svg is excluded by !**/*.svg
  • public/globe.svg is excluded by !**/*.svg
  • public/next.svg is excluded by !**/*.svg
  • public/vercel.svg is excluded by !**/*.svg
  • public/window.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • app/api/chatbots/[id]/prompt/route.ts (5 hunks)
  • embed-widget/.gitignore (1 hunks)
  • embed-widget/README.md (1 hunks)
  • embed-widget/eslint.config.js (1 hunks)
  • embed-widget/index.html (1 hunks)
  • embed-widget/package.json (1 hunks)
  • embed-widget/src/Widget.tsx (1 hunks)
  • embed-widget/src/main.tsx (1 hunks)
  • embed-widget/tsconfig.app.json (1 hunks)
  • embed-widget/tsconfig.json (1 hunks)
  • embed-widget/tsconfig.node.json (1 hunks)
  • embed-widget/vite.config.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
embed-widget/src/main.tsx (1)
embed-widget/src/Widget.tsx (1)
  • Widget (21-131)
app/api/chatbots/[id]/prompt/route.ts (2)
app/api/chatbots/route.ts (1)
  • POST (5-45)
lib/supabase_admin.ts (1)
  • supabase_admin (3-3)
🔇 Additional comments (8)
embed-widget/.gitignore (1)

1-24: LGTM!

Standard gitignore patterns appropriate for a Node.js/Vite project.

embed-widget/index.html (1)

1-13: LGTM!

Standard HTML5 structure appropriate for a React application entry point.

embed-widget/tsconfig.json (1)

1-7: LGTM!

Standard TypeScript project references configuration for composite builds.

embed-widget/package.json (1)

12-16: Verify React 19 compatibility and test thoroughly before deploying embed widget.

React 19 is production-ready but includes opt‑in new features and removal/cleanup of older APIs, requiring testing and migration work. Real-world issues include TypeScript/tooling breakages and third-party library incompatibilities, plus some performance regressions reported in certain scenarios.

For an embed widget distributed to external sites:

  1. Test in staging with StrictMode and run React codemods; audit for usage of removed APIs and verify all dependencies support React 19
  2. Profile for performance regressions (INP, flamegraphs) and adjust code or enable React compiler if needed
  3. Consider pinning exact versions (remove ^) for react and react-dom to ensure build consistency across all external deployments and reduce risk of unexpected updates introducing issues
app/api/chatbots/[id]/prompt/route.ts (1)

104-119: openrouter model is valid — replace hardcoded localhost headers

openai/gpt-5 is present in OpenRouter's model list (so the model-name objection is incorrect). Still update the request headers in app/api/chatbots/[id]/prompt/route.ts to avoid hardcoding. Minimal actions:

  • Replace the hardcoded referer/title headers (around lines 104–119):
    • 'HTTP-Referer': 'http://localhost:3000' → 'Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
    • 'X-Title': 'Chatbot app' → 'X-Title': process.env.NEXT_PUBLIC_APP_NAME || 'Chatbot app'

Location: app/api/chatbots/[id]/prompt/route.ts (axios headers block).

Likely an incorrect or invalid review comment.

embed-widget/tsconfig.node.json (1)

1-26: LGTM! Standard Vite TypeScript configuration.

The configuration is appropriate for a Vite bundler setup with strict type checking and modern ESNext features enabled.

embed-widget/tsconfig.app.json (1)

1-28: LGTM! Appropriate TypeScript configuration for React application.

The ES2022 target (vs ES2023 in the node config) provides better browser compatibility for the embedded widget while maintaining modern features.

embed-widget/eslint.config.js (1)

6-6: The ESLint config import is correct.

The imports defineConfig and globalIgnores from 'eslint/config' are valid in ESLint v9 and follow the official flat config pattern. Both utilities can be imported from "eslint/config" and used together in ESLint v9 flat config. The current code in embed-widget/eslint.config.js matches the documented approach for ESLint v9.36.0.

Likely an incorrect or invalid review comment.

const userMessage = body.messages[body.messages.length - 1].text;

try {
const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded localhost URL prevents production deployment.

The API URL is hardcoded to http://localhost:3000, which will fail when the widget is embedded on external websites in production environments.

Add an apiBaseUrl prop to the Widget component and pass it through from the embed script:

 interface WidgetProps {
   chatbotId: string;
+  apiBaseUrl: string;
 }

 export function Widget({ chatbotId }: WidgetProps) {
   const [isOpen, setIsOpen] = useState(false);

   const chatHandler = async (body: DeepChatRequestBody, signals: DeepChatResponseSignals) => {
     const userMessage = body.messages[body.messages.length - 1].text;

     try {
-      const response = await fetch(`http://localhost:3000/api/chatbots/${chatbotId}/prompt`, {
+      const response = await fetch(`${apiBaseUrl}/api/chatbots/${chatbotId}/prompt`, {
         method: 'POST',

Then update embed-widget/src/main.tsx to read the API URL from a script data attribute (e.g., data-api-url) or use window.location.origin if the widget is served from the same domain as the API.

Committable suggestion skipped: line range outside the PR's diff.

@qubi00 qubi00 force-pushed the feature/embedded-script branch from b4d5771 to 87b0507 Compare November 11, 2025 03:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
app/api/chatbots/[id]/prompt/route.ts (1)

75-80: Unconfigured allowed_domains blocks all requests.

When allowed_domains is null, undefined, or an empty array, line 75 defaults to [], and line 77 will always reject requests (assuming requestHostname is not null). This blocks all legitimate traffic when a user hasn't yet configured their allowed domains.

Consider this approach to handle unconfigured domains:

- const allowedDomains = userData?.allowed_domains || [];
+ const allowedDomains = userData.allowed_domains;

- if (!requestHostname || !allowedDomains.includes(requestHostname)) {
+ if (allowedDomains && allowedDomains.length > 0) {
+   if (!requestHostname || !allowedDomains.includes(requestHostname)) {
-     console.error(`Website'${requestHostname}' not in allowed list [${allowedDomains.join(', ')}]`);
+     console.error(`Website '${requestHostname}' not in allowed list [${allowedDomains.join(', ')}]`);
-     return createResponse({ error: 'Host not allowed' }, 403);
+     return createResponse({ error: 'Host not allowed' }, 403);
+   }
+ }

This way, if allowed_domains is null, undefined, or empty, the validation is skipped, and requests are allowed. Only when domains are explicitly configured is the allowlist enforced.

🧹 Nitpick comments (1)
embed-widget/.gitignore (1)

1-24: Solid .gitignore coverage for a Vite + React project.

The file comprehensively excludes logs, build artifacts, editor config, and node_modules. The exception for .vscode/extensions.json is good practice for sharing editor recommendations.

Consider adding explicit patterns for environment variables to prevent accidental secrets leakage:

 *.local
+.env
+.env.local
+.env.*.local

This is a best practice for projects that use environment variables or .env files.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4d5771 and 87b0507.

⛔ Files ignored due to path filters (8)
  • embed-widget/package-lock.json is excluded by !**/package-lock.json
  • embed-widget/public/vite.svg is excluded by !**/*.svg
  • public/embed/vite.svg is excluded by !**/*.svg
  • public/file.svg is excluded by !**/*.svg
  • public/globe.svg is excluded by !**/*.svg
  • public/next.svg is excluded by !**/*.svg
  • public/vercel.svg is excluded by !**/*.svg
  • public/window.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • app/api/chatbots/[id]/prompt/route.ts (1 hunks)
  • app/assistant/page.tsx (0 hunks)
  • app/page.test.tsx (0 hunks)
  • embed-widget/.gitignore (1 hunks)
  • embed-widget/README.md (1 hunks)
  • embed-widget/eslint.config.js (1 hunks)
  • embed-widget/index.html (1 hunks)
  • embed-widget/package.json (1 hunks)
  • embed-widget/src/Widget.tsx (1 hunks)
  • embed-widget/src/main.tsx (1 hunks)
  • embed-widget/tsconfig.app.json (1 hunks)
  • embed-widget/tsconfig.json (1 hunks)
  • embed-widget/tsconfig.node.json (1 hunks)
  • embed-widget/vite.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • app/page.test.tsx
  • app/assistant/page.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • embed-widget/vite.config.ts
  • embed-widget/src/main.tsx
  • embed-widget/tsconfig.app.json
  • embed-widget/src/Widget.tsx
  • embed-widget/tsconfig.node.json
  • embed-widget/README.md
  • embed-widget/index.html
  • embed-widget/package.json
  • embed-widget/tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (1)
app/api/chatbots/[id]/prompt/route.ts (2)
app/api/chatbots/route.ts (1)
  • POST (31-73)
lib/supabase_admin.ts (1)
  • supabase_admin (13-15)
🔇 Additional comments (8)
app/api/chatbots/[id]/prompt/route.ts (8)

5-9: LGTM!

The Message type definition properly constrains the role field to valid OpenAI-compatible values and provides clear structure for conversation history.


10-24: LGTM! Previous CORS security issue resolved.

The OPTIONS handler now correctly rejects preflight requests without an Origin header and avoids the wildcard fallback that was previously flagged. This prevents unauthorized origins from bypassing CORS restrictions.


37-45: LGTM! CORS fallback security issue resolved.

The createResponse helper now uses an empty string fallback instead of the wildcard, ensuring browsers will correctly block requests from unauthorized origins.


71-74: LGTM!

Good defensive check for missing user configuration. This prevents downstream null pointer issues and provides a clear error message.


85-97: LGTM!

Conversation history retrieval properly validates that the conversation belongs to the specified chatbot before using it, preventing cross-chatbot data leakage.


108-110: LGTM!

Good defensive check for the required API key before attempting the OpenRouter call.


138-155: LGTM!

The conversation persistence logic correctly handles both updating existing conversations and creating new ones, returning the appropriate response shape in each case.


156-159: LGTM!

The catch-all error handler provides a consistent response format and logs errors for debugging while avoiding sensitive information leakage.

const openrouterResponse = await axios.post(
'https://openrouter.ai/api/v1/chat/completions',
{
model: 'openai/gpt-5',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the model name is valid.

The model 'openai/gpt-5' does not appear to be a valid OpenRouter model identifier. This will likely cause API calls to fail.

Please verify the correct model name. Common valid models include:

  • 'openai/gpt-4-turbo'
  • 'openai/gpt-4'
  • 'openai/gpt-3.5-turbo'

You can check the latest available models by searching OpenRouter's documentation:


🌐 Web query:

What are the available OpenAI models on OpenRouter API?

💡 Result:

OpenRouter exposes a marketplace of 400+ models from many providers (OpenAI, Anthropic, Google, Meta, Mistral, xAI, Amazon, etc.), and you can list them via the OpenRouter “list available models” endpoint or browse their models page. Example popular IDs available through OpenRouter include (but are not limited to):

  • OpenAI: openai/gpt-4, openai/gpt-4-32k, openai/gpt-4o, openai/gpt-3.5-turbo (and variants).
  • Anthropic: anthropic/claude-3-opus, anthropic/claude-3-haiku, claude-instant variants.
  • Google: google/palm-2-chat-bison, google/palm-2-codechat-bison, google/gemini (various).
  • Meta: meta-llama/llama-2-13b-chat, meta-llama/llama-2-70b-chat (and newer Llama versions where listed).
  • Other providers: mistralai, deepseek, cohere, xAI (grok), amazon (nova), etc.

For the definitive, up-to-date list use the OpenRouter API endpoint “List available models” or their models catalog (they keep the catalog updated). [1][2]

Sources:
[1] OpenRouter API — List available models (docs).
[2] OpenRouter — Models overview / catalog.


Fix invalid model identifier to use valid OpenRouter model.

The model 'openai/gpt-5' is not available on OpenRouter API and will cause API calls to fail. Valid OpenAI models on OpenRouter include openai/gpt-4, openai/gpt-4-32k, openai/gpt-4o, and openai/gpt-3.5-turbo. Update line 115 to use one of these valid identifiers (e.g., 'openai/gpt-4' or 'openai/gpt-4o').

🤖 Prompt for AI Agents
In app/api/chatbots/[id]/prompt/route.ts around line 115 the model identifier is
set to 'openai/gpt-5', which is invalid for OpenRouter; change it to a supported
OpenRouter model such as 'openai/gpt-4' or 'openai/gpt-4o' (e.g., replace
'openai/gpt-5' with 'openai/gpt-4') so API calls use a valid model identifier.

headers: {
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
'Content-Type': 'application/json',
'HTTP-Referer': 'http://localhost:3000',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Replace hardcoded localhost with dynamic referer.

The HTTP-Referer header is hardcoded to 'http://localhost:3000', which will be incorrect in production environments and may affect request attribution or rate limiting.

Consider using the actual request origin or a configurable environment variable:

- 'HTTP-Referer': 'http://localhost:3000',
+ 'HTTP-Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
📝 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.

Suggested change
'HTTP-Referer': 'http://localhost:3000',
'HTTP-Referer': origin || process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
🤖 Prompt for AI Agents
In app/api/chatbots/[id]/prompt/route.ts around line 123, the 'HTTP-Referer'
header is hardcoded to 'http://localhost:3000'; change it to use a dynamic value
by reading the request origin (e.g., request.headers.get('origin') or
reconstructing from request URL) or falling back to a configurable env var
(e.g., process.env.NEXT_PUBLIC_APP_URL) so production deployments send the
correct referer; ensure you validate or normalize the value before setting the
header and keep localhost as a fallback only when no origin/env is available.

Comment on lines +1 to +23
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
import { defineConfig, globalIgnores } from 'eslint/config';

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix ESLint flat config syntax errors.

This configuration contains multiple syntax errors that will prevent ESLint from loading:

  1. Line 6: eslint/config is not a valid import path. ESLint 9.x flat config doesn't export defineConfig or globalIgnores from that path.
  2. Line 9: The globalIgnores() function doesn't exist in flat config. Use { ignores: ['dist'] } instead.
  3. Lines 12-17: The extends property doesn't exist in flat config. Configs should be spread directly into the top-level array.

Apply this diff to use correct ESLint 9.x flat config syntax:

-import js from '@eslint/js';
-import globals from 'globals';
-import reactHooks from 'eslint-plugin-react-hooks';
-import reactRefresh from 'eslint-plugin-react-refresh';
-import tseslint from 'typescript-eslint';
-import { defineConfig, globalIgnores } from 'eslint/config';
-
-export default defineConfig([
-  globalIgnores(['dist']),
-  {
-    files: ['**/*.{ts,tsx}'],
-    extends: [
-      js.configs.recommended,
-      tseslint.configs.recommended,
-      reactHooks.configs['recommended-latest'],
-      reactRefresh.configs.vite,
-    ],
-    languageOptions: {
-      ecmaVersion: 2020,
-      globals: globals.browser,
-    },
-  },
-]);
+import js from '@eslint/js';
+import globals from 'globals';
+import reactHooks from 'eslint-plugin-react-hooks';
+import reactRefresh from 'eslint-plugin-react-refresh';
+import tseslint from 'typescript-eslint';
+
+export default [
+  { ignores: ['dist'] },
+  js.configs.recommended,
+  ...tseslint.configs.recommended,
+  {
+    files: ['**/*.{ts,tsx}'],
+    plugins: {
+      'react-hooks': reactHooks,
+      'react-refresh': reactRefresh,
+    },
+    rules: {
+      ...reactHooks.configs.recommended.rules,
+      'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
+    },
+    languageOptions: {
+      ecmaVersion: 2020,
+      globals: globals.browser,
+    },
+  },
+];
📝 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.

Suggested change
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
import { defineConfig, globalIgnores } from 'eslint/config';
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
]);
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
export default [
{ ignores: ['dist'] },
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.{ts,tsx}'],
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
},
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
];

@arnavSingh23 arnavSingh23 merged commit 25c39d2 into dev Nov 11, 2025
1 of 2 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Nov 16, 2025
1 task
@coderabbitai coderabbitai bot mentioned this pull request Nov 25, 2025
11 tasks
@coderabbitai coderabbitai bot mentioned this pull request Dec 16, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants