Skip to content

feat: save compatible provider models to customModels DB for /v1/models listing#122

Merged
diegosouzapw merged 13 commits intodiegosouzapw:mainfrom
nyatoru:feat/custom-models-fix
Feb 24, 2026
Merged

feat: save compatible provider models to customModels DB for /v1/models listing#122
diegosouzapw merged 13 commits intodiegosouzapw:mainfrom
nyatoru:feat/custom-models-fix

Conversation

@nyatoru
Copy link
Contributor

@nyatoru nyatoru commented Feb 24, 2026

Add Custom Provider to support models endpoint

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @nyatoru, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the management of compatible provider models by integrating them with a customModels database. The changes ensure that both manually added and imported models are persisted, allowing them to be correctly listed via the /v1/models endpoint. Furthermore, the deletion process has been updated to remove models from both their aliases and the custom database, maintaining data integrity.

Highlights

  • Model Persistence for Manual Additions: Implemented logic to save manually added compatible provider models to the customModels database via a new API endpoint (/api/provider-models) to ensure they appear in the /v1/models listing.
  • Model Persistence for Imports: Extended the model import process to also persist imported compatible provider models into the customModels database, ensuring their visibility in the /v1/models endpoint.
  • Unified Model Deletion: Introduced a unified handleDeleteModel function to remove models from both their alias configuration and the customModels database, ensuring complete removal and consistency.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/app/(dashboard)/dashboard/providers/[id]/page.tsx
    • Added a POST request to /api/provider-models to save manually added models.
    • Added a POST request to /api/provider-models to save imported models.
    • Implemented handleDeleteModel to perform DELETE requests to /api/provider-models and delete aliases.
    • Modified the onDeleteAlias callback to use handleDeleteModel.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@nyatoru nyatoru changed the title feat: save compatible provider models to customModels DB for /v1/mode… feat: save compatible provider models to customModels DB for /v1/models listing Feb 24, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces functionality to persist compatible provider models in a custom database, ensuring they appear in the /v1/models listing, and integrates their saving and deletion across various workflows. While the feature is useful, the implementation has several security vulnerabilities. New API endpoints for managing provider models and aliases lack authentication and authorization checks, allowing unauthorized modification of system configuration. Furthermore, a URL parameter injection vulnerability exists in the model deletion logic due to improper encoding of user-controlled variables. These security issues must be addressed before merging.

Comment on lines 1543 to 1555
// Save to customModels DB so it shows up in /v1/models
await fetch("/api/provider-models", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
provider: providerStorageAlias,
modelId,
modelName: model.name || modelId,
source: "imported",
}),
});
// Also create alias for routing
await onSetAlias(modelId, resolvedAlias, providerStorageAlias);
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Similar to the manual add function, if the fetch call to save the imported model to the customModels database fails, the onSetAlias call still proceeds. This can result in an alias being created for a model that wasn't successfully recorded in the database, leading to data inconsistencies.

Ensure that the onSetAlias call is only executed if the model is successfully saved to the customModels database. This will prevent partial updates and maintain data integrity.

          // Save to customModels DB so it shows up in /v1/models
          const res = await fetch("/api/provider-models", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              provider: providerStorageAlias,
              modelId,
              modelName: model.name || modelId,
              source: "imported",
            }),
          });
          if (!res.ok) {
            const errorData = await res.json();
            throw new Error(errorData.error?.message || "Failed to save imported model to custom DB");
          }
          // Also create alias for routing
          await onSetAlias(modelId, resolvedAlias, providerStorageAlias);

try {
// Remove from customModels DB
await fetch(
`/api/provider-models?provider=${providerStorageAlias}&model=${encodeURIComponent(modelId)}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The providerStorageAlias variable is concatenated directly into the URL query string without proper encoding. Since providerStorageAlias is derived from the providerId URL parameter (which is user-controlled), an attacker could craft a malicious URL containing characters like & or = to inject additional query parameters into the API request, potentially manipulating the deletion logic (e.g., by injecting a different model parameter).

        `/api/provider-models?provider=${encodeURIComponent(providerStorageAlias)}&model=${encodeURIComponent(modelId)}`,

// Also delete the alias
await onDeleteAlias(alias);
} catch (error) {
console.log("Error deleting model:", error);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The handleDeleteModel function only logs errors to the console. For a user-facing action like deleting a model, it would be beneficial to provide visual feedback to the user if the deletion fails. This could be an alert, a toast notification, or an error message displayed on the UI.

Consider adding a user-friendly error notification to improve the user experience.

      console.error("Error deleting model:", error);
      alert("Failed to delete model. Please try again.");

@nyatoru
Copy link
Contributor Author

nyatoru commented Feb 24, 2026

@gemini-code-assist

@gemini-code-assist
Copy link
Contributor

Hello @nyatoru! I'm here to help. Do you have any specific questions about the pull request or my previous summary and review comments? Feel free to ask, or if you'd like me to perform another action, you can use commands like /gemini review for a new review or /gemini summary for an updated summary.

@nyatoru
Copy link
Contributor Author

nyatoru commented Feb 24, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant enhancements to model management and API security. Key changes include updating the ComboFormModal to match provider nodes by ID or prefix, and refactoring model addition and deletion logic in CompatibleModelsSection to first interact with a customModels database before managing aliases. A new handleDeleteModel function was added to ensure models are removed from both the database and alias system. Authentication has been added to several API routes (/api/models/alias and /api/provider-models) by introducing a verifyAuth function that checks for API keys or JWT cookies. The /api/v1/models endpoint now incorporates providerNodes to better handle custom model prefixes and activation checks for compatible providers. Model display in ModelSelectModal and model availability checks in chat.ts were updated to correctly resolve custom prefixes using getModelInfo. The getModelInfo service itself was refactored to prioritize checking custom provider nodes for both alias and non-alias model strings.

Review comments highlight several areas for improvement: the verifyAuth function is duplicated across multiple API routes and should be extracted into a shared utility; the variable providerPart in ComboFormModal could be renamed for better clarity; error handling for customModelRes.json() could be more explicit; and alert calls for user feedback should be replaced with a non-blocking notification system. Additionally, user-facing notifications are suggested for failed imported model saves and model deletions. Finally, the review questions the suitability of providerId as a fallback for nodePrefix if it's a UUID, and asks for assurance that prefixToCheck in getModelInfo is always a concise identifier.

Comment on lines 12 to 34
async function verifyAuth(request) {
// Check API key (for external clients)
const apiKey = extractApiKey(request);
if (apiKey && (await isValidApiKey(apiKey))) {
return true;
}

// Check JWT cookie (for dashboard session)
if (process.env.JWT_SECRET) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("auth_token")?.value;
if (token) {
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
await jwtVerify(token, secret);
return true;
}
} catch {
// Invalid/expired token or cookies not available
}
}

return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The verifyAuth function is duplicated across src/app/api/models/alias/route.ts and src/app/api/provider-models/route.ts. This leads to code duplication and makes maintenance harder. It would be better to extract this authentication logic into a shared utility function or middleware that can be imported and reused across different API routes. This improves maintainability and ensures consistent authentication logic.

/**
 * Verify authentication - check API key or JWT cookie
 */
// This function is duplicated. Consider moving it to a shared utility file.
// For example: import { verifyAuth } from "@/lib/authUtils";
async function verifyAuth(request) {
  // Check API key (for external clients)
  const apiKey = extractApiKey(request);
  if (apiKey && (await isValidApiKey(apiKey))) {
    return true;
  }

  // Check JWT cookie (for dashboard session)
  if (process.env.JWT_SECRET) {
    try {
      const cookieStore = await cookies();
      const token = cookieStore.get("auth_token")?.value;
      if (token) {
        const secret = new TextEncoder().encode(process.env.JWT_SECRET);
        await jwtVerify(token, secret);
        return true;
      }
    } catch {
      // Invalid/expired token or cookies not available
    }
  }

  return false;
}

Comment on lines 14 to 36
async function verifyAuth(request) {
// Check API key (for external clients)
const apiKey = extractApiKey(request);
if (apiKey && (await isValidApiKey(apiKey))) {
return true;
}

// Check JWT cookie (for dashboard session)
if (process.env.JWT_SECRET) {
try {
const cookieStore = await cookies();
const token = cookieStore.get("auth_token")?.value;
if (token) {
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
await jwtVerify(token, secret);
return true;
}
} catch {
// Invalid/expired token or cookies not available
}
}

return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The verifyAuth function is duplicated across src/app/api/models/alias/route.ts and src/app/api/provider-models/route.ts. This leads to code duplication and makes maintenance harder. It would be better to extract this authentication logic into a shared utility function or middleware that can be imported and reused across different API routes. This improves maintainability and ensures consistent authentication logic.

/**
 * Verify authentication - check API key or JWT cookie
 */
// This function is duplicated. Consider moving it to a shared utility file.
// For example: import { verifyAuth } from "@/lib/authUtils";
async function verifyAuth(request) {
  // Check API key (for external clients)
  const apiKey = extractApiKey(request);
  if (apiKey && (await isValidApiKey(apiKey))) {
    return true;
  }

  // Check JWT cookie (for dashboard session)
  if (process.env.JWT_SECRET) {
    try {
      const cookieStore = await cookies();
      const token = cookieStore.get("auth_token")?.value;
      if (token) {
        const secret = new TextEncoder().encode(process.env.JWT_SECRET);
        await jwtVerify(token, secret);
        return true;
      }
    } catch {
      // Invalid/expired token or cookies not available
    }
  }

  return false;
}

Comment on lines 1522 to +1523
console.log("Error adding model:", error);
alert(error instanceof Error ? error.message : "Failed to add model. Please try again.");
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The alert function is generally not recommended for user feedback in modern web applications, as it's blocking and can lead to a poor user experience. Consider using a more integrated notification system (like the notify.error used elsewhere in the codebase) to provide feedback to the user without interrupting their workflow.

      console.log("Error adding model:", error);
      // Use a non-blocking notification system instead of alert
      // notify.error(error instanceof Error ? error.message : "Failed to add model. Please try again.");
      alert(error instanceof Error ? error.message : "Failed to add model. Please try again.");

Comment on lines +1563 to +1564
if (!customModelRes.ok) {
console.error("Failed to save imported model to customModels DB");
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the previous comment, console.error is used here for an error that might be user-facing. While it's good for debugging, if this failure is due to user input or a known API issue, it might be better to provide user feedback through a notification system rather than just logging to the console. This ensures the user is aware of why the import failed.

          if (!customModelRes.ok) {
            console.error("Failed to save imported model to customModels DB");
            // Consider adding user-facing notification here, e.g., notify.error("Failed to save imported model.");
            return false;
          }

Comment on lines +1583 to +1595
const handleDeleteModel = async (modelId: string, alias: string) => {
try {
// Remove from customModels DB
await fetch(
`/api/provider-models?provider=${providerStorageAlias}&model=${encodeURIComponent(modelId)}`,
{ method: "DELETE" }
);
// Also delete the alias
await onDeleteAlias(alias);
} catch (error) {
console.log("Error deleting model:", error);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The handleDeleteModel function is well-structured. However, it only logs the error to the console. For a user-initiated action like deleting a model, it's important to provide feedback to the user if the deletion fails. Consider adding a user-facing notification (e.g., using notify.error) to inform the user about the failure.

  const handleDeleteModel = async (modelId: string, alias: string) => {
    try {
      // Remove from customModels DB
      await fetch(
        `/api/provider-models?provider=${providerStorageAlias}&model=${encodeURIComponent(modelId)}`,
        { method: "DELETE" }
      );
      // Also delete the alias
      await onDeleteAlias(alias);
      // notify.success("Model deleted successfully"); // Example user feedback
    } catch (error) {
      console.log("Error deleting model:", error);
      // notify.error("Failed to delete model. Please try again."); // Example user feedback
    }
  };

nyatoru and others added 5 commits February 24, 2026 21:19
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@nyatoru
Copy link
Contributor Author

nyatoru commented Feb 24, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request introduces significant improvements by enhancing model handling for custom providers, centralizing authentication logic, and refining the model import/delete processes. The changes improve flexibility and security across the application. However, there are a couple of minor issues that need to be addressed.

}
throw new Error(errorData.error?.message || "Failed to save custom model");
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

There's an extra closing brace } on this line. This will cause a syntax error and prevent the application from compiling or running correctly.

diegosouzapw added a commit that referenced this pull request Feb 24, 2026
- Fix URL parameter injection: apply encodeURIComponent on providerStorageAlias and providerId in all API calls
- Replace blocking alert() with non-blocking notify.error/notify.success toast notifications
- Add success feedback for model add and delete operations
- Improve error handling: use console.error consistently and add user-facing notifications for import failures
- Check DELETE response status before proceeding with alias removal
diegosouzapw added a commit that referenced this pull request Feb 24, 2026
…DB for /v1/models listing

Includes security hardening and UX improvements:
- Authentication on /api/provider-models via isAuthenticated
- URL parameter injection prevention (encodeURIComponent)
- Replaced alert() with notify.error/notify.success toasts
- Transactional save: DB first, then alias creation
- Consistent error handling across all model operations
@diegosouzapw diegosouzapw merged commit 6f7ba1f into diegosouzapw:main Feb 24, 2026
10 of 11 checks passed
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.

2 participants