Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add new provider OpenRouter #6324

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

wyfyjc
Copy link

@wyfyjc wyfyjc commented Mar 2, 2025

💻 变更类型 | Change Type

  • feat
  • fix
  • refactor
  • perf
  • style
  • test
  • docs
  • ci
  • chore
  • build

🔀 变更说明 | Description of Change

Add new provider OpenRouter

📝 补充信息 | Additional Information

Due to the excessive number of models provided by OpenRouter, only one model, anthropic/claude-3.7-sonnet, is built into constant.ts.

Summary by CodeRabbit

  • New Features

    • Enabled integration with OpenRouter as an additional service provider.
    • Added new configuration options for a custom API key and endpoint.
    • Introduced enhanced routing and API handling to support OpenRouter queries.
    • Updated the settings interface to include OpenRouter configuration fields.
    • Improved visual icon assignment for model identification.
  • Documentation

    • Expanded localization support with new labels and placeholders for OpenRouter in multiple languages.

Copy link

vercel bot commented Mar 2, 2025

@wyfyjc is attempting to deploy a commit to the NextChat Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Mar 2, 2025

Walkthrough

This pull request integrates support for the OpenRouter service. It adds new environment configuration entries and updates the server configuration to load these variables. The API routing is extended with a new case for OpenRouter along with a dedicated handler file. Client-side API classes and a new platform module are introduced to support OpenRouter calls. Additionally, UI components, locale strings, and state management in the access store are updated to incorporate settings and validations for OpenRouter.

Changes

File(s) Change Summary
.env.template Added new optional configuration entries: OPENROUTER_API_KEY and OPENROUTER_URL.
app/api/[provider]/[...path]/route.ts
app/api/auth.ts
app/api/openrouter.ts
Introduced OpenRouter API support by adding a new route case in the handler, new authentication branch, and a dedicated API handler file with handle and request functions.
app/client/api.ts
app/client/platforms/openrouter.ts
Integrated client-side support via a new OpenRouterApi class and corresponding initialization in ClientApi.
app/components/emoji.tsx
app/components/settings.tsx
Adjusted icon assignment logic to recognize OpenRouter model names and added a new settings component for OpenRouter configurations.
app/config/server.ts
app/constant.ts
Updated server configuration and constants/enums to include OpenRouter endpoints, environment variables, and default model entries.
app/locales/en.ts
app/locales/cn.ts
Added localization sections for OpenRouter’s API key and endpoint configuration.
app/store/access.ts Extended the access store with defaults and validation (DEFAULT_OPENROUTER_URL, openrouterApiKey, and isValidOpenRouter method) for OpenRouter integration.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant R as API Router
    participant H as OpenRouter Handler
    participant A as Auth Module
    participant X as External OpenRouter Service

    C->>R: Send request to /api/openrouter
    R->>H: Route to OpenRouter handler
    H->>A: Call authentication for OpenRouter
    A-->>H: Return auth status (success/failure)
    alt Auth success
        H->>X: Forward request to OpenRouter service
        X-->>H: Return response
        H-->>R: Return processed response
        R-->>C: Send final response
    else Auth failure
        H-->>C: Return 401 Unauthorized
    end
Loading

Poem

Hippity-hoppity, I’m a coding bunny,
My lines now dance with OpenRouter honey.
New routes and settings in a merry array,
Configs and keys light up my day.
With every code hop, joy does unfurl—
A rabbit’s delight in our evolving world!
🐇💻🌟

✨ Finishing Touches
  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 1

🔭 Outside diff range comments (2)
app/api/[provider]/[...path]/route.ts (1)

26-56: 💡 Verification agent

🧩 Analysis chain

Verify ApiPath.OpenRouter is defined in the constant file

The PR adds a handler for ApiPath.OpenRouter, but we should verify this constant is properly defined in the app/constant.ts file.


🏁 Script executed:

#!/bin/bash
# Check if OpenRouter is defined in the constant.ts file
grep -A 5 "ApiPath" app/constant.ts

Length of output: 178


Missing ApiPath.OpenRouter definition in app/constant.ts.
It appears that while a handler for ApiPath.OpenRouter has been added in the routing file, there is no corresponding enum entry in app/constant.ts. Please update the ApiPath enum to include a proper definition for OpenRouter (e.g., OpenRouter = "/api/openrouter") to ensure consistency.

app/client/api.ts (1)

254-313: 💡 Verification agent

🧩 Analysis chain

Consider adding OpenRouter to the API key selection logic.

The getConfig function doesn't include a case for OpenRouter when selecting the appropriate API key. This could potentially cause issues when the OpenRouter provider is selected.


🏁 Script executed:

#!/bin/bash
# Check if OpenRouter is handled in the access store
rg -A 5 "openrouterApiKey" --glob "*.ts" -i

Length of output: 1140


Action Required: Integrate OpenRouter into API Key Selection

The current implementation of getConfig in app/client/api.ts (lines 254–313) does not handle the OpenRouter provider. Our repository confirms that an openrouterApiKey is defined in the access store and is used in app/api/auth.ts, but it isn’t referenced in this selection chain. Please update the API key selection logic to include a case for when modelConfig.providerName is OpenRouter. For example, you might add:

  • A new condition like:
    const isOpenRouter = modelConfig.providerName === ServiceProvider.OpenRouter;
  • And update the apiKey selection chain to use:
    : isOpenRouter
        ? accessStore.openrouterApiKey

This change will ensure consistency across the codebase and proper handling of the OpenRouter provider.

🧹 Nitpick comments (9)
app/config/server.ts (1)

91-257: Documentation would enhance the OpenRouter implementation.

Consider adding a brief comment explaining what OpenRouter is and why it's being integrated, especially since the PR mentions only implementing one specific model ("anthropic/claude-3.7-sonnet").

 // openrouter only
+// OpenRouter is a unified API that provides access to various AI models, 
+// including those from Anthropic, OpenAI, and others.
+// Currently only anthropic/claude-3.7-sonnet model is integrated.
 OPENROUTER_URL?: string;
 OPENROUTER_API_KEY?: string;
app/components/settings.tsx (1)

1462-1503: Consider extracting repeated config blocks into a generic factory.
The newly introduced openRouterConfigComponent closely resembles configuration blocks for other providers. Refactoring all provider config components into a single, data-driven factory-style component could reduce code duplication and centralize maintenance.

-  // Example snippet: unify repeated config blocks
-  const openRouterConfigComponent = accessStore.provider === ServiceProvider.OpenRouter && (
-    <>
-      <ListItem ... >
-        <input ... />
-      </ListItem>
-      <ListItem ... >
-        <PasswordInput ... />
-      </ListItem>
-    </>
-  );
+  // Proposed pseudocode:
+  function renderProviderConfig(provider: ServiceProvider) {
+    const configs = [
+      { label: "Endpoint", stateKey: "xxxUrl", placeholder: "Example.com/..." },
+      { label: "ApiKey", stateKey: "xxxApiKey", placeholder: "sk-..." },
+      // ...
+    ];
+    return configs.map(({ label, stateKey, placeholder }) => (
+      <ListItem title={label} ...>
+        <PasswordInput or input
+          ...
+          value={accessStore[stateKey]}
+          placeholder={placeholder}
+          onChange={(e) => accessStore.update((st) => (st[stateKey] = e.currentTarget.value))}
+        />
+      </ListItem>
+    ));
+  }
app/api/openrouter.ts (2)

14-15: Limited ALLOWED_PATH ensures request security.
By restricting requests only to OpenRouter.ChatPath, this prevents unauthorized route access. If additional routes are introduced later, ensure that they are similarly whitelisted.


59-146: Suggest thorough testing and monitoring for long-running requests.

  1. A 10-minute timeout may be suitable for certain tasks, but if responses grow or concurrent requests are frequent, the server may consume resources excessively.
  2. Model filtering logic in lines 98–127 gracefully handles unapproved models with a 403. Continue maintaining a thorough test suite to verify correct handling of malformed request bodies.
  3. Final headers remove www-authenticate and disable buffering, ensuring a correct streaming response.
app/client/platforms/openrouter.ts (4)

65-70: Unify error handling in extractMessage(...).
Returning res outright when choices?.at(0)?.message?.content is missing can yield inconsistent return types. Consider returning a string or throwing an error to maintain consistent consumption patterns downstream.


72-74: Implement speech(...) method or remove placeholder.
This placeholder currently throws an error. If speech functionality is not immediately required, either remove the method or comment it with a clear roadmap.


105-109: Avoid hardcoding 4000 tokens for vision models.
Currently, max_tokens is forced to at least 4000 for vision models. This arbitrary limit may not be suitable for all usage scenarios and can unexpectedly inflate usage costs.


249-265: Provide a fallback or additional models in models().
Currently, only one model—“anthropic/claude-3.7-sonnet”—is returned. If longer-term expansion is planned, allow for dynamic retrieval from an API or configuration to avoid future manual updates.

app/constant.ts (1)

274-277: Document or allow overrides for OpenRouter.ChatPath.
Having ChatPath hardcoded to "v1/chat/completions" is valid for now, but future changes to the OpenRouter API or custom routing might require this core logic to be configurable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7cde17 and 636b234.

📒 Files selected for processing (13)
  • .env.template (1 hunks)
  • app/api/[provider]/[...path]/route.ts (2 hunks)
  • app/api/auth.ts (1 hunks)
  • app/api/openrouter.ts (1 hunks)
  • app/client/api.ts (3 hunks)
  • app/client/platforms/openrouter.ts (1 hunks)
  • app/components/emoji.tsx (1 hunks)
  • app/components/settings.tsx (3 hunks)
  • app/config/server.ts (3 hunks)
  • app/constant.ts (7 hunks)
  • app/locales/cn.ts (1 hunks)
  • app/locales/en.ts (1 hunks)
  • app/store/access.ts (5 hunks)
🔇 Additional comments (26)
.env.template (1)

85-89: Good addition of OpenRouter configuration variables

The OpenRouter API key and URL configuration entries are appropriately added with clear comments indicating they're optional. This matches the convention used for other service configurations in the file.

app/api/auth.ts (1)

107-109: Authorization handler properly added for OpenRouter

The OpenRouter case is correctly integrated into the existing switch statement, following the established pattern of other providers.

app/components/emoji.tsx (2)

67-70: Icon mapping properly updated for Anthropic models

Adding support for model names starting with "anthropic" for the Claude icon is appropriate, as OpenRouter may reference Anthropic models with this prefix.


74-77: Improved readability for Mistral model condition

The reformatting of the condition for Mistral models improves readability while maintaining the same functionality.

app/api/[provider]/[...path]/route.ts (2)

17-17: Correct import of OpenRouter handler

The import follows the established pattern for other API handlers.


54-55: OpenRouter API path case correctly added

The OpenRouter case is properly integrated into the existing switch statement, allowing the application to handle OpenRouter API requests.

app/client/api.ts (3)

27-27: Appropriate import for the new OpenRouter API integration.

The import follows the same pattern as other platform imports, maintaining consistency in the code organization.


177-179: Proper handler implementation for OpenRouter in the ClientApi constructor.

This implementation follows the established pattern for other providers, creating a new instance of the OpenRouterApi class when ModelProvider.OpenRouter is selected.


389-390: Complete the OpenRouter implementation in the getClientApi function.

The implementation correctly maps the ServiceProvider.OpenRouter to ModelProvider.OpenRouter, which is consistent with the pattern used for other providers.

app/locales/en.ts (1)

546-556: Good localization implementation for OpenRouter.

The localization strings for OpenRouter follow the same structure and pattern as other providers, including both API key and endpoint configuration options. This maintains consistency in the user interface.

app/locales/cn.ts (1)

537-547: Chinese localization implemented properly for OpenRouter.

The Chinese localization strings for OpenRouter match the structure and content of the English version, providing a consistent experience for Chinese users. The translations appear accurate and maintain the same informational content.

app/config/server.ts (3)

91-94: Proper environment variable declarations for OpenRouter.

The environment variables for OpenRouter (OPENROUTER_URL and OPENROUTER_API_KEY) are declared with correct types and follow the established pattern for other providers.


170-170: Server-side flag implementation for OpenRouter detection.

The isOpenRouter flag is implemented consistently with other provider flags, checking for the presence of the API key environment variable.


254-257: Configuration values exported for OpenRouter.

The server configuration correctly exports the OpenRouter-related values, including the flag, URL, and API key, following the same pattern as other providers.

app/components/settings.tsx (1)

78-78: No concerns regarding the OpenRouter import.
This import appropriately matches the newly introduced provider and is consistent with the existing import style.

app/store/access.ts (5)

20-20: Importing OPENROUTER_BASE_URL is aligned with other providers.
The new import follows the existing pattern for default URLs and ensures maintainability.


63-64: Default OpenRouter URL initialization is consistent.
Defining DEFAULT_OPENROUTER_URL mirrors the approach for other providers, supporting both app and API path usage.


138-141: Adding openrouterUrl and openrouterApiKey maintains store consistency.
The new fields match the pattern for storing provider-specific credentials and endpoints, ensuring uniform usage with other providers.


229-232: The introduced isValidOpenRouter() method is consistent with existing validations.
It follows the same pattern of ensuring that necessary keys are set. The approach is straightforward and easy to maintain.


252-252: Including isValidOpenRouter() in isAuthorized() properly integrates OpenRouter.
This addition ensures that OpenRouter credentials are recognized as a valid authorization source.

app/api/openrouter.ts (2)

1-13: Imports and initial definitions are well-structured.
They align with the project’s architecture, referencing updated constants and utilities for OpenRouter.


16-55: The handle function correctly restricts methods and enforces authentication.

  1. Returns 200 for OPTIONS requests, conforming to standard preflight handling.
  2. Blocks forbidden paths with a 403.
  3. Enforces authorization via the auth function, returning 401 on failure.
    This pattern prevents unauthorized usage and ensures robust security.
app/client/platforms/openrouter.ts (1)

32-63: Handle potential custom protocol edge cases in path(...).
The logic adequately checks whether baseUrl starts with "http" or `ApiPath.OpenRouter", but if a user specifies a protocol other than HTTP(S), it might be prepended with "https://". Consider whether to allow or prohibit alternative protocols, and clarify this handling in documentation.

app/constant.ts (3)

39-39: New OpenRouter constants and enum entries look good.
Defining OPENROUTER_BASE_URL, ApiPath.OpenRouter, and enumerating OpenRouter in ServiceProvider and ModelProvider is consistent and well-structured.

Also applies to: 77-77, 136-136, 163-163


663-666: Limiting built-in OpenRouter models.
Using a single built-in model simplifies maintenance. If more models are needed in the future, consider bundling them behind a configuration or discovery mechanism.


823-833: Seamless addition of openrouterModels to DEFAULT_MODELS.
This extension properly sets providerName: "OpenRouter" and aligns with the existing pattern for enumerating default models.

Comment on lines +160 to +164
// @ts-ignore
runTools[index]["function"]["arguments"] += args;
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Revisit the ts-ignore and string concatenation approach.
Doing runTools[index]["function"]["arguments"] += args; with ts-ignore can introduce hidden bugs. Consider properly typing these arguments or using a safer merge strategy to reduce reliance on ts-ignore.

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.

1 participant