Skip to content

perf(agents): keep active sessions warm and reap idle state - #195

Closed
Waishnav wants to merge 7 commits into
perf/pi-in-process-runtimefrom
perf/claude-warm-runtime
Closed

perf(agents): keep active sessions warm and reap idle state#195
Waishnav wants to merge 7 commits into
perf/pi-in-process-runtimefrom
perf/claude-warm-runtime

Conversation

@Waishnav

@Waishnav Waishnav commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Claude still restarts its CLI-backed query between turns, and multiplexed runtimes can retain provider sessions long after those sessions stop being useful. This keeps one streaming Claude query warm per active DevSpace agent and completes the pool lifecycle with provider-owned idle-session reaping: Codex can unsubscribe threads, ACP can close sessions when supported, and Pi can dispose idle AgentSessions without tearing down a shared runtime.\n\nThe runtime pool remains provider-agnostic: it only asks a runtime to reap idle session state and still treats every live runtime as disposable. Claude stays intentionally per-agent rather than being multiplexed across unrelated conversations. Stacked on #194.

Summary by CodeRabbit

  • New Features

    • Added support for persistent Claude sessions, enabling smoother multi-turn interactions and session resumption.
    • Added automatic cleanup of idle local-agent sessions to reduce stale activity while preserving active work.
    • Improved handling when sessions expire, fail, or require updated model settings.
    • Agent executions now retain the correct agent identity across requests.
  • Documentation

    • Clarified the Claude provider’s streaming-session behavior.
  • Tests

    • Expanded coverage for session reuse, cleanup, resumption, model updates, and concurrent activity.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8aa86530-1299-4524-87c0-a28466cf383a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds a warm Claude streaming runtime, routes Claude through the shared runtime pool, passes agent IDs through local-agent execution, and adds idle-session reaping for ACP, Codex, and Pi runtimes.

Changes

Local-agent runtime lifecycle

Layer / File(s) Summary
Warm Claude runtime integration
src/local-agent-claude/runtime.ts, src/local-agent-adapters.ts, src/local-agent-runtime-registry.ts, src/local-agent-runtime.ts, src/local-agent-manager.ts, src/local-agent-claude/runtime.test.ts, docs/agent-profile-schema.md, package.json
Claude now uses a reusable streaming runtime with session resumption, model updates, query replacement, environment sanitization, and pooled driver creation. Local-agent execution passes agentId, and Claude routes through the shared runtime pool. Tests and documentation cover the new flow.
Runtime pool maintenance and synchronization
src/local-agent-runtime-pool.ts, src/local-agent-runtime-pool.test.ts
The pool schedules idle maintenance, waits for maintenance during acquisition and shutdown, and closes idle runtime slots after activity checks. Tests cover timestamps, closure, and maintenance races.
Provider session activity and reaping
src/local-agent-acp/runtime.ts, src/local-agent-codex/runtime.ts, src/local-agent-pi/runtime.ts, src/local-agent-acp/*, src/local-agent-codex/runtime.test.ts, src/local-agent-pi/runtime.test.ts
ACP, Codex, and Pi runtimes track active state and last-use timestamps. Idle sessions are closed or unsubscribed after five minutes. Failed cleanup remains available for retry. Tests cover reaping and session recreation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LocalAgentManager
  participant LocalAgentRuntimeRegistry
  participant RuntimePool
  participant ClaudeWarmRuntime
  participant ClaudeSDK
  LocalAgentManager->>LocalAgentRuntimeRegistry: executeTurn with agentId
  LocalAgentRuntimeRegistry->>RuntimePool: route Claude run
  RuntimePool->>ClaudeWarmRuntime: acquire pooled runtime
  ClaudeWarmRuntime->>ClaudeSDK: stream prompt or resume session
  ClaudeSDK-->>ClaudeWarmRuntime: result message and session ID
  ClaudeWarmRuntime-->>RuntimePool: return run result
  RuntimePool-->>LocalAgentRuntimeRegistry: return provider response
Loading

Possibly related PRs

  • Waishnav/devspace#55: Provides the local-agent runtime architecture extended here with warm Claude sessions and idle-session reaping.
  • Waishnav/devspace#183: Introduces runtime-pool and provider-runtime changes extended here with idle maintenance and Claude pooling.
  • Waishnav/devspace#190: Shares local-agent manager execution changes extended here to pass agentId.

Poem

A rabbit watched warm queries stream,
While idle sessions left the dream.
Pools now wait, then clean with care,
Claude hops through a session there.
“Reuse, reap, and run anew!”
Said Bunny, “That’s efficient too!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main changes: keeping active sessions warm and reaping idle sessions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/claude-warm-runtime

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.

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds a pooled warm Claude SDK runtime and provider-level idle-session cleanup while preserving durable conversation identifiers.

  • Routes Claude runs through the shared runtime pool using the DevSpace agent ID as the runtime key.
  • Adds five-minute idle cleanup for ACP sessions, Codex subscriptions, and Pi sessions.
  • Extends tests and documentation for warm-runtime reuse and cleanup behavior.

Confidence Score: 4/5

The idle-reaping race should be fixed before merging because it can terminate a provider runtime after a new turn has already started.

The new awaited per-provider cleanup separates the pool's activity check from eviction, allowing a concurrent run to make the slot active before the reaper deletes and closes it.

Files Needing Attention: src/local-agent-runtime-pool.ts

Important Files Changed

Filename Overview
src/local-agent-claude/runtime.ts Adds a persistent Claude SDK query, prompt queue, model switching, resumable session handling, and runtime driver.
src/local-agent-runtime-pool.ts Adds provider-level idle cleanup, but the awaited cleanup creates a race that can close a newly active runtime.
src/local-agent-acp/runtime.ts Tracks ACP session activity and closes idle sessions when the provider advertises support.
src/local-agent-codex/runtime.ts Tracks thread activity and unsubscribes idle Codex threads without shutting down the shared app server.
src/local-agent-pi/runtime.ts Wraps Pi sessions with activity metadata and disposes idle in-memory sessions for later durable reopening.
src/local-agent-runtime-registry.ts Registers Claude as a pooled harness driver alongside Codex, ACP, and Pi.

Sequence Diagram

sequenceDiagram
    participant Timer as Idle reaper
    participant Pool as Runtime pool
    participant Run as New turn
    participant Runtime as Provider runtime
    Timer->>Pool: reapIdle()
    Pool->>Pool: "observe activeRuns == 0"
    Pool->>Runtime: await reapIdleSessions(now)
    Run->>Pool: acquire same ready slot
    Pool->>Pool: activeRuns++
    Run->>Runtime: run(input)
    Runtime-->>Pool: cleanup returns
    Pool->>Pool: delete slot
    Pool->>Runtime: close()
    Runtime-->>Run: active turn fails
Loading

Reviews (1): Last reviewed commit: "perf(agents): reclaim idle provider sess..." | Re-trigger Greptile

Comment thread src/local-agent-runtime-pool.ts Outdated
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from 5f76ffb to c7233f2 Compare August 12, 2026 01:52
@Waishnav Waishnav changed the title perf/claude warm runtime perf(agents): keep active sessions warm and reap idle state Aug 12, 2026
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from c7233f2 to 4529736 Compare August 12, 2026 02:03
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from 4529736 to 0b3d090 Compare August 12, 2026 02:15
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from 0b3d090 to f9086d1 Compare August 12, 2026 02:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/local-agent-claude/runtime.test.ts (1)

83-100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the failure and stream-end paths.

The test covers reuse, model change, effort-triggered replacement, and close. It does not cover the two paths in ClaudeWarmRuntime.run that call resetQuery on failure:

  • next() resolves with done: true, which must throw "Claude session ended before returning a result." and discard the live query.
  • A result message with is_error: true, which must throw and discard the live query.

Both paths must leave the runtime able to start a fresh query and resume from the persisted provider session id. That recovery behavior is the reason the warm runtime is safe to pool. Add a case that forces a failure and then asserts the next run creates a new query with resume set to the persisted session id.

Based on learnings, add and maintain behavior and regression tests for affected contracts and lifecycle behavior.

🤖 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/local-agent-claude/runtime.test.ts` around lines 83 - 100, Add regression
coverage around ClaudeWarmRuntime.run for both resetQuery failure paths: a
stream ending before a result and an is_error result message. Assert each throws
the expected error, discards the live query, and allows the following run to
create a fresh query resumed with the persisted provider session id.

Source: Learnings

src/local-agent-claude/runtime.ts (1)

42-85: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Reject concurrent turns on one warm runtime.

run pushes a prompt and then drains live.query.next() in a loop. Two overlapping run calls share one iterator. Each call would consume messages belonging to the other turn, and both results would be wrong.

The manager serializes turns per agent, and the pool key is the agent id, so the current call path is safe. The runtime itself does not enforce this. CodexAppServerRuntime.run and the ACP runtime both reject a second concurrent turn with an explicit error. Add the same guard here to keep the invariant local and testable.

♻️ Proposed guard
 export class ClaudeWarmRuntime implements HarnessRuntime {
   private live: LiveClaudeQuery | undefined;
   private providerSessionId: string | undefined;
   private closed = false;
+  private turnInProgress = false;
 
   constructor(private readonly createQuery: ClaudeQueryFactory) {}
 
   async run(input: LocalAgentRunInput): Promise<LocalAgentRunResult> {
     if (this.closed) throw new Error("Claude runtime is closed.");
+    if (this.turnInProgress) {
+      throw new Error("Claude runtime already has a turn in progress.");
+    }
+    this.turnInProgress = true;
+    try {

Close the try with a finally { this.turnInProgress = false; } around the existing body.

🤖 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/local-agent-claude/runtime.ts` around lines 42 - 85, Update the Claude
runtime class and its run method to reject a second concurrent turn with an
explicit error before mutating the shared query state. Track turn ownership with
a turnInProgress guard, set it when entering run, and clear it in a finally
block covering the existing query-draining logic, including error and success
paths.
package.json (1)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the manual test chain with Node.js test discovery.

The package requires Node.js 22.19 or newer, and the current script lists all 31 test files manually. Use the test runner to include new suites automatically and report failures from later suites:

Example replacement
-    "test": "tsx src/config.test.ts && ... && tsx src/cli.test.ts",
+    "test": "tsx --test \"src/**/*.test.ts\"",

Node.js process isolation keeps the existing top-level assertion suites and their environment changes isolated.

🤖 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 `@package.json` at line 31, Replace the manual test command in the package
scripts with Node.js 22.19+ test discovery, using process isolation so the
existing top-level assertion suites and environment changes remain isolated.
Configure discovery to include the current test files automatically and ensure
failures from later suites are still reported.
🤖 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 `@src/local-agent-claude/runtime.ts`:
- Around line 97-109: Update ensureQuery to bind each live query to
input.workspace: store the workspace when creating this.live, compare it
alongside thinking before reusing the existing query, and reset/recreate (or
explicitly reject) when the workspace differs. Preserve reuse only when both
workspace and effort match, ensuring createQuery receives the current workspace
context.

In `@src/local-agent-runtime-pool.ts`:
- Around line 83-85: The cleanup loop in maintainSlot must not use runtime-wide
activeRuns to suppress reaping of unrelated sessions. Add session-level
coordination so idle sessions can be cleaned while another PiHarnessRuntime
session is active, or defer cleanup until the runtime becomes idle, and add
coverage for the mixed idle/active-session case across the process and subagent
lifecycle.

---

Nitpick comments:
In `@package.json`:
- Line 31: Replace the manual test command in the package scripts with Node.js
22.19+ test discovery, using process isolation so the existing top-level
assertion suites and environment changes remain isolated. Configure discovery to
include the current test files automatically and ensure failures from later
suites are still reported.

In `@src/local-agent-claude/runtime.test.ts`:
- Around line 83-100: Add regression coverage around ClaudeWarmRuntime.run for
both resetQuery failure paths: a stream ending before a result and an is_error
result message. Assert each throws the expected error, discards the live query,
and allows the following run to create a fresh query resumed with the persisted
provider session id.

In `@src/local-agent-claude/runtime.ts`:
- Around line 42-85: Update the Claude runtime class and its run method to
reject a second concurrent turn with an explicit error before mutating the
shared query state. Track turn ownership with a turnInProgress guard, set it
when entering run, and clear it in a finally block covering the existing
query-draining logic, including error and success paths.
🪄 Autofix

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: 73394a35-e7e3-4495-994c-10da19faa050

📥 Commits

Reviewing files that changed from the base of the PR and between 8a19605 and 0b3d090.

📒 Files selected for processing (16)
  • docs/agent-profile-schema.md
  • package.json
  • src/local-agent-acp/runtime.ts
  • src/local-agent-adapters.ts
  • src/local-agent-claude/runtime.test.ts
  • src/local-agent-claude/runtime.ts
  • src/local-agent-codex/runtime.test.ts
  • src/local-agent-codex/runtime.ts
  • src/local-agent-manager.test.ts
  • src/local-agent-manager.ts
  • src/local-agent-pi/runtime.test.ts
  • src/local-agent-pi/runtime.ts
  • src/local-agent-runtime-pool.test.ts
  • src/local-agent-runtime-pool.ts
  • src/local-agent-runtime-registry.ts
  • src/local-agent-runtime.ts

Comment thread src/local-agent-claude/runtime.ts
Comment thread src/local-agent-runtime-pool.ts Outdated
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from f9086d1 to a3da077 Compare August 12, 2026 02:30
@Waishnav
Waishnav force-pushed the perf/claude-warm-runtime branch from a3da077 to fbc19e6 Compare August 12, 2026 02:38
@Waishnav

Copy link
Copy Markdown
Owner Author

Closing this Sol stack PR in favor of the Luna-based implementation.

@Waishnav Waishnav closed this Aug 13, 2026
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.

1 participant