Skip to content

Quiet Claude rate-limit pings and tidy subagents pane#302

Merged
arul28 merged 4 commits into
mainfrom
ade/chat-20260514-125806-4dcfa0bb
May 14, 2026
Merged

Quiet Claude rate-limit pings and tidy subagents pane#302
arul28 merged 4 commits into
mainfrom
ade/chat-20260514-125806-4dcfa0bb

Conversation

@arul28

@arul28 arul28 commented May 14, 2026

Copy link
Copy Markdown
Owner

Summary

Two small chat-UX cleanups in the Claude provider:

  • Rate-limit notice softened. The Claude SDK emits a rate_limit_event every turn once you cross ~80% utilization, which surfaced as a yellow RATE LIMIT warning that looked like an error even though the request was still allowed. Now:
    • status: "allowed" → suppressed entirely (no signal needed).
    • status: "allowed_warning" → emitted once per session as info severity with the message Approaching Claude plan limit and a neutral USAGE chip. The 80% utilized | resets … detail is preserved.
    • Actual blocked/limited states → unchanged: full red RATE LIMIT chip with error severity.
  • Subagents pane. Removed the redundant bottom drawer in Claude chat (mission threads still use it). Persist the "auto-opened this session" bit to localStorage so leaving and returning to the chat doesn't re-pop the pane after you've closed it — first subagent in a session still auto-opens once, then the pane state is up to you.

Test plan

  • pnpm vitest run apps/desktop/src/main/services/chat/agentChatService.test.ts apps/desktop/src/renderer/components/chat/AgentChatMessageList.test.tsx apps/desktop/src/renderer/components/chat/ChatSubagentsPanel.test.tsx — 348 passed
  • pnpm exec tsc --noEmit — clean (two pre-existing module-resolution errors unrelated to this change)
  • Manual: open a Claude chat near plan limit, confirm the USAGE notice appears once with neutral styling and the chat continues
  • Manual: spawn a subagent, close the right pane, leave and return to the chat — pane should stay closed

🤖 Generated with Claude Code

Greptile Summary

This PR bundles several UX improvements: Claude rate-limit events are now silenced when allowed and de-escalated to a one-time info notice when allowed_warning; the subagents auto-open flag is persisted to localStorage with a 7-day TTL and migration path for legacy entries. Alongside these headline changes the diff also ships a new PR badge slide-out toolbar in Claude chat, fire-and-forget rebase scanning to unblock the PR-tab cold open, issue-comment support in the resolver (centralised noise filtering, actionableIssueCommentCount), and prPollingService.poke() calls after every PR-mutating IPC handler.

  • Rate-limit / subagents pane: dual session+runtime guard prevents re-notifying after runtime reinit; localStorage persistence with TTL and legacy-value migration is well-tested.
  • PrsContext refresh: rebase scans moved off the critical path; refreshPending now carries full options so targeted refreshes queued behind an in-flight call are correctly forwarded — but the new warm-cache fast path fires async work without acquiring refreshInFlight, opening a race with concurrent poke()-triggered refreshes.
  • Issue-comment support: isActionablePrIssueComment consolidates duplicated noise-filter patterns from three call sites into one shared location in prIssueResolution.ts."

Confidence Score: 4/5

Safe to merge with one concurrency fix recommended in PrsContext before heavy PR-tab usage.

The warm-cache fast path in refreshCore launches async work and returns without acquiring the in-flight lock, so any PR mutation that calls poke() in the same window can start a second concurrent refresh chain — both calling window.ade.prs.refresh() and writing PR list state simultaneously. The state writes are idempotent (React functional updates + jsonEqual guards), so data corruption is unlikely, but duplicate GitHub API calls and a stale background snapshot potentially overwriting a targeted refresh are real. The remainder of the changes — rate-limit notice suppression, localStorage-persisted subagent flag, issue-comment resolver support, and the PR toolbar slide-out — are well-structured with good test coverage.

apps/desktop/src/renderer/components/prs/state/PrsContext.tsx — the warm-cache branch and new refreshSelectedPrDetail function.

Important Files Changed

Filename Overview
apps/desktop/src/main/services/chat/agentChatService.ts Rate-limit handling softened: allowed events suppressed, allowed_warning emitted once per session via dual session+runtime guard; fixes previous runtime-reinit reset issue.
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx Subagent auto-open flag persisted to localStorage with 7-day TTL; legacy values migrated; cleanup runs on mount; inline bottom drawer removed for Claude chat.
apps/desktop/src/renderer/components/chat/ChatGitToolbar.tsx New PR badge slide-out menu with ADE/GitHub/Copy actions and live checks summary; summarizeChecks omits action_required/timed_out from the failure count.
apps/desktop/src/renderer/components/prs/state/PrsContext.tsx Rebase scanning moved to fire-and-forget; refreshPending now stores full options; warm-cache path fires background work without acquiring refreshInFlight, enabling concurrent refresh races; new refreshSelectedPrDetail bypasses detailFetchInProgress guard.
apps/desktop/src/shared/prIssueResolution.ts New isActionablePrIssueComment centralises noise filtering; getPrIssueResolutionAvailability gains issueComments param with actionableIssueCommentCount/actionableCommentCount fields.
apps/desktop/src/main/services/ipc/registerIpc.ts All PR-mutating IPC handlers now call ctx.prPollingService.poke() after completion to push immediate refresh to the frontend.
apps/desktop/src/main/services/prs/resolverUtils.ts Noise-detection logic consolidated: isNoisyIssueComment delegates to isActionablePrIssueComment; duplicate pattern lists removed.
apps/desktop/src/renderer/components/prs/detail/PrDetailTimelineRails.tsx Extracted buildTimelineVisibleEventSearch helper; now correctly preserves detailTab in URL when navigating to an event.
apps/desktop/vitest.config.ts Module alias stubs moved to regex-based patterns and added to top-level vitest config so the node test project picks them up.

Sequence Diagram

sequenceDiagram
    participant UI as PrsContext
    participant RC as refreshCore
    participant ALS as applyLocalPrState
    participant GH as window.ade.prs.refresh

    Note over UI,GH: Normal full-refresh path
    UI->>RC: refreshCore
    RC->>RC: "refreshInFlight=true"
    RC->>ALS: await applyLocalPrState
    RC-->>GH: void refresh background
    RC->>RC: "refreshInFlight=false"

    Note over UI,GH: New warm-cache path no lock
    UI->>RC: refreshCore skipFreshWarmCache
    RC->>RC: warmCacheUsable return early
    RC-->>ALS: void applyLocalPrState background
    RC-->>GH: void refresh no lock

    Note over UI,GH: Concurrent poke fires while background running
    UI->>RC: refreshCore from poke
    RC->>RC: refreshInFlight false proceeds
    RC->>RC: "refreshInFlight=true"
    RC->>ALS: applyLocalPrState races with background
    RC-->>GH: void refresh duplicate call
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/components/chat/AgentChatPane.tsx, line 6694-6702 (link)

    P2 No inline fallback when subagent pane is closed after first spawn

    The removed block was the only in-pane indicator of running subagents when effectiveSubagentPaneOpen was false. After this PR, the auto-open fires exactly once (now persisted across navigations), but if the user explicitly closes the side panel, any subsequently spawned subagents in that session become invisible — no badge, no inline strip, nothing. Depending on whether a separate re-open affordance exists (e.g., a toolbar button), users may miss active subagent work entirely.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
    Line: 6694-6702
    
    Comment:
    **No inline fallback when subagent pane is closed after first spawn**
    
    The removed block was the only in-pane indicator of running subagents when `effectiveSubagentPaneOpen` was false. After this PR, the auto-open fires exactly once (now persisted across navigations), but if the user explicitly closes the side panel, any subsequently spawned subagents in that session become invisible — no badge, no inline strip, nothing. Depending on whether a separate re-open affordance exists (e.g., a toolbar button), users may miss active subagent work entirely.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
apps/desktop/src/renderer/components/prs/state/PrsContext.tsx:822-845
**Warm-cache path bypasses `refreshInFlight` lock**

The `skipFreshWarmCache && warmCacheUsable` branch launches async work with `void applyLocalPrState(...)` and then `window.ade.prs.refresh()`, but returns before setting `refreshInFlight.current = true`. A concurrent `refreshCore` call — e.g. from any of the new `prPollingService.poke()` sites in `registerIpc.ts` — will see `refreshInFlight === false`, enter the normal path, and fire its own `applyLocalPrState` + GitHub refresh simultaneously. The two async chains can race to write PR list state and `warmCacheHydratedAtRef`, and the slower background chain could overwrite data from the faster targeted refresh with an older snapshot.

### Issue 2 of 3
apps/desktop/src/renderer/components/chat/ChatGitToolbar.tsx:101-105
`action_required` and `timed_out` are terminal failure-like conclusions, but `summarizeChecks` doesn't count them in either `passed` or `failed`. A PR with only `action_required` checks shows "N checks" in the neutral fallback color rather than red, making the CI state appear healthy when it isn't. Other parts of the codebase (e.g. `workflowTools.ts` filtering action runs) already treat these as failures.

```suggestion
    } else if (c.conclusion === "failure" || c.conclusion === "cancelled" || c.conclusion === "action_required" || c.conclusion === "timed_out") {
      failed += 1;
    }
  }
  return { passed, failed, running, total: checks.length };
```

### Issue 3 of 3
apps/desktop/src/renderer/components/prs/state/PrsContext.tsx:965-1029
**`refreshSelectedPrDetail` bypasses the `detailFetchInProgress` guard**

`refreshDetailSilently` (the polling path) checks `if (detailFetchInProgress.current) return;` before starting. The new `refreshSelectedPrDetail` — called from `refresh()` — does not perform this check: it unconditionally sets `detailFetchInProgress.current = true`. If the background polling fires first and sets the flag, `refreshSelectedPrDetail` still starts, and both run concurrently. The flag is then cleared by whichever completes first, allowing the polling to fire again while the other is still in flight.

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

The Claude SDK fires a rate_limit_event on every turn once usage crosses
80%, which made each turn surface a yellow "RATE LIMIT" warning even
though the request was still allowed. Suppress the always-fine "allowed"
status, soften "allowed_warning" to a once-per-session info notice
("Approaching Claude plan limit") with a neutral USAGE chip, and keep
the loud RATE LIMIT chrome only for actual blocked states.

Also drop the redundant subagents bottom drawer in Claude chat — the
right-pane variant is the single source of truth now. Persist the
"already auto-opened this session" bit to localStorage so leaving and
returning to a chat no longer re-pops the pane after you've closed it.
@vercel

vercel Bot commented May 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview May 14, 2026 7:55pm

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@arul28 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 7 minutes and 2 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0b271fd9-d460-4802-b4d5-fe363979a401

📥 Commits

Reviewing files that changed from the base of the PR and between 750401d and 8a5da70.

📒 Files selected for processing (37)
  • apps/ade-cli/src/adeRpcServer.test.ts
  • apps/ade-cli/src/adeRpcServer.ts
  • apps/ade-cli/src/tuiClient/__tests__/commands.test.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/ade-cli/src/tuiClient/commands.ts
  • apps/desktop/src/main/services/ai/tools/workflowTools.test.ts
  • apps/desktop/src/main/services/ai/tools/workflowTools.ts
  • apps/desktop/src/main/services/chat/agentChatService.test.ts
  • apps/desktop/src/main/services/chat/agentChatService.ts
  • apps/desktop/src/main/services/ipc/registerIpc.ts
  • apps/desktop/src/main/services/prs/pathToMergeOrchestrator.ts
  • apps/desktop/src/main/services/prs/prIssueResolution.test.ts
  • apps/desktop/src/main/services/prs/prIssueResolver.ts
  • apps/desktop/src/main/services/prs/resolverUtils.ts
  • apps/desktop/src/renderer/components/chat/AgentChatMessageList.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatMessageList.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.companionDrawers.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.submit.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.test.ts
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/chat/ChatGitToolbar.test.tsx
  • apps/desktop/src/renderer/components/chat/ChatGitToolbar.tsx
  • apps/desktop/src/renderer/components/prs/detail/PrDetailPane.tsx
  • apps/desktop/src/renderer/components/prs/detail/PrDetailTimelineRails.test.ts
  • apps/desktop/src/renderer/components/prs/detail/PrDetailTimelineRails.tsx
  • apps/desktop/src/renderer/components/prs/shared/PrIssueResolverModal.test.tsx
  • apps/desktop/src/renderer/components/prs/shared/PrIssueResolverModal.tsx
  • apps/desktop/src/renderer/components/prs/state/PrsContext.test.tsx
  • apps/desktop/src/renderer/components/prs/state/PrsContext.tsx
  • apps/desktop/src/shared/prIssueResolution.test.ts
  • apps/desktop/src/shared/prIssueResolution.ts
  • apps/desktop/vitest.config.ts
  • apps/desktop/vitest.workspace.ts
  • apps/ios/ADE/Views/PRs/PrAiResolverCtaCard.swift
  • apps/ios/ADE/Views/PRs/PrDetailActivityTab.swift
  • apps/ios/ADE/Views/PRs/PrDetailOverviewTab.swift
  • apps/ios/ADE/Views/PRs/PrDetailScreen.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/chat-20260514-125806-4dcfa0bb

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@arul28 arul28 changed the title Chat 20260514 125806 Quiet Claude rate-limit pings and tidy subagents pane May 14, 2026
@capy-ai

capy-ai Bot commented May 14, 2026

Copy link
Copy Markdown

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

Comment thread apps/desktop/src/main/services/chat/agentChatService.ts Outdated
Comment thread apps/desktop/src/renderer/components/chat/AgentChatPane.tsx Outdated
@arul28

arul28 commented May 14, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

Copilot AI commented May 14, 2026

Copy link
Copy Markdown
Contributor

@copilot review but do not make fixes

Reviewed at commit 2f3d168 (no fixes applied, per request). Current state looks good for the three flagged items: rate-limit warning dedupe is session-level, subagent auto-open storage now has TTL cleanup, and there is still a visible subagent toggle/badge affordance when the pane is closed. I also checked recent CI failures; the latest failure I inspected was unrelated (aiOrchestratorService test failures on another branch/run).

Copilot finished work on behalf of arul28 May 14, 2026 19:28
Comment on lines +822 to 845
if (options.skipFreshWarmCache && warmCacheUsable) {
// Cache is fresh — render what we have immediately and refresh silently
// in the background. Avoids the visible cold-load freeze on tab return.
setLoading(false);
initialLoadDone.current = true;
const shouldLoadWorkflowDiagnostics =
activeTabRef.current !== "normal" || selectedPrIdRef.current !== null || currentRouteRequestsPrDiagnostics();
void applyLocalPrState({ forceRebaseDiagnostics: shouldLoadWorkflowDiagnostics })
.then(() => options.githubRefreshMode === "background"
? window.ade.prs.refresh(options.githubRefreshArgs).catch(() => null)
: null)
.then(() => {
if (options.githubRefreshMode === "background") {
return applyLocalPrState({ forceRebaseDiagnostics: shouldLoadWorkflowDiagnostics });
}
return null;
})
.then(() => {
warmCacheHydratedAtRef.current = Date.now();
})
.catch((err) => {
console.warn("[PrsContext] Silent background refresh failed:", err);
});
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Warm-cache path bypasses refreshInFlight lock

The skipFreshWarmCache && warmCacheUsable branch launches async work with void applyLocalPrState(...) and then window.ade.prs.refresh(), but returns before setting refreshInFlight.current = true. A concurrent refreshCore call — e.g. from any of the new prPollingService.poke() sites in registerIpc.ts — will see refreshInFlight === false, enter the normal path, and fire its own applyLocalPrState + GitHub refresh simultaneously. The two async chains can race to write PR list state and warmCacheHydratedAtRef, and the slower background chain could overwrite data from the faster targeted refresh with an older snapshot.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/components/prs/state/PrsContext.tsx
Line: 822-845

Comment:
**Warm-cache path bypasses `refreshInFlight` lock**

The `skipFreshWarmCache && warmCacheUsable` branch launches async work with `void applyLocalPrState(...)` and then `window.ade.prs.refresh()`, but returns before setting `refreshInFlight.current = true`. A concurrent `refreshCore` call — e.g. from any of the new `prPollingService.poke()` sites in `registerIpc.ts` — will see `refreshInFlight === false`, enter the normal path, and fire its own `applyLocalPrState` + GitHub refresh simultaneously. The two async chains can race to write PR list state and `warmCacheHydratedAtRef`, and the slower background chain could overwrite data from the faster targeted refresh with an older snapshot.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

@arul28 arul28 merged commit 4560bdb into main May 14, 2026
28 checks passed
@arul28 arul28 deleted the ade/chat-20260514-125806-4dcfa0bb branch May 14, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants