Conversation
…Dashboard, Notification System, Cross-Transport Fallback, 5 new providers, Kiro fix, Responses accumulator, dead code cleanup Features: - Dollar Savings Tracker (hero card + per-mechanism breakdown) - Provider Performance Leaderboard (sortable, TTFT/P95/cost/success) - SSE Live Dashboard (unified stream + auto-reconnect hook) - In-App Notification System (bell + unread badge + history) - Cross-Transport Fallback (OpenAI timeout -> Anthropic auto-retry) - New providers: Bynara, InxoraStudio (API + Web), Infron AI, AgentRouter - Updated: Command Code (standard API), Grok Web quota, Infron quota - Quota trackers: Grok Web rate-limits, Infron credit balance Fixes: - Kiro REQUEST_BODY_INVALID (level suffix normalization) - Responses API accumulator (alias-safe + exactly-once terminal) - Antigravity model turn 400 + tier routing + Cloud Code endpoints - Circuit breaker releaseBreakerProbe ReferenceError - Combo stickyLimit key + comboStrategies deep-merge - Notification spam (health_update filtered) + raw JSON + duplicates - hcnsec model discovery + WEB_COOKIE_PROVIDERS modelsFetcher Improvements: - Dead code cleanup (12 files, 1,705 LOC) - Junk dependency removed (fs placeholder) - Authenticated model discovery proxy Bumps package.json + cli/package.json to 0.7.6
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
📝 WalkthroughWalkthroughVersion 0.7.6 adds provider integrations, cross-transport fallback, Responses stream accumulation, Kiro thinking normalization, dashboard metrics and SSE updates, persistent notifications, authenticated model discovery, and release cleanup. ChangesCore streaming and routing
Dashboard and provider UI
Release maintenance
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 20
🧹 Nitpick comments (9)
src/lib/db/repos/usageRepo.js (1)
329-362: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low valueReuse the pricing lookup once —
getPricingForModel()is synchronous here, so the unawaited calls inside the transaction are fine. Resolve it once and reuse it in both savings blocks.🤖 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 `@src/lib/db/repos/usageRepo.js` around lines 329 - 362, Resolve getPricingForModel(entry.provider, entry.model) once before the overall savings processing, then reuse that pricing value in both the total costSavedLifetime block and the per-mechanism cost calculation. Remove the duplicate lookup assigned to mechPricing while preserving the existing pricing checks and savings updates.open-sse/config/kiroConstants.js (2)
1-1: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winUnclear/untested handling of the
"none"thinking override.applyKiroThinkingOverridesetsoutput_config.effortto the literal"none"for a(none)/(off)suffix, a value outside the documented effort enum, and no test confirms how this round-trips throughextractThinking/resolveKiroThinkingBudget.
open-sse/config/kiroConstants.js#L296-313: confirm (or special-case, similar to the"budget"branch) howoverride.mode === "none"is meant to disable thinking without emitting a non-enumeffortvalue.tests/unit/kiro-thinking-normalization.test.js#L67-96: once the intended behavior is confirmed, add a test assertingapplyKiroThinkingOverride(body, { mode: "none" })produces the expected, budget-resolvable result.🤖 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 `@open-sse/config/kiroConstants.js` at line 1, Clarify and implement the mode-none behavior in applyKiroThinkingOverride so disabling thinking does not emit the unsupported effort value "none"; align it with the existing budget handling and ensure extractThinking/resolveKiroThinkingBudget can resolve the result correctly. Add coverage in the Kiro thinking normalization tests asserting applyKiroThinkingOverride with mode "none" produces the intended budget-resolvable body.
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFamily classification duplicated in two places using two different mechanisms.
resolveKiroEffortPath(regex) andPATTERN_THINKING(glob) both classify Claude-5/GPT-5.6 vs. everything else; keeping them in sync manually risks drift as new model families are added.
open-sse/config/kiroConstants.js#L254-263: keep as the single source of truth for family classification (and tighten the\bboundary per the earlier comment).open-sse/providers/thinkingLevels.js#L29-38,54-69: dropPATTERN_THINKING's redundant glob re-match and returnL.KIRO_NATIVEdirectly onceresolveKiroEffortPathconfirms the family, instead of re-deriving it via a second pattern list.🤖 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 `@open-sse/config/kiroConstants.js` at line 1, Use resolveKiroEffortPath as the sole source of truth for model-family classification, tightening its word-boundary matching as required. In the thinking-level resolution flow, remove PATTERN_THINKING and its redundant glob matching; once resolveKiroEffortPath confirms the supported family, return the KIRO_NATIVE constant directly. Keep existing behavior for models that do not resolve to that family.open-sse/providers/thinkingLevels.js (1)
29-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate family classification vs.
resolveKiroEffortPath.
PATTERN_THINKING's glob patterns re-encode the same Claude-5/GPT-5.6 family classification thatresolveKiroEffortPath(inkiroConstants.js) already computes via regex.getThinkingLevelscalls both: firstresolveKiroEffortPathto gate, thenPATTERN_THINKING.findto pick levels — two independent lists that must stay in sync manually.♻️ Proposed consolidation
export function getThinkingLevels(provider, model) { - // Kiro gate FIRST: only Claude 5 / GPT-5.6 families advertise native levels. - // resolveKiroEffortPath returns null for everything else → hide the picker. - if (provider === "kiro" && resolveKiroEffortPath(model) === null) return null; - - const caps = getCapabilitiesForModel(provider, model); - if (!caps.reasoning) return null; - - // Pattern match for Kiro native families. - const hit = PATTERN_THINKING.find((p) => matchPattern(p.pattern, model)); - if (hit) return hit.levels; + if (provider === "kiro") { + const path = resolveKiroEffortPath(model); + if (path === null) return null; + return L.KIRO_NATIVE; + } + + const caps = getCapabilitiesForModel(provider, model); + if (!caps.reasoning) return null;Also applies to: 54-69
🤖 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 `@open-sse/providers/thinkingLevels.js` around lines 29 - 38, Remove the duplicated Claude-5/GPT-5.6 family patterns from PATTERN_THINKING and update getThinkingLevels to derive the supported thinking levels from the result of resolveKiroEffortPath. Preserve the existing gating and KIRO_NATIVE level behavior while ensuring family classification has a single source of truth.open-sse/handlers/chatCore.js (2)
440-447: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDead
AbortErrorbranches.
AbortErroralready returned at line 430-433, so botherror.name === "AbortError"ternaries here always evaluate to theBAD_GATEWAY/502arm. Simplify to constants to avoid implying a reachable 499 path.🤖 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 `@open-sse/handlers/chatCore.js` around lines 440 - 447, In the failure logging block after the early AbortError return, update the status in appendRequestLog and the response.status in buildRequestDetail to use the constant BAD_GATEWAY/502 values directly. Remove both unreachable error.name === "AbortError" ternaries while preserving the existing error message and request-detail fields.
486-528: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winBoth branches duplicate the same ~15-line error-return block.
Lines 493-508 and 512-527 are byte-identical apart from
trackPendingRequestordering. Extract one localreturnUpstreamError(statusCode, message, resetsAtMs)closure and call it from both branches so future changes to error logging/detail persistence can't diverge.🤖 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 `@open-sse/handlers/chatCore.js` around lines 486 - 528, Extract the duplicated upstream error handling in the surrounding request flow into a local returnUpstreamError(statusCode, message, resetsAtMs) closure, including tracking, request logging, detail persistence, formatting, console logging, and createErrorResult. Replace both the recovered=false 5xx/transport-failure path and the 4xx path with calls to this closure, preserving their existing control flow and parameters.open-sse/utils/responsesStreamHelpers.js (1)
34-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the
stream_disconnectederror payload into a shared constant.The same
{ type, code, message }triple is now literal in bothbuildAbortedResponsesTerminalBytesandformatIncompleteOpenAIResponsesStreamFailure(lines 53-57); they can silently drift so the SSE payload and the accumulator's recorded error disagree.♻️ Suggested consolidation
+const STREAM_DISCONNECTED_ERROR = { + type: "stream_error", + code: "stream_disconnected", + message: "stream closed before response.completed", +}; + export function buildAbortedResponsesTerminalBytes(accumulator = null) { if (accumulator) { accumulator.finalize({ - error: { type: "stream_error", code: "stream_disconnected", message: "stream closed before response.completed" }, + error: { ...STREAM_DISCONNECTED_ERROR }, status: "failed", }); }Then reuse
STREAM_DISCONNECTED_ERRORinsideformatIncompleteOpenAIResponsesStreamFailure.As per coding guidelines, "never hardcode values" and keep the code DRY using constants from
config/.🤖 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 `@open-sse/utils/responsesStreamHelpers.js` around lines 34 - 41, Extract the shared `{ type: "stream_error", code: "stream_disconnected", message: "stream closed before response.completed" }` payload into a named constant in the appropriate config/constants module, then reuse that constant in both `buildAbortedResponsesTerminalBytes` and `formatIncompleteOpenAIResponsesStreamFailure` so the accumulator error and SSE response remain identical.Source: Coding guidelines
open-sse/executors/inxorastudio-web.js (1)
58-131: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd a request timeout to both upstream calls.
Only
signalis forwarded; a hunglabs.inxorastudio.comresponse blocks the request path indefinitely. Compose the caller signal with a timeout (AbortSignal.any([signal, AbortSignal.timeout(ms)])) using the shared timeout constant.🤖 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 `@open-sse/executors/inxorastudio-web.js` around lines 58 - 131, Update execute’s upstream fetch calls, including the conversation creation request and the later generation request, to compose the caller’s signal with AbortSignal.timeout using the shared timeout constant. Pass the composed signal to proxyAwareFetch while preserving caller cancellation and existing AbortError handling.tests/unit/responses-accumulator.test.js (1)
118-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the terminal-snapshot merge path.
Current suite never exercises
response.completedcarrying anoutputarray after deltas, nor afunction_callitem without anargumentsfield — both are where_ingestFullItemmisbehaves today (clobberedargsBuffer,'""'arguments). Also worth coveringfinalize()exactly-once andpreferCompletedisagreement between deltas and snapshot.🤖 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 `@tests/unit/responses-accumulator.test.js` around lines 118 - 132, Extend the response.completed tests around ResponsesAccumulator to cover merging a terminal output snapshot after prior deltas, including function_call items without arguments, preserving buffered arguments and avoiding synthesized empty-string arguments. Add assertions that finalize() is idempotent and that preferComplete resolves disagreements between delta data and the terminal snapshot as intended.
🤖 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 `@open-sse/executors/inxorastudio-web.js`:
- Around line 24-26: Update the inxorastudio-web executor to remove hardcoded
API_BASE, USER_AGENT, default model, and request mode values. Source the host
from the inxorastudio-web registry transport.baseUrl, the model from
config/providerModels.js, and the user-agent and mode from the existing
config/schema constants; reuse those values at the affected request and payload
construction points while preserving current behavior.
- Around line 245-251: Update the usage guard in the assistant token handling
block to use explicit presence checks for inputTokens and outputTokens rather
than truthiness, so zero-valued counts still populate finalChunk.usage. Preserve
the existing prompt_tokens, completion_tokens, and total_tokens assignments.
- Around line 258-263: Update the stream lifecycle around the catch/finally
handling in the executor’s start flow: do not enqueue SSE_DONE or close the
controller after controller.error(err), and ensure the upstream reader is
released or cancelled when the abort path breaks. Preserve normal completion
behavior by sending SSE_DONE and closing only while the controller remains
usable, without masking the original error.
In `@open-sse/handlers/chatCore.js`:
- Around line 375-393: Restore credentials.runtimeTransport to originalTransport
in the alternate non-OK branch before returning false, matching the catch-path
cleanup. Also consume or cancel altResult.response.body there so the failed
alternate response does not retain its socket.
In `@open-sse/providers/registry/agentrouter.js`:
- Line 43: Update the comment above the multi-endpoint configuration to
accurately describe the Claude base URL as the full /v1/messages endpoint, and
remove the claim that the SDK appends /v1/messages. Leave the endpoint
configuration unchanged.
In `@open-sse/providers/registry/bynara.js`:
- Around line 26-30: Remove the referral query parameter from both signupUrl and
apiKeyUrl in the notice configuration, leaving the links pointed at the plain
Bynara registration URL. Keep the existing notice text and other provider
settings unchanged.
In `@open-sse/providers/registry/glm.js`:
- Around line 36-39: Restore the GLM Coding Plan endpoint in the registry
entry’s baseUrl to /api/coding/paas/v4/chat/completions. Do not route
coding-plan keys through the standard /api/paas/v4 endpoint; if supporting both
key types, branch explicitly by key type while preserving the coding-plan URL.
In `@open-sse/translator/concerns/responsesAccumulator.js`:
- Around line 437-442: Update toolCallIndexFor to deduplicate aliases by their
underlying tool-entry identity before calculating the index, so equivalent
item_id and output_index references resolve to the same position. Preserve the
existing fallback of toolKeys.length when resolution fails, and ensure the index
used by openai-responses.js remains stable across header and delta events.
- Around line 277-299: Update _ingestFullItem to preserve an existing streamed
tool entry instead of overwriting it: reuse the entry, apply the existing
preferComplete behavior, and ensure _toolsByItemId and _toolsByCallId aliases
are registered for late deltas and lookups. When initializing arguments from a
full item with no arguments, use an empty string rather than JSON-stringifying a
fallback that produces "\"\""; retain valid streamed arguments and existing
message handling.
In `@open-sse/translator/response/openai-responses.js`:
- Around line 524-541: Update the terminal-event handling around
computeFinishReason so response.incomplete produces a normal terminal chunk
without injected error content, using computeFinishReason to preserve the LENGTH
mapping and including available usage. Restrict the existing error chunk with
STOP and error text to error, response.failed, and response.cancelled, while
preserving the exactly-once finish guard.
- Around line 487-494: Update the response.output_item.done handling in the
function-call branch to emit the complete arguments from data.item when no
argument deltas were streamed for that item, using state.argsStreamed as the
guard. Preserve exactly-once behavior by checking acc.isToolCallEmitted and
marking the item emitted after emitting or confirming the existing streamed
path; do not return null before the done-only arguments can reach the client.
In `@src/app/`(dashboard)/dashboard/overview/components/LeaderboardTable.js:
- Around line 49-56: Update the leaderboard fetch effect keyed by period to
avoid calling setLoading(true) directly in the effect body, while preserving
loading during the request and the existing setLoading(false) cleanup behavior.
Use an established lint-compliant state or fetch pattern without changing the
data/error handling flow.
In `@src/app/`(dashboard)/dashboard/providers/[id]/InxoraProfile.js:
- Line 17: Update the response returned by the inxora-profile API route to omit
the apiKey field before serialization, while preserving the profile data
consumed by InxoraProfile. Locate the response construction in the route handler
for /api/providers/[id]/inxora-profile and remove only the credential from its
returned payload.
- Around line 18-24: Update the profile-loading flow around the response check
so loading always finishes when the fetch response is unsuccessful, including
401/404/500 responses. Ensure the existing cancellation guard is preserved and
the setLoading(false) call in the InxoraProfile effect remains reachable before
returning from the failed-response path.
In `@src/app/`(dashboard)/dashboard/providers/[id]/page.js:
- Around line 436-441: Update the useEffect that invokes fetchSuggestedModels to
clear suggestedModels when no modelsFetcher exists, and guard asynchronous
results with an invalidation or cancellation mechanism so only the latest
provider/connection request can call setSuggestedModels. Ensure cleanup
invalidates the previous request when the effect reruns or unmounts.
In `@src/app/api/providers/`[id]/inxora-profile/route.js:
- Around line 9-48: Update GET to authenticate the caller and retrieve the
provider connection through an owner-scoped lookup, rejecting unauthenticated or
unauthorized requests before contacting the upstream API. In the response
construction around data.user, remove u.apiKey and return only a masked or
non-secret indicator if required by the UI; preserve the existing profile fields
and status handling.
- Around line 19-26: Update the upstream fetch in the inxora profile route to
use an AbortController with a configurable, bounded timeout, ensuring the timer
is cleaned up after completion. Catch aborts caused by this deadline and return
the route’s controlled upstream-timeout error while preserving existing handling
for other fetch failures.
In `@src/app/api/providers/suggested-models/route.js`:
- Around line 40-65: Update the suggested-models route’s connectionId/url
handling to avoid sending stored credentials to caller-controlled destinations:
authenticate and authorize the connection owner, resolve the models URL and
filter type from the trusted provider configuration, and validate the resolved
destination against its configured allowlist before fetching. Reject or omit
caller-supplied destinations that do not match the authorized configuration,
while preserving unauthenticated behavior only where no connection is selected.
In `@src/app/api/providers/validate/route.js`:
- Around line 642-649: Add a timeout to the upstream fetch in the Inxora
validation branch, using the handler’s existing bounded-probe pattern and
timeout configuration where available. Update the fetch options around the
Inxora validation request while preserving its method and headers, ensuring
stalled requests abort rather than holding validation indefinitely.
In `@src/shared/components/NotificationBell.js`:
- Around line 33-53: Align NOTIFIABLE_TYPES in the NotificationBell effect with
the event types emitted by /api/dashboard/stream: remove rate_limited,
budget_exceeded, and health_degraded unless the stream is updated to forward
them. Ensure the set and related filtering reflect the actual SSE types,
preserving provider_down and provider_recovered handling.
---
Nitpick comments:
In `@open-sse/config/kiroConstants.js`:
- Line 1: Clarify and implement the mode-none behavior in
applyKiroThinkingOverride so disabling thinking does not emit the unsupported
effort value "none"; align it with the existing budget handling and ensure
extractThinking/resolveKiroThinkingBudget can resolve the result correctly. Add
coverage in the Kiro thinking normalization tests asserting
applyKiroThinkingOverride with mode "none" produces the intended
budget-resolvable body.
- Line 1: Use resolveKiroEffortPath as the sole source of truth for model-family
classification, tightening its word-boundary matching as required. In the
thinking-level resolution flow, remove PATTERN_THINKING and its redundant glob
matching; once resolveKiroEffortPath confirms the supported family, return the
KIRO_NATIVE constant directly. Keep existing behavior for models that do not
resolve to that family.
In `@open-sse/executors/inxorastudio-web.js`:
- Around line 58-131: Update execute’s upstream fetch calls, including the
conversation creation request and the later generation request, to compose the
caller’s signal with AbortSignal.timeout using the shared timeout constant. Pass
the composed signal to proxyAwareFetch while preserving caller cancellation and
existing AbortError handling.
In `@open-sse/handlers/chatCore.js`:
- Around line 440-447: In the failure logging block after the early AbortError
return, update the status in appendRequestLog and the response.status in
buildRequestDetail to use the constant BAD_GATEWAY/502 values directly. Remove
both unreachable error.name === "AbortError" ternaries while preserving the
existing error message and request-detail fields.
- Around line 486-528: Extract the duplicated upstream error handling in the
surrounding request flow into a local returnUpstreamError(statusCode, message,
resetsAtMs) closure, including tracking, request logging, detail persistence,
formatting, console logging, and createErrorResult. Replace both the
recovered=false 5xx/transport-failure path and the 4xx path with calls to this
closure, preserving their existing control flow and parameters.
In `@open-sse/providers/thinkingLevels.js`:
- Around line 29-38: Remove the duplicated Claude-5/GPT-5.6 family patterns from
PATTERN_THINKING and update getThinkingLevels to derive the supported thinking
levels from the result of resolveKiroEffortPath. Preserve the existing gating
and KIRO_NATIVE level behavior while ensuring family classification has a single
source of truth.
In `@open-sse/utils/responsesStreamHelpers.js`:
- Around line 34-41: Extract the shared `{ type: "stream_error", code:
"stream_disconnected", message: "stream closed before response.completed" }`
payload into a named constant in the appropriate config/constants module, then
reuse that constant in both `buildAbortedResponsesTerminalBytes` and
`formatIncompleteOpenAIResponsesStreamFailure` so the accumulator error and SSE
response remain identical.
In `@src/lib/db/repos/usageRepo.js`:
- Around line 329-362: Resolve getPricingForModel(entry.provider, entry.model)
once before the overall savings processing, then reuse that pricing value in
both the total costSavedLifetime block and the per-mechanism cost calculation.
Remove the duplicate lookup assigned to mechPricing while preserving the
existing pricing checks and savings updates.
In `@tests/unit/responses-accumulator.test.js`:
- Around line 118-132: Extend the response.completed tests around
ResponsesAccumulator to cover merging a terminal output snapshot after prior
deltas, including function_call items without arguments, preserving buffered
arguments and avoiding synthesized empty-string arguments. Add assertions that
finalize() is idempotent and that preferComplete resolves disagreements between
delta data and the terminal snapshot as intended.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ce95746-e821-4bba-85a3-0b1584b95964
⛔ Files ignored due to path filters (5)
public/providers/agentrouter.pngis excluded by!**/*.pngpublic/providers/bynara.svgis excluded by!**/*.svgpublic/providers/infron.svgis excluded by!**/*.svgpublic/providers/inxorastudio-web.svgis excluded by!**/*.svgpublic/providers/inxorastudio.svgis excluded by!**/*.svg
📒 Files selected for processing (76)
CHANGELOG.mdcli/package.jsonopen-sse/config/appConstants.jsopen-sse/config/kiroConstants.jsopen-sse/config/providerModels.jsopen-sse/executors/antigravity.jsopen-sse/executors/index.jsopen-sse/executors/inxorastudio-web.jsopen-sse/handlers/chatCore.jsopen-sse/handlers/chatCore/streamingHandler.jsopen-sse/handlers/responsesHandler.jsopen-sse/providers/registry/agentrouter.jsopen-sse/providers/registry/antigravity.jsopen-sse/providers/registry/bynara.jsopen-sse/providers/registry/commandcode.jsopen-sse/providers/registry/glm.jsopen-sse/providers/registry/grok-web.jsopen-sse/providers/registry/hcnsec.jsopen-sse/providers/registry/index.jsopen-sse/providers/registry/infron.jsopen-sse/providers/registry/inxorastudio-web.jsopen-sse/providers/registry/inxorastudio.jsopen-sse/providers/thinkingLevels.jsopen-sse/services/projectId.jsopen-sse/services/provider.jsopen-sse/services/usage.jsopen-sse/services/usage/grok-web.jsopen-sse/services/usage/infron.jsopen-sse/transformer/responsesTransformer.jsopen-sse/transformer/streamToJsonConverter.jsopen-sse/translator/concerns/responsesAccumulator.jsopen-sse/translator/formats/responsesApi.jsopen-sse/translator/request/claude-to-kiro.jsopen-sse/translator/request/openai-to-kiro.jsopen-sse/translator/response/openai-responses.jsopen-sse/utils/responsesStreamHelpers.jsopen-sse/utils/stream.jsopen-sse/utils/tlsImpersonate.jspackage.jsonscripts/test-combo-autoswitch.mjssrc/app/(dashboard)/dashboard/combos/components/ComboTemplates.jssrc/app/(dashboard)/dashboard/overview/OverviewClient.jssrc/app/(dashboard)/dashboard/overview/components/LeaderboardTable.jssrc/app/(dashboard)/dashboard/overview/components/SavingsCard.jssrc/app/(dashboard)/dashboard/providers/[id]/InxoraProfile.jssrc/app/(dashboard)/dashboard/providers/[id]/ModelRow.jssrc/app/(dashboard)/dashboard/providers/[id]/PassthroughModelsSection.jssrc/app/(dashboard)/dashboard/providers/[id]/components/ConnectionsCard.jssrc/app/(dashboard)/dashboard/providers/[id]/page.jssrc/app/(dashboard)/dashboard/providers/components/ProviderCardV2.jssrc/app/(dashboard)/dashboard/providers/components/ProviderSection.jssrc/app/(dashboard)/dashboard/providers/components/ProviderSummary.jssrc/app/(dashboard)/dashboard/quota/components/ProviderLimits/ProviderLimitCard.jssrc/app/(dashboard)/dashboard/quota/components/ProviderLimits/utils.jssrc/app/api/dashboard/stream/route.jssrc/app/api/providers/[id]/inxora-profile/route.jssrc/app/api/providers/client/route.jssrc/app/api/providers/suggested-models/filters.jssrc/app/api/providers/suggested-models/route.jssrc/app/api/providers/validate/route.jssrc/app/api/usage/leaderboard/route.jssrc/app/api/usage/meta/route.jssrc/lib/db/repos/usageRepo.jssrc/lib/oauth/utils/banner.jssrc/shared/components/Header.jssrc/shared/components/NotificationBell.jssrc/shared/hooks/useDashboardStream.jssrc/shared/utils/providerIcon.jssrc/shared/utils/providerModelsFetcher.jssrc/sse/handlers/chat.jssrc/sse/services/tokenRefresh.jssrc/store/notificationStore.jssrc/store/settingsStore.jstests/translator/real/nvidia-thinking.e2e.test.jstests/unit/kiro-thinking-normalization.test.jstests/unit/responses-accumulator.test.js
💤 Files with no reviewable changes (11)
- src/app/(dashboard)/dashboard/quota/components/ProviderLimits/ProviderLimitCard.js
- open-sse/utils/tlsImpersonate.js
- src/app/(dashboard)/dashboard/providers/components/ProviderSummary.js
- src/lib/oauth/utils/banner.js
- src/app/(dashboard)/dashboard/providers/components/ProviderSection.js
- src/store/settingsStore.js
- open-sse/handlers/responsesHandler.js
- src/app/(dashboard)/dashboard/combos/components/ComboTemplates.js
- src/app/(dashboard)/dashboard/providers/components/ProviderCardV2.js
- src/app/(dashboard)/dashboard/providers/[id]/PassthroughModelsSection.js
- open-sse/transformer/responsesTransformer.js
| const API_BASE = "https://labs.inxorastudio.com"; | ||
| const USER_AGENT = | ||
| "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36"; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Move host, User-Agent, default model, and request mode into config/ and the provider registry.
API_BASE, USER_AGENT, the default model "ixlabs/gpt-5.5", and mode: "deep" are hardcoded in the executor. Source them from config/ (and the inxorastudio-web registry transport.baseUrl / config/providerModels.js) so the endpoint and catalog stay config-driven like the other providers.
As per coding guidelines, "Keep the code config-driven and DRY; use camelCase, and never hardcode values, models, or block/role strings. Use constants and schemas from config/ and translator/schema/."
Also applies to: 89-89, 132-140
🤖 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 `@open-sse/executors/inxorastudio-web.js` around lines 24 - 26, Update the
inxorastudio-web executor to remove hardcoded API_BASE, USER_AGENT, default
model, and request mode values. Source the host from the inxorastudio-web
registry transport.baseUrl, the model from config/providerModels.js, and the
user-agent and mode from the existing config/schema constants; reuse those
values at the affected request and payload construction points while preserving
current behavior.
Source: Coding guidelines
| if (assistant?.inputTokens && assistant?.outputTokens) { | ||
| finalChunk.usage = { | ||
| prompt_tokens: assistant.inputTokens, | ||
| completion_tokens: assistant.outputTokens, | ||
| total_tokens: assistant.tokens || (assistant.inputTokens + assistant.outputTokens), | ||
| }; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Usage is dropped when either token count is 0.
Truthiness check hides legitimate zero values and skips usage entirely. Prefer explicit presence checks.
🐛 Proposed fix
- if (assistant?.inputTokens && assistant?.outputTokens) {
+ if (Number.isFinite(assistant?.inputTokens) && Number.isFinite(assistant?.outputTokens)) {
finalChunk.usage = {
prompt_tokens: assistant.inputTokens,
completion_tokens: assistant.outputTokens,
- total_tokens: assistant.tokens || (assistant.inputTokens + assistant.outputTokens),
+ total_tokens: assistant.tokens ?? (assistant.inputTokens + assistant.outputTokens),
};
}📝 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.
| if (assistant?.inputTokens && assistant?.outputTokens) { | |
| finalChunk.usage = { | |
| prompt_tokens: assistant.inputTokens, | |
| completion_tokens: assistant.outputTokens, | |
| total_tokens: assistant.tokens || (assistant.inputTokens + assistant.outputTokens), | |
| }; | |
| } | |
| if (Number.isFinite(assistant?.inputTokens) && Number.isFinite(assistant?.outputTokens)) { | |
| finalChunk.usage = { | |
| prompt_tokens: assistant.inputTokens, | |
| completion_tokens: assistant.outputTokens, | |
| total_tokens: assistant.tokens ?? (assistant.inputTokens + assistant.outputTokens), | |
| }; | |
| } |
🤖 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 `@open-sse/executors/inxorastudio-web.js` around lines 245 - 251, Update the
usage guard in the assistant token handling block to use explicit presence
checks for inputTokens and outputTokens rather than truthiness, so zero-valued
counts still populate finalChunk.usage. Preserve the existing prompt_tokens,
completion_tokens, and total_tokens assignments.
| } catch (err) { | ||
| if (!signal?.aborted) controller.error(err); | ||
| } finally { | ||
| controller.enqueue(encoder.encode(SSE_DONE)); | ||
| controller.close(); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
finally block enqueues/closes after controller.error() → throws inside start().
Once controller.error(err) runs, the controller is errored: the subsequent controller.enqueue(SSE_DONE) and controller.close() both throw TypeError, producing an unhandled rejection from start() and masking the original error. The upstream reader is also never released/cancelled on the abort break path.
🐛 Proposed fix
- } catch (err) {
- if (!signal?.aborted) controller.error(err);
- } finally {
- controller.enqueue(encoder.encode(SSE_DONE));
- controller.close();
- }
+ } catch (err) {
+ if (!signal?.aborted) {
+ try { reader.cancel(); } catch { /* noop */ }
+ reader.releaseLock();
+ controller.error(err);
+ return;
+ }
+ }
+ try { await reader.cancel(); } catch { /* noop */ }
+ reader.releaseLock();
+ try {
+ controller.enqueue(encoder.encode(SSE_DONE));
+ controller.close();
+ } catch { /* controller already closed */ }📝 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.
| } catch (err) { | |
| if (!signal?.aborted) controller.error(err); | |
| } finally { | |
| controller.enqueue(encoder.encode(SSE_DONE)); | |
| controller.close(); | |
| } | |
| } catch (err) { | |
| if (!signal?.aborted) { | |
| try { reader.cancel(); } catch { /* noop */ } | |
| reader.releaseLock(); | |
| controller.error(err); | |
| return; | |
| } | |
| } | |
| try { await reader.cancel(); } catch { /* noop */ } | |
| reader.releaseLock(); | |
| try { | |
| controller.enqueue(encoder.encode(SSE_DONE)); | |
| controller.close(); | |
| } catch { /* controller already closed */ } |
🤖 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 `@open-sse/executors/inxorastudio-web.js` around lines 258 - 263, Update the
stream lifecycle around the catch/finally handling in the executor’s start flow:
do not enqueue SSE_DONE or close the controller after controller.error(err), and
ensure the upstream reader is released or cancelled when the abort path breaks.
Preserve normal completion behavior by sending SSE_DONE and closing only while
the controller remains usable, without masking the original error.
| if (altResult.response?.ok) { | ||
| providerResponse = altResult.response; | ||
| providerUrl = altResult.url; | ||
| providerHeaders = altResult.headers; | ||
| finalBody = altResult.transformedBody; | ||
| executorRetryCount += altResult.retryCount || 0; | ||
| return true; | ||
| } else { | ||
| // M1 FIX: Log the alternate's failure status so operators can debug | ||
| // "both endpoints down" scenarios instead of seeing only the primary error. | ||
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} also failed (HTTP ${altResult.response.status})`); | ||
| } | ||
| } catch (altErr) { | ||
| // M1 FIX: Log the alternate's exception instead of swallowing it silently. | ||
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} threw: ${altErr?.message || altErr}`); | ||
| // Restore original transport so downstream retry paths use the correct endpoint. | ||
| credentials.runtimeTransport = originalTransport; | ||
| } | ||
| return false; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
credentials.runtimeTransport is not restored when the alternate returns a non-OK response.
The catch branch restores originalTransport, but the non-OK branch (lines 382-386) returns false with credentials.runtimeTransport still pointing at the alternate. Since credentials is a caller-owned object (refreshedCredentials in src/sse/handlers/chat.js), any later use of it executes against the alternate endpoint while the body is still in primary format — exactly the hazard the comment on lines 353-356 describes. Also, the alternate's non-OK body is never consumed or cancelled, which holds the socket until GC.
🛠️ Proposed fix
try {
const altResult = await executor.execute({ model, body: altTranslatedBody, stream, credentials, signal: altController.signal, log, proxyOptions });
if (altResult.response?.ok) {
providerResponse = altResult.response;
providerUrl = altResult.url;
providerHeaders = altResult.headers;
finalBody = altResult.transformedBody;
executorRetryCount += altResult.retryCount || 0;
return true;
- } else {
- // M1 FIX: Log the alternate's failure status so operators can debug
- // "both endpoints down" scenarios instead of seeing only the primary error.
- log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} also failed (HTTP ${altResult.response.status})`);
}
+ log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} also failed (HTTP ${altResult.response?.status ?? "no response"})`);
+ try { await altResult.response?.body?.cancel?.(); } catch { /* ignore */ }
+ credentials.runtimeTransport = originalTransport;
} catch (altErr) {
- // M1 FIX: Log the alternate's exception instead of swallowing it silently.
log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} threw: ${altErr?.message || altErr}`);
- // Restore original transport so downstream retry paths use the correct endpoint.
credentials.runtimeTransport = originalTransport;
}
return false;📝 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.
| if (altResult.response?.ok) { | |
| providerResponse = altResult.response; | |
| providerUrl = altResult.url; | |
| providerHeaders = altResult.headers; | |
| finalBody = altResult.transformedBody; | |
| executorRetryCount += altResult.retryCount || 0; | |
| return true; | |
| } else { | |
| // M1 FIX: Log the alternate's failure status so operators can debug | |
| // "both endpoints down" scenarios instead of seeing only the primary error. | |
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} also failed (HTTP ${altResult.response.status})`); | |
| } | |
| } catch (altErr) { | |
| // M1 FIX: Log the alternate's exception instead of swallowing it silently. | |
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} threw: ${altErr?.message || altErr}`); | |
| // Restore original transport so downstream retry paths use the correct endpoint. | |
| credentials.runtimeTransport = originalTransport; | |
| } | |
| return false; | |
| if (altResult.response?.ok) { | |
| providerResponse = altResult.response; | |
| providerUrl = altResult.url; | |
| providerHeaders = altResult.headers; | |
| finalBody = altResult.transformedBody; | |
| executorRetryCount += altResult.retryCount || 0; | |
| return true; | |
| } | |
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} also failed (HTTP ${altResult.response?.status ?? "no response"})`); | |
| try { await altResult.response?.body?.cancel?.(); } catch { /* ignore */ } | |
| credentials.runtimeTransport = originalTransport; | |
| } catch (altErr) { | |
| log?.warn?.("TRANSPORT", `${provider.toUpperCase()} | alternate ${altTransport.format} threw: ${altErr?.message || altErr}`); | |
| credentials.runtimeTransport = originalTransport; | |
| } | |
| return false; |
🤖 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 `@open-sse/handlers/chatCore.js` around lines 375 - 393, Restore
credentials.runtimeTransport to originalTransport in the alternate non-OK branch
before returning false, matching the catch-path cleanup. Also consume or cancel
altResult.response.body there so the failed alternate response does not retain
its socket.
| scheme: "bearer", | ||
| }, | ||
| }, | ||
| // Multi-endpoint: OpenAI (/v1) + Anthropic (root — SDK appends /v1/messages). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stale comment: the Claude baseUrl is not a root URL.
Line 52 already carries the full /v1/messages path, so "root — SDK appends /v1/messages" is misleading.
📝 Proposed fix
- // Multi-endpoint: OpenAI (/v1) + Anthropic (root — SDK appends /v1/messages).
+ // Multi-endpoint: OpenAI (/v1/chat/completions) + Anthropic (/v1/messages).📝 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.
| // Multi-endpoint: OpenAI (/v1) + Anthropic (root — SDK appends /v1/messages). | |
| // Multi-endpoint: OpenAI (/v1/chat/completions) + Anthropic (/v1/messages). |
🤖 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 `@open-sse/providers/registry/agentrouter.js` at line 43, Update the comment
above the multi-endpoint configuration to accurately describe the Claude base
URL as the full /v1/messages endpoint, and remove the claim that the SDK appends
/v1/messages. Leave the endpoint configuration unchanged.
| export async function GET(_request, { params }) { | ||
| try { | ||
| const { id } = await params; | ||
| const connection = await getProviderConnectionById(id); | ||
| if (!connection) { | ||
| return NextResponse.json({ error: "Connection not found" }, { status: 404 }); | ||
| } | ||
|
|
||
| let token = (connection.apiKey || "").replace(/^Bearer\s+/i, "").replace(/^cookie:\s*/i, "").trim(); | ||
|
|
||
| const res = await fetch("https://labs.inxorastudio.com/api/auth/me", { | ||
| method: "GET", | ||
| headers: { | ||
| Authorization: `Bearer ${token}`, | ||
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", | ||
| Referer: "https://labs.inxorastudio.com/dashboard", | ||
| }, | ||
| }); | ||
|
|
||
| if (res.status === 401 || res.status === 403) { | ||
| return NextResponse.json({ error: "Session expired" }, { status: 401 }); | ||
| } | ||
|
|
||
| if (!res.ok) { | ||
| return NextResponse.json({ error: `InxoraStudio returned ${res.status}` }, { status: res.status }); | ||
| } | ||
|
|
||
| const data = await res.json(); | ||
| if (!data?.user) { | ||
| return NextResponse.json({ error: "No user in response" }, { status: 401 }); | ||
| } | ||
|
|
||
| const u = data.user; | ||
| return NextResponse.json({ | ||
| name: u.name || u.email?.split("@")[0] || "User", | ||
| email: u.email || "", | ||
| plan: u.plan || "FREE", | ||
| apiKey: u.apiKey || "", | ||
| isActive: u.isActive !== false, | ||
| }); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win
Enforce connection ownership and do not return u.apiKey.
This handler has no authentication/ownership check and serializes the upstream API key to the client. A caller with another connection ID can obtain that connection’s profile PII and credential. Authenticate the caller, scope the connection lookup to its owner, and return only a masked/non-secret key indicator if the UI needs one.
As per coding guidelines: “Protect API keys and secrets; implement authentication, authorization, input validation, rate limiting, secure headers, environment-variable usage, and secrets management. Never expose secrets.”
🤖 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 `@src/app/api/providers/`[id]/inxora-profile/route.js around lines 9 - 48,
Update GET to authenticate the caller and retrieve the provider connection
through an owner-scoped lookup, rejecting unauthenticated or unauthorized
requests before contacting the upstream API. In the response construction around
data.user, remove u.apiKey and return only a masked or non-secret indicator if
required by the UI; preserve the existing profile fields and status handling.
Source: Coding guidelines
| const res = await fetch("https://labs.inxorastudio.com/api/auth/me", { | ||
| method: "GET", | ||
| headers: { | ||
| Authorization: `Bearer ${token}`, | ||
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", | ||
| Referer: "https://labs.inxorastudio.com/dashboard", | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Add a bounded timeout to the upstream profile request.
A stalled InxoraStudio response can hold this route open indefinitely. Attach a configurable abort deadline and return a controlled upstream-timeout error.
As per coding guidelines: “Consider response speed, memory usage, bundle size, lazy loading, caching, parallel requests, and streaming; identify bottlenecks before implementation.”
🤖 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 `@src/app/api/providers/`[id]/inxora-profile/route.js around lines 19 - 26,
Update the upstream fetch in the inxora profile route to use an AbortController
with a configurable, bounded timeout, ensuring the timer is cleaned up after
completion. Catch aborts caused by this deadline and return the route’s
controlled upstream-timeout error while preserving existing handling for other
fetch failures.
Source: Coding guidelines
| if (connectionId) { | ||
| try { | ||
| const connection = await getProviderConnectionById(connectionId); | ||
| if (!connection) { | ||
| return NextResponse.json({ error: "Connection not found" }, { status: 404 }); | ||
| } | ||
| const token = connection.apiKey || connection.accessToken; | ||
| if (token) { | ||
| authHeader = `Bearer ${token}`; | ||
| } | ||
| } catch { | ||
| // Fall through — try unauthenticated fetch | ||
| } | ||
| } | ||
|
|
||
| if (!url) { | ||
| return NextResponse.json({ error: "Missing url" }, { status: 400 }); | ||
| } | ||
|
|
||
| try { | ||
| const res = await fetch(url); | ||
| const headers = { Accept: "application/json" }; | ||
| if (authHeader) headers.Authorization = authHeader; | ||
|
|
||
| const res = await fetch(url, { | ||
| headers, | ||
| signal: AbortSignal.timeout(12000), |
There was a problem hiding this comment.
🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift
Do not forward connection credentials to a caller-controlled URL.
connectionId selects a stored token while url selects its destination. A request with an attacker URL can exfiltrate that token in Authorization and can also probe internal URLs. Resolve the models URL and filter type server-side from trusted provider configuration after loading the connection; enforce connection ownership and reject destinations outside the configured allowlist.
As per coding guidelines, “Protect API keys and secrets; implement authentication, authorization, input validation…”
🤖 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 `@src/app/api/providers/suggested-models/route.js` around lines 40 - 65, Update
the suggested-models route’s connectionId/url handling to avoid sending stored
credentials to caller-controlled destinations: authenticate and authorize the
connection owner, resolve the models URL and filter type from the trusted
provider configuration, and validate the resolved destination against its
configured allowlist before fetching. Reject or omit caller-supplied
destinations that do not match the authorized configuration, while preserving
unauthenticated behavior only where no connection is selected.
Source: Coding guidelines
| const res = await fetch("https://labs.inxorastudio.com/api/auth/me", { | ||
| method: "GET", | ||
| headers: { | ||
| Authorization: `Bearer ${token}`, | ||
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", | ||
| Referer: "https://labs.inxorastudio.com/dashboard", | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Bound the Inxora validation request.
This new upstream call has no timeout, so a stalled provider can indefinitely hold validation work. Match the bounded probes elsewhere in this handler.
Proposed fix
const res = await fetch("https://labs.inxorastudio.com/api/auth/me", {
method: "GET",
+ signal: AbortSignal.timeout(8000),
headers: {As per coding guidelines, external calls should be resilient and safe.
📝 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 res = await fetch("https://labs.inxorastudio.com/api/auth/me", { | |
| method: "GET", | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", | |
| Referer: "https://labs.inxorastudio.com/dashboard", | |
| }, | |
| }); | |
| const res = await fetch("https://labs.inxorastudio.com/api/auth/me", { | |
| method: "GET", | |
| signal: AbortSignal.timeout(8000), | |
| headers: { | |
| Authorization: `Bearer ${token}`, | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36", | |
| Referer: "https://labs.inxorastudio.com/dashboard", | |
| }, | |
| }); |
🤖 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 `@src/app/api/providers/validate/route.js` around lines 642 - 649, Add a
timeout to the upstream fetch in the Inxora validation branch, using the
handler’s existing bounded-probe pattern and timeout configuration where
available. Update the fetch options around the Inxora validation request while
preserving its method and headers, ensuring stalled requests abort rather than
holding validation indefinitely.
Source: Coding guidelines
| const NOTIFIABLE_TYPES = new Set([ | ||
| "provider_down", | ||
| "provider_recovered", | ||
| "health_degraded", | ||
| "rate_limited", | ||
| "budget_exceeded", | ||
| ]); | ||
|
|
||
| useEffect(() => { | ||
| if (events.length === 0) return; | ||
| const latest = events[0]; | ||
| // Only notify on significant events — skip health_update (too spammy) | ||
| // and usage_update (not actionable). health_update fires every 500ms per | ||
| // provider on any metric change; only health_degraded (success < 70%) | ||
| // is worth surfacing as a notification. | ||
| if (!NOTIFIABLE_TYPES.has(latest.type)) return; | ||
| if (latest.ts && latest.ts > lastProcessedTs.current) { | ||
| lastProcessedTs.current = latest.ts; | ||
| useNotificationStore.getState().addServerEvent(latest); | ||
| } | ||
| }, [events]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n "rate_limited|budget_exceeded|health_degraded" --type=jsRepository: rsalmn/ExtremeRouter
Length of output: 158
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- matches for target event types ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'rate_limited|budget_exceeded|health_degraded|provider_down|provider_recovered|health_update|usage_update|snapshot' .
printf '\n%s\n' '--- files mentioning NotificationBell or notification store ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'NotificationBell|formatEventTitle|formatEventMessage|addServerEvent|useNotificationStore' .Repository: rsalmn/ExtremeRouter
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- dashboard stream route and notification store ---'
fd -a 'route.js|notificationStore.js|NotificationBell.js' src
printf '\n%s\n' '--- outline NotificationBell.js ---'
ast-grep outline src/shared/components/NotificationBell.js --view expanded
printf '\n%s\n' '--- outline notificationStore.js ---'
ast-grep outline src/shared/stores/notificationStore.js --view expandedRepository: rsalmn/ExtremeRouter
Length of output: 9532
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- dashboard stream route ---'
sed -n '1,260p' src/app/api/dashboard/stream/route.js
printf '\n%s\n' '--- notification store ---'
sed -n '1,260p' src/store/notificationStore.js
printf '\n%s\n' '--- notification bell ---'
sed -n '1,220p' src/shared/components/NotificationBell.jsRepository: rsalmn/ExtremeRouter
Length of output: 15063
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- event type matches ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'rate_limited|budget_exceeded|health_degraded' src
printf '\n%s\n' '--- notification formatting matches ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'formatEventTitle|formatEventMessage|addServerEvent|NOTIFIABLE_TYPES|health_update|provider_down|provider_recovered|usage_update|snapshot' \
src/store src/shared src/app/api/dashboard/streamRepository: rsalmn/ExtremeRouter
Length of output: 6491
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- alert service ---'
sed -n '1,220p' src/shared/services/alertService.js
printf '\n%s\n' '--- dispatchAlert call sites for the extra types ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
'dispatchAlert\("(health_degraded|budget_exceeded|rate_limited)"|type:\s*"(health_degraded|budget_exceeded|rate_limited)"' \
src/sse src/shared src/appRepository: rsalmn/ExtremeRouter
Length of output: 6277
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- useDashboardStream ---'
sed -n '1,220p' src/shared/hooks/useDashboardStream.js
printf '\n%s\n' '--- NotificationBell line numbers ---'
cat -n src/shared/components/NotificationBell.js | sed -n '1,120p'Repository: rsalmn/ExtremeRouter
Length of output: 8493
Keep the notification types aligned with the dashboard stream NOTIFIABLE_TYPES includes health_degraded, rate_limited, and budget_exceeded, but /api/dashboard/stream only emits provider_down, provider_recovered, and health_update. rate_limited is used by the webhook alert service, not this SSE path, so this bell never sees it; the health_update branch in src/store/notificationStore.js is also unreachable from here. Either forward those events into the stream or trim the unused cases.
🤖 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 `@src/shared/components/NotificationBell.js` around lines 33 - 53, Align
NOTIFIABLE_TYPES in the NotificationBell effect with the event types emitted by
/api/dashboard/stream: remove rate_limited, budget_exceeded, and health_degraded
unless the stream is updated to forward them. Ensure the set and related
filtering reflect the actual SSE types, preserving provider_down and
provider_recovered handling.
Features
getClineUsagehandler with OAuth/API-key auth fallback.isBreakerBlocking()check (does not consume the single HALF_OPEN probe slot) +filterBreakerOpenModels()helper. Falls back to the original model list if ALL are blocked (probe window may open during attempt).ProviderDetailHeader(branded header),ConnectionsCard(toolbar + rows + bulk proxy modal),ModelsCard(toolbar + grid),CollapsibleSection(reusable wrapper). page.js reduced to a lean orchestrator (~960 lines). Visual polish: branded header with category summary, collapsible sections (Health default-collapsed), responsive model grid (grid-cols-3), progress-bar-style one-by-one test summary, compact pill toolbars.Fixes — Combo Engine (28 bug fixes across 4 audit rounds)
body_globalrace condition (swarm.js): removed module-level mutable state;bodythreaded explicitly to all stage runners. Concurrent swarm requests no longer clobber each other's prompt (cross-request leak).releaseBreakerProbeReferenceError (circuitBreaker.js):monitors→breakers— half-open probe slot now releases correctly; breaker no longer stuck open forever.patchComboStrategiesnow sends partial patches with{ [key]: null }delete-signals compatible with the deep-merge in updateSettings.comboStickyLimit(chat.js):comboStickyLimit→comboStickyRoundRobinLimit. Round-robin fast-path now respects sticky limit config.handleSetComboStrategy(settingsRepo.js + CombosPageInner.js): backend deep-mergescomboStrategiesat combo-name level; UI sends only the changed entry.useEffectwatch onisOpentransition.setModels(prev => ...).if (body.name)→if (body.name !== undefined)+ non-empty check.Array.isArray(models)validation in POST + PUT.normalizeStrategy()helper (trim+lowercase+whitelist).body.stream === true.combo.modelsnormalized to[]defensively.alert().skipBreakeropt for panel calls; fusion/swarm failures no longer trip shared per-provider breaker.parseStrategytruncated JSON: lenient recovery salvages complete subtask objects via regex.workerCountconfig ignored:workerCountfrom UI now honored viaworkerCap.getStrategyDistributionwhitelist, PUT response canonical shape, stale role-field cleanup, ModelSelectModal highlight,VALID_NAME_REGEXdedup, ComboFormModal fetch cleanup.Fixes — Code Review Feedback
/responsesproactive routing (github.js):buildUrl()+execute()routetargetFormat:"openai-responses"models to/responsesproactively.Uimport (xai.js): dead code removed.it.each/expect+ standalone-script fallback.Improvements
comboStrategiesmerged at combo-name level (not replaced), withnullas the delete-signal.ALIAS_TO_IDmap (combo.js): built from REGISTRY for breaker lookups without crossing the open-sse→src layer boundary.categorytags replaces 5 separate section arrays.Summary by CodeRabbit
New Features
Bug Fixes