diff --git a/ui/src/components/IssueMonitorBanner.test.tsx b/ui/src/components/IssueMonitorBanner.test.tsx
index 412581a6b7e..bd4430501c3 100644
--- a/ui/src/components/IssueMonitorBanner.test.tsx
+++ b/ui/src/components/IssueMonitorBanner.test.tsx
@@ -158,6 +158,21 @@ describe("IssueMonitorBanner / IssueMonitorComposerStrip rendering", () => {
flushSync(() => root.unmount());
});
+ it("explains pool exhaustion and retained account affinity on both waiting surfaces", () => {
+ const issue = {
+ status: "in_progress", scheduledRetry: { status: "scheduled_retry", scheduledRetryReason: "ai_connection_pool_wait", scheduledRetryAt: new Date(NOW.getTime() + 60_000).toISOString(), scheduledRetryAttempt: 1 },
+ } as Issue;
+ const root = createRoot(container);
+ flushSync(() => root.render(<>>));
+ expect(container.textContent).toContain("Pool exhausted");
+ expect(container.textContent).toContain("Usage recheck in 1m");
+ expect(container.textContent).toContain("This task keeps its account");
+ expect(container.textContent).toContain("The selected account stays pinned.");
+ expect(container.textContent).not.toContain("Attempt 1");
+ expect(container.querySelector("button")).not.toBeNull();
+ flushSync(() => root.unmount());
+ });
+
it("renders the banner with a working Check now button while waiting", () => {
const onCheckNow = vi.fn();
expect(hasVisibleMonitorSurface(issueWithMonitor(new Date(NOW.getTime() + 2 * 60 * 60_000).toISOString()))).toBe(true);
diff --git a/ui/src/components/IssueMonitorBanner.tsx b/ui/src/components/IssueMonitorBanner.tsx
index de0e83ff470..ac7fdc4a3c1 100644
--- a/ui/src/components/IssueMonitorBanner.tsx
+++ b/ui/src/components/IssueMonitorBanner.tsx
@@ -81,6 +81,16 @@ export function buildMonitorSurfaceCopy(
const eta = formatMonitorEta(derived.nextCheckAt, now); // "in 2h 12m" | "due now" | "overdue by 18m"
const absolute = formatMonitorAbsolute(derived.nextCheckAt, {}, now); // local time, e.g. "Today, 4:08 PM"
+ if (derived.source === "scheduled-retry" && scheduledRetryReason === "ai_connection_pool_wait") {
+ return {
+ bannerTitle: "Pool exhausted",
+ stripTitle: "Pool exhausted",
+ bannerMeta: [`Usage recheck ${eta} · ${absolute} (your time)`, "This task keeps its account and resumes when usage permits."],
+ stripMeta: [`Usage recheck ${eta} · ${absolute}`, "The selected account stays pinned."],
+ tone: "info",
+ };
+ }
+
const isScheduledRetryOnly = derived.source === "scheduled-retry";
let bannerTitle: string;