Skip to content

feat(cloud-agent-next): hold Kilo under memory pressure and explain restarts - #7290

Merged
eshurakov merged 6 commits into
mainfrom
eshurakov/calm-pebble
Oct 9, 2026
Merged

eshurakov merged 6 commits into
mainfrom
eshurakov/calm-pebble

Conversation

@eshurakov

Copy link
Copy Markdown
Contributor

Summary

Keeps Kilo alive under memory pressure in workspace_* sessions, and tells the user what happened when a control-plane failure ends a turn.

Memory protection and hold (wrapper)

  • control.workload stats now split memory between tools and the Kilo server (current, peak, anon, file, shmem).
  • Each Kilo scope group and server cgroup gets memory.min = 1 GiB, so reclaim at the shared workload cap takes tools and page cache first. It is optional: if the kernel refuses the write, the hard caps stay and a failed control.workload protection record goes to the native logs.
  • The watchdog samples the shared workload cgroup every 5 s. It counts as reclaiming at the cap when usage is within 256 MiB of memory.max and the memory.events max counter rose since the previous sample.
  • While it reclaims, a hang restart is held instead of run. This covers the three hang triggers: no health answer, the reconnect budget, or failed activity observation.
    • Kilo keeps running, and the decision is made again at every check.
    • The hold ends as recovered once Kilo delivers events and its activity is observable.
    • Otherwise it ends in the restart after two quiet samples, or after at most 10 minutes per episode.
    • A cap full of idle page cache does not raise the counter, so it never holds.
  • While held:
    • the runtime's native executions pause their no-progress clocks (overlap with a user wait counts once);
    • the 120 s prompt delivery deadline does not run;
    • each turn on the runtime gets a non-fatal error notice. Nothing acts on it.
  • Hold start and end are logged as kilo_memory_hold_started / kilo_memory_hold_ended.

Failure text and stale busy (Worker, wrapper, mobile)

  • New reason agent_unresponsive for a turn, or interrupted native work, failed by a Kilo hang restart. Other restarts stay agent_restarted, including activity-capacity ones. Telemetry classifies it like agent_restarted.

  • cloud.message.failed error now carries readable text for control-plane reasons, live and on reconnect, for example "Kilo was not responding and was restarted". reason keeps the raw code. The text table moved from callbacks to failure-messages.ts, and Kilo-written reasons pass through unchanged.

  • On reconnect, connected now carries sessionStatus: idle when all three hold:

    • Kilo's last stored root status is busy/retry;
    • an accepted message settled after that status;
    • no message is accepted now.

    Previously, a reload after a hang or kill re-applied Kilo's stale busy. Native work without a Cloud message keeps Kilo's replayed status.

  • Mobile adds the new texts to its safe copy, so it no longer shows the generic "The response failed." The safe list moved to its own module because of max-lines.

  • .specs/cloud-agent-session.md gains the hold and failure-text rules. docs/control-plane.md and DEBUG.md are updated.

Failure UX, both effects

  • Spurious restarts: a hang restart that was only a reclaim stall becomes a wait, so the turn survives.
  • Genuine hangs: a real hang during real memory pressure now takes up to about 10.5 min to restart. Before, it took about 35 s through the health probe, or about 2 min through the observation path. The 120 s delivery deadline is also held for that time.

Deploy order: deploy the Worker before the wrapper image. An old Worker accepts agent_unresponsive, because the outcome reason is free text. Until it is updated, that reason gets an unknown/unclassified report and the raw code as callback errorMessage.

Verification

No manual test was run. A real check needs a sandbox driven into reclaim at its memory cap. That would show whether memory.min takes effect on the container kernel and whether memory.events max behaves as expected there. Neither has been verified on a real sandbox.

Visual Changes

Before After
Web shows the raw code (agent_restarted, no_progress, …) above the composer and in the bubble tooltip Readable text, e.g. "Kilo was not responding and was restarted"
Mobile shows "The response failed." for control-plane reasons The readable reason text
Reloading after a hang/kill can show the session as busy Shows idle

The hold notice is posted, but the SDK currently turns non-fatal error events into a no-op warning, so web and mobile do not show it yet. The web delivery badge still says "Failed to deliver:" for an accepted message; that is unchanged.

Reviewer Notes

  • Rebased onto feat(cloud-agent-next): supervise native Kilo execution independently of Cloud turns #7256, which moved the no-progress clock into the session supervisor. The design choices that forced:
    • The pause lives in the supervisor's Execution, in the new execution-clock.ts. An execution that opens during a hold starts paused.
    • A held activity_observation fault does not latch (onFault returns false), and the activity keeps reading snapshots, so a recovered Kilo clears unhealthySince. abort_unconfirmed and activity_capacity still latch and never hold.
    • The watchdog is the hold's only sampler, so restart paths in the same check get one answer. The 10-minute cap covers the whole episode, and heartbeats alone do not end a hold while observation fails.
  • The reconnect idle rule is ordered by a persisted settled flag on the root status, not timestamps.
  • Not done:
    • memory.high on tools: without swap it throttles instead of a clean OOM.
    • A userspace "kill largest tool": memory.min already makes the kernel pick a tool.
    • The sidebar cli_sessions_v2.status, which Kilo writes through session ingest, can still show busy after a hang. Left as a follow-up.
  • memory.min also applies to the legacy plane, which shares the cgroup code. It does not protect against reclaim triggered above the shared workload cgroup.
  • Automated checks run:
    • services/cloud-agent-next: typecheck, lint, duplication ratchet, Worker unit (5982), integration (652), wrapper (1003).
    • apps/mobile: typecheck, lint, src/components/agents (4933).
    • Root format:check, lint and typecheck --changes-only.
    • One earlier full integration run had timeouts in three sandbox-control-v2-* files I did not touch; they passed alone and in the final full run.

Comment thread .specs/cloud-agent-session.md Resolved
@kilo-code-bot

kilo-code-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental commit correctly moves sandbox_out_of_memory attribution from a workload-at-cap check to an expired memory hold; one prior SUGGESTION remains unresolved in the Session DO (unchanged; author elected not to fix).

Overview

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

SUGGESTION

File Line Issue
services/cloud-agent-next/src/control-plane/session/session-do.ts 2487 The settled latch can report idle while Kilo is still busy (unchanged; author elected not to fix)
Files Reviewed (11 files)
  • .specs/cloud-agent-session.md
  • services/cloud-agent-next/DEBUG.md
  • services/cloud-agent-next/docs/control-plane.md
  • services/cloud-agent-next/src/telemetry/control-plane-failure.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-health-diagnostic.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts

Fix these issues in Kilo Cloud

Previous Review Summaries (3 snapshots, latest commit 1398bb6)

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

Previous review (commit 1398bb6)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental documentation changes correctly scope agent_unresponsive to non-activity-capacity hang restarts and split the Kilo-crash from the dead-event-stream case; one prior SUGGESTION remains unresolved in the Session DO.

Overview

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

SUGGESTION

File Line Issue
services/cloud-agent-next/src/control-plane/session/session-do.ts 2487 The settled latch can report idle while Kilo is still busy (unchanged; author elected not to fix)
Files Reviewed (37 files)
  • .specs/cloud-agent-session.md
  • apps/mobile/src/components/agents/safe-failure-messages.ts
  • apps/mobile/src/components/agents/session-terminal-error.test.ts
  • apps/mobile/src/components/agents/session-terminal-error.ts
  • services/cloud-agent-next/DEBUG.md
  • services/cloud-agent-next/docs/control-plane.md
  • services/cloud-agent-next/src/control-plane/session/callbacks.ts
  • services/cloud-agent-next/src/control-plane/session/failure-messages.ts
  • services/cloud-agent-next/src/control-plane/session/session-do.ts - 1 issue
  • services/cloud-agent-next/src/shared/control-diagnostics.test.ts
  • services/cloud-agent-next/src/shared/control-diagnostics.ts
  • services/cloud-agent-next/src/shared/control-plane-protocol.ts
  • services/cloud-agent-next/src/shared/control-plane-timers.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.test.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.ts
  • services/cloud-agent-next/test/integration/control-plane-session-v2.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/execution-clock.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/execution-clock.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-activity.real.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts
  • services/cloud-agent-next/wrapper/src/control-plane/main.ts
  • services/cloud-agent-next/wrapper/src/control-plane/runtime-activity.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/runtime-activity.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-host.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-supervisor.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-supervisor.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-budget.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts
  • services/cloud-agent-next/wrapper/src/control/workload-stats-fields.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-stats-fields.ts

Fix these issues in Kilo Cloud

Previous review (commit 58fef8b)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental documentation changes correctly scope agent_unresponsive to non-activity-capacity hang restarts, resolving three prior findings; one prior SUGGESTION remains in the Session DO.

Overview

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

SUGGESTION

File Line Issue
services/cloud-agent-next/src/control-plane/session/session-do.ts 2487 The settled latch can report idle while Kilo is still busy
Files Reviewed (2 files)
  • .specs/cloud-agent-session.md
  • services/cloud-agent-next/docs/control-plane.md

Fix these issues in Kilo Cloud

Previous review (commit 5104e36)

Status: 4 Issues Found | Recommendation: Address before merge

Executive Summary

No critical or blocking defects: the memory-hold state machine, execution-clock union accounting, workload-cgroup memory.min changes, and the mobile safe-copy move verified clean. The findings are documentation/spec inconsistencies with the same PR's activity_capacity carve-out plus one stale-status edge case in the Session DO.

Overview

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

WARNING

File Line Issue
services/cloud-agent-next/docs/control-plane.md 627 "after a hang restart" ignores the activity-capacity carve-out
.specs/cloud-agent-session.md 122 MUST contradicts the activity-capacity carve-out added in the same PR

SUGGESTION

File Line Issue
services/cloud-agent-next/docs/control-plane.md 725 Dead-event-stream failure reason stated as agent_restarted
services/cloud-agent-next/src/control-plane/session/session-do.ts 2487 settled latch can report idle while Kilo is still busy
Files Reviewed (37 files)
  • .specs/cloud-agent-session.md - 1 issue
  • apps/mobile/src/components/agents/safe-failure-messages.ts
  • apps/mobile/src/components/agents/session-terminal-error.test.ts
  • apps/mobile/src/components/agents/session-terminal-error.ts
  • services/cloud-agent-next/DEBUG.md
  • services/cloud-agent-next/docs/control-plane.md - 2 issues
  • services/cloud-agent-next/src/control-plane/session/callbacks.ts
  • services/cloud-agent-next/src/control-plane/session/failure-messages.ts
  • services/cloud-agent-next/src/control-plane/session/session-do.ts - 1 issue
  • services/cloud-agent-next/src/shared/control-diagnostics.test.ts
  • services/cloud-agent-next/src/shared/control-diagnostics.ts
  • services/cloud-agent-next/src/shared/control-plane-protocol.ts
  • services/cloud-agent-next/src/shared/control-plane-timers.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.test.ts
  • services/cloud-agent-next/src/telemetry/control-plane-failure.ts
  • services/cloud-agent-next/test/integration/control-plane-session-v2.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/execution-clock.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/execution-clock.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-activity.real.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-memory-hold.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/kilo-runtime.ts
  • services/cloud-agent-next/wrapper/src/control-plane/main.ts
  • services/cloud-agent-next/wrapper/src/control-plane/runtime-activity.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/runtime-activity.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-host.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-supervisor.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/session-supervisor.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.test.ts
  • services/cloud-agent-next/wrapper/src/control-plane/turn.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-budget.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup-stats.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-cgroup.ts
  • services/cloud-agent-next/wrapper/src/control/workload-stats-fields.test.ts
  • services/cloud-agent-next/wrapper/src/control/workload-stats-fields.ts

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 81.4K · Output: 20.7K · Cached: 1.2M

Review guidance: REVIEW.md from base branch main

…der pressure

- Report per-child memory stats (tools vs. Kilo server: current, peak,
  anon, file, shmem) in control.workload records.
- Set memory.min = 1 GiB on each Kilo scope group and server cgroup so
  reclaim at the shared workload cap takes tools and page cache first.
  It is optional: a refused write keeps the hard caps and emits a failed
  control.workload "protection" record, which reaches the native logs.
- Sample the shared workload cgroup at every watchdog check. While it
  reclaims at its cap (usage within 256 MiB of memory.max and the
  memory.events max counter rising), a hang restart (no health answer,
  reconnect budget, or failed activity observation) is held: Kilo keeps
  running and the decision is made again at each check, for at most 10
  minutes per episode. The hold ends as recovered once Kilo delivers
  events and its activity is observable, or with the restart after two
  quiet samples or at expiry. Hold start/end are logged.
- While held, the runtime's native executions pause their no-progress
  clocks (overlap with a user wait counts once), the 120 s prompt
  delivery deadline does not run, and each turn on the runtime gets a
  non-fatal notice.
…e busy on reconnect

- Add agent_unresponsive for a turn, or interrupted native work, failed
  by a Kilo hang restart (including one at the end of a memory hold);
  other Kilo restarts stay agent_restarted. Telemetry classifies it like
  agent_restarted.
- Send readable text in cloud.message.failed `error` for control-plane
  reasons (live and on reconnect); `reason` keeps the raw code. The
  reason-to-text table moves out of callbacks into failure-messages.ts,
  and Kilo-written reasons pass through unchanged.
- When Kilo's last root status is busy/retry, an accepted message has
  settled since, and none is accepted now, the connected event carries
  sessionStatus idle, so a reload after a hang or kill no longer applies
  the stale busy. Native work without a Cloud message keeps Kilo's
  replayed status.
- Mobile shows the new texts as safe copy instead of the generic
  failure line; the safe list moves to its own module (max-lines).
…tarts

A hang restart for exhausted activity tracking capacity is not Kilo
failing to answer, so it must not say Kilo was not responding.
The activity-capacity carve-out and the dead-event-stream path were
described with the wrong reason in the spec and the control-plane doc.
@eshurakov
eshurakov force-pushed the eshurakov/calm-pebble branch from 58fef8b to 1398bb6 Compare October 8, 2026 19:22
The restart attribution and the memory hold each decided whether the
sandbox was at its memory cap, with different rules. The attribution
compared one runtime's scope usage with the shared cap at 95%, which
misses a cap filled by sibling scopes and fires on reclaimable page
cache after a large build.

The hold is now the only owner: a hang restart that ends an expired
hold (the shared workload kept reclaiming at its cap for the whole
window) fails the turn as sandbox_out_of_memory. Other hang restarts
stay agent_unresponsive or agent_restarted. isWorkloadAtCap and its
95% fraction are removed; the per-scope snapshot stays on the restart
log line as diagnostic data only.
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