feat: add OrcaRouter support and update version to 0.1.80#220
Conversation
- Introduced OrcaRouter API integration for chat and object generation. - Enhanced error handling for OrcaRouter API responses. - Updated environment variable management for OrcaRouter API keys. - Bumped supercode-cli version to 0.1.80 for new features and improvements.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
WalkthroughMiniMax BYOK configuration and selection were added. OrcaRouter now supports direct streaming and structured requests, API-key precedence, and proxy fallback when no key is configured. The server package version was incremented to 0.1.80. ChangesProvider support
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant ChatEndpoint
participant OrcaRouterAPI
participant UsageRecorder
Client->>ChatEndpoint: provider orcarouter request
ChatEndpoint->>OrcaRouterAPI: streaming chat completion
OrcaRouterAPI-->>ChatEndpoint: SSE text, tool calls, and usage
ChatEndpoint->>UsageRecorder: token usage and computed cost
ChatEndpoint-->>Client: NDJSON text, tool-call, and finish events
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
apps/supercode-cli/server/src/cli/ai/provider.ts (1)
87-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate proxy-provider construction for
supercodeandorcarouter.The new
orcarouterfallback branch (Lines 87-99) is structurally identical to the existingsupercodebranch (Lines 72-86), differing only in the provider name and comment. Consider extracting a small helper (e.g.,buildProxyProvider(providerName, model, meta)) to avoid the duplication going forward.♻️ Example helper extraction
+function buildProxyProvider(providerName: ModelProvider, model: string | undefined, meta: { defaultModel: string }): AIProvider { + const svc = new ServerProxyService(providerName, model || meta.defaultModel) + return { + name: providerName, + modelName: model || meta.defaultModel, + connectionType: "proxy", + sendMessage: (messages, onChunk, tools, onToolCall, signal, onReasoning, onToolResult, onStepFinish) => + svc.sendMessage(messages, onChunk, tools, onToolCall, signal, onReasoning, onToolResult, onStepFinish), + generateObject: (schema, prompt) => svc.generateObject(schema, prompt), + } +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/supercode-cli/server/src/cli/ai/provider.ts` around lines 87 - 99, Extract the duplicated proxy-provider construction from the existing supercode and orcarouter branches into a shared helper, such as buildProxyProvider, accepting the provider name, model, and meta. Have both branches call the helper while preserving their provider-specific fallback behavior and comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/supercode-cli/server/src/cli/ai/provider.ts`:
- Line 58: Add a case for "minimax" in createProvider(), constructing and
returning MinimaxService with the resolved providerConfigs.minimax key. Preserve
the existing no-key validation and default error behavior for other providers.
In `@apps/supercode-cli/server/src/index.ts`:
- Around line 1166-1188: The non-streaming OrcaRouter request in the
“orcarouter” case lacks the required timeout. Update its fetch call to use the
same timeout mechanism and duration as the streaming OrcaRouter handler,
preserving the existing request and response handling.
- Around line 692-701: Update the OrcaRouter fetch call in the request handler
to use an AbortSignal with a finite timeout, ensuring hung or unreachable
streaming requests are aborted and handled through the existing error path.
Preserve the current request payload, headers, and non-OK response handling.
- Around line 763-766: Update the final finish event in the streaming response
to use the actual OrcaRouter finish_reason captured during streaming instead of
hardcoding "stop". Preserve the existing usage payload and ensure the streamed
reason is propagated for cases such as "length" and "content_filter".
---
Nitpick comments:
In `@apps/supercode-cli/server/src/cli/ai/provider.ts`:
- Around line 87-99: Extract the duplicated proxy-provider construction from the
existing supercode and orcarouter branches into a shared helper, such as
buildProxyProvider, accepting the provider name, model, and meta. Have both
branches call the helper while preserving their provider-specific fallback
behavior and comments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9de46f97-3bf6-4112-8823-3069f2e53e5f
📒 Files selected for processing (6)
apps/supercode-cli/server/package.jsonapps/supercode-cli/server/src/cli/ai/provider.tsapps/supercode-cli/server/src/cli/commands/slashCommands/connect.tsapps/supercode-cli/server/src/config/orcarouter.config.tsapps/supercode-cli/server/src/index.tsapps/supercode-cli/server/src/lib/cli-config.ts
| supercode: () => "", | ||
| google: () => process.env.GOOGLE_BYOK_PROD_KEY || process.env.GOOGLE_BYOK_DEV_KEY || config.googleApiKey, | ||
| minimax: () => minimaxConfig.apiKey, | ||
| minimax: () => process.env.MINIMAX_BYOK_PROD_KEY || process.env.MINIMAX_BYOK_DEV_KEY || minimaxConfig.apiKey, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm whether provider.ts routes "minimax" to a direct service.
rg -n 'case "minimax"' apps/supercode-cli/server/src/cli/ai/provider.ts
rg -n 'MinimaxService' apps/supercode-cli/server/src/cli/ai/provider.ts
ast-grep run --pattern 'switch ($P) { $$$ }' --lang ts apps/supercode-cli/server/src/cli/ai/provider.tsRepository: yashdev9274/supercli
Length of output: 6657
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,240p' apps/supercode-cli/server/src/cli/ai/provider.ts
printf '\n--- connect.ts ---\n'
sed -n '1,220p' apps/supercode-cli/server/src/cli/ai/connect.ts
printf '\n--- minimax-service.ts ---\n'
sed -n '1,220p' apps/supercode-cli/server/src/cli/ai/minimax-service.tsRepository: yashdev9274/supercli
Length of output: 9268
Add a minimax switch branch
providerConfigs.minimax now returns a BYOK/config key, but createProvider() has no case "minimax". With a valid key, this skips the no-key path and falls through to the default "paused or unavailable" error. Wire MinimaxService into the switch so MiniMax can actually be selected.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/supercode-cli/server/src/cli/ai/provider.ts` at line 58, Add a case for
"minimax" in createProvider(), constructing and returning MinimaxService with
the resolved providerConfigs.minimax key. Preserve the existing no-key
validation and default error behavior for other providers.
| const response = await fetch("https://api.orcarouter.ai/v1/chat/completions", { | ||
| method: "POST", | ||
| headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }, | ||
| body: JSON.stringify(bodyObj), | ||
| }) | ||
| if (!response.ok) { | ||
| const errText = await response.text().catch(() => "unknown error") | ||
| res.status(response.status).json({ error: `OrcaRouter API ${response.status}: ${errText}` }) | ||
| return | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
No timeout on the OrcaRouter fetch call.
The streaming request to https://api.orcarouter.ai/v1/chat/completions has no AbortSignal/timeout. If OrcaRouter hangs or is unreachable, this request-handling thread can block indefinitely, tying up server resources with no way for the client to recover other than disconnecting.
🛡️ Suggested fix
+ const controller = new AbortController()
+ const timeoutId = setTimeout(() => controller.abort(), 60_000)
const response = await fetch("https://api.orcarouter.ai/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
body: JSON.stringify(bodyObj),
+ signal: controller.signal,
})
+ clearTimeout(timeoutId)📝 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.
| const response = await fetch("https://api.orcarouter.ai/v1/chat/completions", { | |
| method: "POST", | |
| headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }, | |
| body: JSON.stringify(bodyObj), | |
| }) | |
| if (!response.ok) { | |
| const errText = await response.text().catch(() => "unknown error") | |
| res.status(response.status).json({ error: `OrcaRouter API ${response.status}: ${errText}` }) | |
| return | |
| } | |
| const controller = new AbortController() | |
| const timeoutId = setTimeout(() => controller.abort(), 60_000) | |
| const response = await fetch("https://api.orcarouter.ai/v1/chat/completions", { | |
| method: "POST", | |
| headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }, | |
| body: JSON.stringify(bodyObj), | |
| signal: controller.signal, | |
| }) | |
| clearTimeout(timeoutId) | |
| if (!response.ok) { | |
| const errText = await response.text().catch(() => "unknown error") | |
| res.status(response.status).json({ error: `OrcaRouter API ${response.status}: ${errText}` }) | |
| return | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/supercode-cli/server/src/index.ts` around lines 692 - 701, Update the
OrcaRouter fetch call in the request handler to use an AbortSignal with a finite
timeout, ensuring hung or unreachable streaming requests are aborted and handled
through the existing error path. Preserve the current request payload, headers,
and non-OK response handling.
| res.write(JSON.stringify({ | ||
| type: "finish", reason: "stop", | ||
| usage: { inputTokens, outputTokenDetails: { textTokens: outputTokens, reasoningTokens: 0 }, outputTokens, inputTokenDetails: { noCacheTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }, totalTokens: inputTokens + outputTokens } | ||
| }) + "\n") |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Finish reason always reported as "stop".
The final finish event hardcodes reason: "stop" regardless of the actual finish_reason streamed by OrcaRouter (e.g., "length" or "content_filter"). Callers lose the ability to distinguish a truncated response from a normal completion.
🐛 Suggested fix
+ let lastFinishReason = "stop"
while (true) {
...
const finishReason = data.choices?.[0]?.finish_reason
+ if (finishReason) lastFinishReason = finishReason
if (finishReason === "tool_calls") {
...
res.write(JSON.stringify({
- type: "finish", reason: "stop",
+ type: "finish", reason: lastFinishReason === "tool_calls" ? "tool-calls" : lastFinishReason,📝 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.
| res.write(JSON.stringify({ | |
| type: "finish", reason: "stop", | |
| usage: { inputTokens, outputTokenDetails: { textTokens: outputTokens, reasoningTokens: 0 }, outputTokens, inputTokenDetails: { noCacheTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }, totalTokens: inputTokens + outputTokens } | |
| }) + "\n") | |
| res.write(JSON.stringify({ | |
| type: "finish", reason: lastFinishReason === "tool_calls" ? "tool-calls" : lastFinishReason, | |
| usage: { inputTokens, outputTokenDetails: { textTokens: outputTokens, reasoningTokens: 0 }, outputTokens, inputTokenDetails: { noCacheTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }, totalTokens: inputTokens + outputTokens } | |
| }) + "\n") |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/supercode-cli/server/src/index.ts` around lines 763 - 766, Update the
final finish event in the streaming response to use the actual OrcaRouter
finish_reason captured during streaming instead of hardcoding "stop". Preserve
the existing usage payload and ensure the streamed reason is propagated for
cases such as "length" and "content_filter".
| case "orcarouter": { | ||
| const apiKey = process.env.ORCAROUTER_API_KEY | ||
| if (!apiKey) { res.status(500).json({ error: "OrcaRouter not configured on server" }); return } | ||
| const modelName = modelParam || "openai/gpt-4o-mini" | ||
| const response = await fetch("https://api.orcarouter.ai/v1/chat/completions", { | ||
| method: "POST", | ||
| headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }, | ||
| body: JSON.stringify({ | ||
| model: modelName, | ||
| messages: [{ role: "user", content: prompt }], | ||
| max_tokens: getModelMaxTokens(modelName), | ||
| stream: false, | ||
| }), | ||
| }) | ||
| if (!response.ok) { | ||
| const errText = await response.text().catch(() => "unknown error") | ||
| res.status(response.status).json({ error: `OrcaRouter API ${response.status}: ${errText}` }) | ||
| return | ||
| } | ||
| const data: any = await response.json() | ||
| res.json({ object: { content: data.choices?.[0]?.message?.content || "" } }) | ||
| break | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Non-streaming OrcaRouter call also lacks a timeout — shares root cause with the streaming handler.
See the fetch-timeout comment on Lines 692-701 (same issue, same fix pattern applies here).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/supercode-cli/server/src/index.ts` around lines 1166 - 1188, The
non-streaming OrcaRouter request in the “orcarouter” case lacks the required
timeout. Update its fetch call to use the same timeout mechanism and duration as
the streaming OrcaRouter handler, preserving the existing request and response
handling.
Description
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes.
bun testpassesbun run typecheckpassesbun run lintpasses (if applicable)Checklist:
Summary by CodeRabbit
New Features
Improvements