feat(openrouter): add OpenRouter plugin with 13 operations - #635
feat(openrouter): add OpenRouter plugin with 13 operations#635Mayank-saraswal wants to merge 8 commits into
Conversation
|
@Mayank-saraswal is attempting to deploy a commit to the corsair Team on Vercel. A member of the Team first needs to authorize it. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR adds the ChangesOpenRouter integration
Estimated code review effort: 4 (Complex) | ~60 minutes Merge Risk: ⚪ Minimal · up to This PR adds the OpenRouter plugin and registration with reported validation, typecheck, build, and test checks passing; no actionable merge-blocking risk remains beyond normal review. Sequence Diagram(s)sequenceDiagram
participant CorsairRequest
participant OpenRouterPlugin
participant OpenRouterClient
participant OpenRouterAPI
CorsairRequest->>OpenRouterPlugin: invokes a registered endpoint
OpenRouterPlugin->>OpenRouterClient: passes endpoint path, API key, and request data
OpenRouterClient->>OpenRouterAPI: sends authenticated HTTP request
OpenRouterAPI-->>OpenRouterClient: returns JSON response or API error
OpenRouterClient-->>OpenRouterPlugin: returns typed result or wrapped error
OpenRouterPlugin-->>CorsairRequest: returns endpoint response
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 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 |
Greptile SummaryThe PR adds a first-class OpenRouter plugin and registers it with Corsair.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Sequence DiagramsequenceDiagram
participant App as Host application
participant Corsair as Corsair endpoint binding
participant Plugin as OpenRouter plugin
participant API as OpenRouter API
participant DB as Corsair entity database
App->>Corsair: Invoke openrouter.api operation
Corsair->>Corsair: Check permission and resolve API key
Corsair->>Plugin: Call typed endpoint with context
Plugin->>API: Bearer-authenticated HTTP request
API-->>Plugin: JSON response
opt Models, providers, or generation metadata
Plugin->>DB: Best-effort entity upsert
end
Plugin-->>Corsair: Return typed response
Corsair-->>App: Validated operation result
Reviews (6): Last reviewed commit: "fix(openrouter): cache models, providers..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (6)
packages/openrouter/tsup.config.ts (1)
10-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider disabling
minifyfor a library build.
minify: truewithsplitting: trueproduces unreadable chunk output. Consumers bundle this package themselves and lose readable stack traces. Most library packages leave minification to the consumer.🤖 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 `@packages/openrouter/tsup.config.ts` around lines 10 - 11, Disable minification in the tsup build configuration by changing the minify setting to false or removing it, while preserving code splitting so consumers can bundle readable library output themselves.packages/openrouter/error-handlers.ts (1)
56-74: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider retrying 408 and simplifying the 5xx check.
Two points:
- The header comment documents 408 as a request timeout, but no matcher handles it. A 408 falls to
DEFAULTwithmaxRetries: 0. Timeouts are usually safe to retry for the read-only GET operations.- Line 60 checks
error.status === 529aftererror.status >= 500 && error.status < 600. The second check is unreachable.🤖 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 `@packages/openrouter/error-handlers.ts` around lines 56 - 74, Update the SERVER_ERROR matcher in error-handling configuration to include HTTP 408 alongside the existing retryable server statuses, preserving the current retry strategy. Simplify the status condition by removing the redundant explicit 529 check, since the existing 5xx range already includes it.packages/openrouter/schema.test.ts (1)
9-20: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the tautological assertion and the dangling comment.
Line 12 asserts
Array.isArray(Object.keys(...)).Object.keysalways returns an array, so this assertion can never fail. Assert the entity count or the expected entity names instead.Lines 19-20 place a rule reference at file scope, but the endpoint tests live in
packages/openrouter/api.test.ts. Move the note there or delete it.🤖 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 `@packages/openrouter/schema.test.ts` around lines 9 - 20, Update the test around OpenrouterSchema.entities to replace the tautological Object.keys array assertion with a meaningful entity-count or expected-entity-name assertion, and remove the dangling file-scope PLUGIN_PR_RULES comment from schema.test.ts. If the rule reference is still needed, move it to the endpoint tests in api.test.ts.packages/openrouter/jest.config.cjs (1)
5-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the template leftovers from the config.
Three settings do not apply to this package:
- Lines 7-9 match
tests/,plugins/, andsetup/directories. This package contains onlyapi.test.tsandschema.test.tsat the root.- Line 16 excludes
jest.config.ts, but the config file isjest.config.cjs. The pattern never matches.- Line 51 exempts
uuidfromtransformIgnorePatterns. This package does not depend onuuid.Also applies to: 51-51
🤖 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 `@packages/openrouter/jest.config.cjs` around lines 5 - 18, Remove the unused `testMatch` entries for `tests`, `plugins`, and `setup` from the Jest configuration, leaving only the root `*.test.ts` pattern. Update `collectCoverageFrom` to exclude the actual `jest.config.cjs` filename, and remove the `uuid` exemption from `transformIgnorePatterns`.packages/openrouter/tsconfig.json (1)
17-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExclude the test files from the declaration build.
includecovers./**/*, soapi.test.tsandschema.test.tsproduce declaration files indist.package.jsonships the wholedistdirectory.♻️ Proposed change
"include": ["./**/*"], - "exclude": ["dist", "node_modules"], + "exclude": ["dist", "node_modules", "**/*.test.ts"],🤖 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 `@packages/openrouter/tsconfig.json` around lines 17 - 18, Update the packages/openrouter TypeScript configuration to exclude api.test.ts and schema.test.ts from declaration output while preserving the existing dist and node_modules exclusions. Ensure the test files remain available to the test tooling but are not emitted into the shipped dist directory.packages/openrouter/endpoints/types.ts (1)
496-562: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winVerify that the endpoint registries stay aligned with the plugin contract.
OpenRouterEndpointInputs,OpenRouterEndpointOutputs,OpenRouterEndpointInputSchemas, andOpenRouterEndpointOutputSchemaseach list the same 14 keys, and they matchOpenRouterEndpointsinpackages/openrouter/index.ts(Lines 65-80). Four parallel maps must be edited together for every new operation. Nothing in the type system enforces that today, because each map is declared independently.Consider deriving the type maps from the schema registries so that drift becomes a compile error.
♻️ Optional refactor
-export type OpenRouterEndpointInputs = { - chatCompletionsCreate: CreateChatCompletionInput; - // ... -}; +export type OpenRouterEndpointInputs = { + [K in keyof typeof OpenRouterEndpointInputSchemas]: z.infer< + (typeof OpenRouterEndpointInputSchemas)[K] + >; +};The same pattern applies to
OpenRouterEndpointOutputs. The registry constants must be declared before the type aliases.🤖 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 `@packages/openrouter/endpoints/types.ts` around lines 496 - 562, Refactor OpenRouterEndpointInputs and OpenRouterEndpointOutputs to derive their key sets and value types from OpenRouterEndpointInputSchemas and OpenRouterEndpointOutputSchemas, so registry drift becomes a compile-time error. Move both schema registry constants before the type aliases and use the existing schema inference conventions to preserve each operation’s input and output types. Keep the registries’ keys aligned with OpenRouterEndpoints.
🤖 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 `@packages/corsair/core/constants.ts`:
- Line 186: Update the openrouter entry in the provider display-name mapping to
use the official casing “OpenRouter”, ensuring formatProviderDisplayName returns
the corrected brand name.
In `@packages/openrouter/api.test.ts`:
- Around line 37-52: Update packages/openrouter/api.test.ts lines 37-52 so the
mocked makeOpenRouterRequest throws by default for unmocked calls, and import
the real client separately via jest.requireActual for the live suite; at lines
346-348 replace mockClear() with mockReset() to remove queued one-time values
before live tests. In packages/openrouter/README.md lines 59-61, retain the “no
API key” claim only once the mocked handler tests cannot reach the network.
In `@packages/openrouter/client.ts`:
- Around line 14-42: Update makeOpenRouterRequest to target the
LiteLLM-compatible llm.corsair.dev gateway instead of OPENROUTER_API_BASE, and
remove provider-specific OpenRouter bearer authentication using apiKey. Use the
Corsair-managed credential configuration required by the gateway while
preserving the existing request method, body, query, and generic response
handling.
In `@packages/openrouter/endpoints/credits.ts`:
- Around line 30-48: Remove the retired createCoinbaseCharge operation and all
related creditsCoinbaseCreate registrations, request/response schemas, types,
tests, and documentation. Ensure no Coinbase charge API path remains exposed,
and direct users to OpenRouter’s web-based credit purchase flow instead.
In `@packages/openrouter/endpoints/types.ts`:
- Around line 67-70: Remove the unsupported stream option from
CreateChatCompletionInputSchema, or reject stream: true in the corresponding
handler before invoking the non-streamed output validation. Ensure callers
cannot request streaming while CreateChatCompletionOutputSchema only supports
chat.completion responses with required usage.
- Around line 18-36: Update ChatMessageSchema’s assistant variant to accept an
optional tool_calls field using ToolCallSchema, and move ToolCallSchema’s
declaration before ChatMessageSchema so the reference resolves during module
evaluation. Preserve the existing optional content behavior and other
message-role variants.
- Around line 165-190: Widen the content block schema in
CreateAnthropicMessageOutputSchema to accept OpenRouter’s thinking,
redacted_thinking, and tool_use block types alongside text. Add explicit schemas
for those variants or a permissive fallback member while preserving validation
of existing text blocks.
In `@packages/openrouter/error-handlers.ts`:
- Around line 19-23: In the rate-limit matcher near the ApiError status check,
replace the broad message substring checks with matching anchored to the HTTP
status text or rely solely on ApiError.status, so unrelated values such as model
slugs, IDs, and durations do not match. In the matcher around the
invalid-message check, narrow the pattern to the intended status text and
prevent invalid_api_key from being classified as the invalid-request case.
In `@packages/openrouter/index.ts`:
- Around line 302-318: Clarify the intended precedence in the OpenRouter
keyBuilder: if tenant credentials must take priority, call
ctx.keys.get_api_key() before returning options.key and use the static key only
as fallback; otherwise preserve the current behavior and document in the README
that options.key overrides per-tenant keys.
- Around line 274-301: Update the OpenRouter model-call routing in the client
implementation to send requests through llm.corsair.dev instead of directly to
OpenRouter with ctx.key. Apply this to the model endpoints used by the
openrouter plugin while preserving the existing endpoint behavior and
authentication contract.
In `@packages/openrouter/package.json`:
- Line 19: Update the package.json test script to run Jest with Node’s
--experimental-vm-modules option, and change the corsair peer dependency range
from >=0.1.0 to ^0.1.0 to bound compatible versions.
In `@packages/openrouter/README.md`:
- Around line 63-77: Remove the “Live demo” section from the README until the
documented demo exists, including its environment-variable setup and pnpm
command; do not add a script or otherwise alter package.json.
- Around line 5-14: Update the “Auth setup” documentation to remove the
unsupported instruction to set OPENROUTER_API_KEY, and describe only the
credential sources handled by keyBuilder: options.key or Corsair credentials via
ctx.keys.get_api_key(). Keep the remaining authorization and missing-credentials
guidance unchanged.
---
Nitpick comments:
In `@packages/openrouter/endpoints/types.ts`:
- Around line 496-562: Refactor OpenRouterEndpointInputs and
OpenRouterEndpointOutputs to derive their key sets and value types from
OpenRouterEndpointInputSchemas and OpenRouterEndpointOutputSchemas, so registry
drift becomes a compile-time error. Move both schema registry constants before
the type aliases and use the existing schema inference conventions to preserve
each operation’s input and output types. Keep the registries’ keys aligned with
OpenRouterEndpoints.
In `@packages/openrouter/error-handlers.ts`:
- Around line 56-74: Update the SERVER_ERROR matcher in error-handling
configuration to include HTTP 408 alongside the existing retryable server
statuses, preserving the current retry strategy. Simplify the status condition
by removing the redundant explicit 529 check, since the existing 5xx range
already includes it.
In `@packages/openrouter/jest.config.cjs`:
- Around line 5-18: Remove the unused `testMatch` entries for `tests`,
`plugins`, and `setup` from the Jest configuration, leaving only the root
`*.test.ts` pattern. Update `collectCoverageFrom` to exclude the actual
`jest.config.cjs` filename, and remove the `uuid` exemption from
`transformIgnorePatterns`.
In `@packages/openrouter/schema.test.ts`:
- Around line 9-20: Update the test around OpenrouterSchema.entities to replace
the tautological Object.keys array assertion with a meaningful entity-count or
expected-entity-name assertion, and remove the dangling file-scope
PLUGIN_PR_RULES comment from schema.test.ts. If the rule reference is still
needed, move it to the endpoint tests in api.test.ts.
In `@packages/openrouter/tsconfig.json`:
- Around line 17-18: Update the packages/openrouter TypeScript configuration to
exclude api.test.ts and schema.test.ts from declaration output while preserving
the existing dist and node_modules exclusions. Ensure the test files remain
available to the test tooling but are not emitted into the shipped dist
directory.
In `@packages/openrouter/tsup.config.ts`:
- Around line 10-11: Disable minification in the tsup build configuration by
changing the minify setting to false or removing it, while preserving code
splitting so consumers can bundle readable library output themselves.
🪄 Autofix
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 Plus
Run ID: dcb25c43-06f1-4c96-96f0-adcfc45aab68
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
packages/corsair/core/constants.tspackages/openrouter/README.mdpackages/openrouter/api.test.tspackages/openrouter/client.tspackages/openrouter/endpoints/chat-completions.tspackages/openrouter/endpoints/credits.tspackages/openrouter/endpoints/embeddings.tspackages/openrouter/endpoints/generations.tspackages/openrouter/endpoints/index.tspackages/openrouter/endpoints/key.tspackages/openrouter/endpoints/messages.tspackages/openrouter/endpoints/model-endpoints.tspackages/openrouter/endpoints/models.tspackages/openrouter/endpoints/providers.tspackages/openrouter/endpoints/types.tspackages/openrouter/endpoints/zdr.tspackages/openrouter/error-handlers.tspackages/openrouter/index.tspackages/openrouter/jest.config.cjspackages/openrouter/package.jsonpackages/openrouter/schema.test.tspackages/openrouter/schema/index.tspackages/openrouter/tsconfig.jsonpackages/openrouter/tsup.config.ts
|
@greptileai review |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@packages/openrouter/api.test.ts`:
- Around line 886-893: Remove the OPENROUTER_API_KEY-gated live test setup and
its direct makeOpenRouterRequest usage in the “OpenRouter API type tests (live)”
suite. Route model validation through llm.corsair.dev using the existing LiteLLM
OpenAI-compatible gateway client, without provider SDK calls or direct provider
keys.
In `@packages/openrouter/endpoints/types.ts`:
- Line 275: Update the maxTokens schema definition to make the field optional
while requiring integer values of at least 1, matching the max_tokens input
contract. Add coverage for omitted, decimal, and zero maxTokens values.
🪄 Autofix
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 Plus
Run ID: 46caea7d-2dd2-4e72-96e4-c36656782353
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
packages/corsair/core/constants.tspackages/openrouter/README.mdpackages/openrouter/api.test.tspackages/openrouter/endpoints/credits.tspackages/openrouter/endpoints/embeddings.tspackages/openrouter/endpoints/index.tspackages/openrouter/endpoints/messages.tspackages/openrouter/endpoints/model-endpoints.tspackages/openrouter/endpoints/models.tspackages/openrouter/endpoints/types.tspackages/openrouter/error-handlers.tspackages/openrouter/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/openrouter/endpoints/embeddings.ts
- packages/openrouter/endpoints/model-endpoints.ts
- packages/corsair/core/constants.ts
- packages/openrouter/README.md
- packages/openrouter/endpoints/models.ts
- packages/openrouter/endpoints/messages.ts
- packages/openrouter/endpoints/index.ts
- packages/openrouter/index.ts
ambikeesshh
left a comment
There was a problem hiding this comment.
pushed fixes for the deprecated Coinbase operation, API contracts, tool and thinking flows, retry safety, tests, and docs
ambikeesshh
left a comment
There was a problem hiding this comment.
tightened chat maxTokens so 0/floats don’t get through. dropped coinbase from the description too
lgtm now
Fixes #634
Description
Adds a first-class OpenRouter plugin (
@corsair-dev/openrouter) exposing the full 13-operation surface claimed on the OSS dashboard:Chat & generation
chatCompletions.create—POST /chat/completions(OpenAI-compatible, with multi-provider routing, tool calling, structured output, reasoning)messages.create—POST /messages(Anthropic Messages API format)generations.get—GET /generation?id={id}Models
models.list—GET /models(pricing, context length, supported parameters)models.count—GET /models/countmodels.listEmbeddings—GET /embeddings/models(withoffset/limitpagination)models.listUser—GET /models/usermodelEndpoints.list—GET /models/{author}/{slug}/endpointsproviders.list—GET /providerszdr.list—GET /endpoints/zdrAccount
credits.list—GET /creditskey.get—GET /keyAll input/output types use Zod schemas, errors route through
error-handlers.ts(incl. 429 + Retry-After), and the footprint is exactly the plugin package + the registration edit inpackages/corsair/core/constants.ts+pnpm-lock.yaml.Verified live against the OpenRouter API (real key): every GET endpoint's response shape is validated in the live test suite; both chat-completion formats return the expected shapes.
pnpm run validate:pluginspasses for openrouter.Checklist
pnpm lintand all checks pass (openrouter files clean; repo-wide lint has pre-existing failures in unrelated packages)pnpm typecheckand there are no TypeScript errorspnpm buildand all packages build successfully (openrouter builds clean viatsc --build --force && tsup)pnpm testand all tests pass (43/43 in@corsair-dev/openrouter, incl. live API tests)Screenshots / Demos (if applicable)
Demo video showing the integration working end-to-end:
https://www.loom.com/share/5e7438d01bac4f76b6bcc351950b0f8b
Additional Notes
GET /embeddings/modelsis the actual embedding-models path,GET /models/{author}/{slug}/endpointsfor model endpoints).