Skip to content

fix(cloud-agent-next): recover stalled ingest reconnects and stuck preparing UI - #5447

Merged
eshurakov merged 2 commits into
mainfrom
eshurakov/windy-sparrow
Aug 25, 2026
Merged

fix(cloud-agent-next): recover stalled ingest reconnects and stuck preparing UI#5447
eshurakov merged 2 commits into
mainfrom
eshurakov/windy-sparrow

Conversation

@eshurakov

Copy link
Copy Markdown
Contributor

Summary

Stops cloud-agent sessions from hanging after a stalled ingest reconnect or an early environment-preparation failure.

Ingest reconnect

  • Keep retrying ingest handshakes until close() instead of giving up after 3 attempts.
  • Cap backoff at 8s.
  • Use a 90s timeout for reconnect handshakes so a blocked Durable Object can still accept the in-flight socket. Aborting at 10s left zombie ingest sockets the wrapper had already abandoned (see agent_0d012c64).
  • Initial connect still fail-fasts at 10s (bad WORKER_URL / network).

Preparing status

  • finalize() now creates the preparation attempt when no progress was observed, so clients get a terminal status instead of staying on "Setting up environment".
  • Ignore progress callbacks after the attempt is finalized (and skip the matching volatile broadcast).
  • SDK clears a stale preparing composer status when cloud.message.failed arrives.

Test plan

  • packages/cloud-agent-sdk: src/service-state.test.ts (166 passed)
  • services/cloud-agent-next: src/session/preparation-progress.test.ts and test/unit/wrapper/reconnection.test.ts (77 passed)
  • Confirm a hung DO ingest accept after ~10s is still picked up by the wrapper instead of becoming a zombie socket
  • Confirm an early prep failure (no progress events) leaves the composer in an error state, not "Setting up environment"

Comment thread services/cloud-agent-next/src/session/preparation-progress.ts Outdated
Comment thread packages/cloud-agent-sdk/src/service-state.ts
@kilo-code-bot

kilo-code-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental change scopes preparation settlement to observed attempts and the workspace-ready boundary; the previous synthesized-failure issue is resolved.

Files Reviewed (5 files)
  • services/cloud-agent-next/src/persistence/CloudAgentSession.ts
  • services/cloud-agent-next/src/session/preparation-progress.ts
  • services/cloud-agent-next/src/session/preparation-progress.test.ts
  • services/cloud-agent-next/src/session/session-message-queue.ts
  • services/cloud-agent-next/test/integration/session/execute-directly-failure.test.ts
Previous Review Summaries (2 snapshots, latest commit 4cfd380)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 4cfd380)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

finalize() still synthesizes a preparation failure for terminal no-progress send() errors (billing, SANDBOX_CAPABILITY_UNAVAILABLE) on already-prepared sessions, which can leave the composer disabled.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/src/session/preparation-progress.ts 114 Default finalize() still synthesizes a prep failure for every no-progress terminal send() error; only WRAPPER_FINALIZING holds are skipped
Files Reviewed (11 files)
  • packages/cloud-agent-sdk/src/service-state.ts - 0 issues
  • packages/cloud-agent-sdk/src/service-state.test.ts - 0 issues
  • services/cloud-agent-next/src/persistence/CloudAgentSession.ts - 0 issues
  • services/cloud-agent-next/src/session/delivery-outcome.ts - 0 issues
  • services/cloud-agent-next/src/session/delivery-outcome.test.ts - 0 issues
  • services/cloud-agent-next/src/session/preparation-progress.ts - 1 issue
  • services/cloud-agent-next/src/session/preparation-progress.test.ts - 0 issues
  • services/cloud-agent-next/src/session/session-message-queue.ts - 0 issues
  • services/cloud-agent-next/test/integration/session/execute-directly-failure.test.ts - 0 issues
  • services/cloud-agent-next/test/unit/wrapper/reconnection.test.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/connection.ts - 0 issues

Fix these issues in Kilo Cloud

Previous review (commit 35c0b7a)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

finalize() and the SDK cloud.message.failed handler can mark a ready or interrupted session as a preparation error and leave the composer disabled.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/src/session/preparation-progress.ts 100 finalize() synthesizes a prep failure for every no-progress send() error, including billing/WRAPPER_FINALIZING
packages/cloud-agent-sdk/src/service-state.ts 597 Any cloud.message.failed while preparing becomes a cloud error, including user interrupt
Files Reviewed (7 files)
  • packages/cloud-agent-sdk/src/service-state.ts - 1 issue
  • packages/cloud-agent-sdk/src/service-state.test.ts - 0 issues
  • services/cloud-agent-next/src/session/preparation-progress.ts - 1 issue
  • services/cloud-agent-next/src/session/preparation-progress.test.ts - 0 issues
  • services/cloud-agent-next/src/persistence/CloudAgentSession.ts - 0 issues
  • services/cloud-agent-next/wrapper/src/connection.ts - 0 issues
  • services/cloud-agent-next/test/unit/wrapper/reconnection.test.ts - 0 issues

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 99.5K · Output: 13.7K · Cached: 668.5K

Review guidance: REVIEW.md from base branch main

…eparing UI

Wrapper reconnects no longer stop after 3 attempts. Hung reconnect
handshakes wait 90s so a blocked Durable Object can still accept the
in-flight socket instead of leaving zombie ingest connections. Retrying
is bounded by wall clock rather than attempt count — a stale run/
connection fence is rejected with 409 forever and a failed WebSocket
upgrade exposes no status to classify — so the wrapper still reports a
disconnect and aborts its Kilo turn instead of retrying into a socket
nobody will accept.

Early preparation failures now emit a terminal attempt, and the SDK
clears a stale preparing composer status when delivery fails. A held
delivery is excluded from both: the message stays queued and is retried
moments later, so inventing a failed attempt for it would flash a
spurious preparation failure. A hold raised after preparation already
started still terminalizes its attempt. An interrupt clears the stale
preparing status rather than raising an error banner, since the user
cancelling is not a failure.
@eshurakov
eshurakov force-pushed the eshurakov/windy-sparrow branch from 35c0b7a to 4cfd380 Compare August 24, 2026 10:19

@pandemicsyn pandemicsyn left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not positive on this one, i think the bot finding is correct. At services/cloud-agent-next/wrapper/src/connection.ts:1351, scheduleReconnect() checks the five-minute RECONNECT_TOTAL_BUDGET_MS and, once elapsed, stops the campaign and calls onDisconnect. The main callback then aborts the active session and closes/drains the wrapper, so an ingest outage that lasts past the budget cannot reconnect later within that turn i think ? Which i guess now that i write it out loud is actually ok ?

prepapproved either way

if (reconnectAttempt > MAX_RECONNECT_ATTEMPTS) {
logToFile(`reconnection failed after ${MAX_RECONNECT_ATTEMPTS} attempts — giving up`);
const elapsed = Date.now() - reconnectStartedAt;
if (elapsed >= RECONNECT_TOTAL_BUDGET_MS) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

bot: The reconnect loop still gives up after five minutes instead of retrying until close().

Suggested fix: Do not terminate the reconnect campaign based on RECONNECT_TOTAL_BUDGET_MS. Keep the capped backoff retry loop active until close() cancels it, and replace the budget-exhaustion unit test with coverage that verifies retries remain scheduled beyond five minutes. If permanent fencing must terminate the turn, detect that specific server response rather than applying a wall-clock cutoff to every reconnect failure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Keeping the five-minute ceiling. Bun does not expose the WebSocket upgrade status, so transient outages are indistinguishable from permanent rejections such as a stale fence. Five minutes allows several 90s stalled handshakes to recover, while still ensuring a permanently invalid wrapper eventually aborts and drains instead of retrying forever. I’ll align the PR description with that behavior.

@eshurakov
eshurakov merged commit a9a8a98 into main Aug 25, 2026
20 checks passed
@eshurakov
eshurakov deleted the eshurakov/windy-sparrow branch August 25, 2026 09:35
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