# AgentSessionWrapper Idle Timeout Behavior in Pi Web: 10-Minute Session Management

> Understand AgentSessionWrapper idle timeout behavior in Pi Web. Learn how inactive sessions reset after 10 minutes of inactivity. Maximize session efficiency.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: deep-dive
- Published: 2026-07-25

---

**The `AgentSessionWrapper` in Pi Web automatically destroys inactive sessions after 10 minutes of idle time, resetting the timer whenever a session starts or receives an RPC command.**

The `agegr/pi-web` repository implements automatic resource cleanup through the `AgentSessionWrapper` class to prevent orphaned sessions from consuming server resources. This idle timeout mechanism ensures that abandoned sessions terminate automatically while keeping active workflows alive through intelligent activity detection.

## How the 10-Minute Idle Timeout Works

The idle timeout logic is hard-coded within the `AgentSessionWrapper` class in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts). When the wrapper detects 10 minutes of inactivity and no running operations, it triggers an automatic cleanup sequence.

### The resetIdleTimer() Implementation

The core timeout logic resides in the private `resetIdleTimer()` method, which creates a 10-minute timer (600,000 milliseconds) that checks session status before destruction:

```typescript
// lib/rpc-manager.ts
private resetIdleTimer(): void {
  if (this.idleTimer) clearTimeout(this.idleTimer);
  this.idleTimer = setTimeout(() => {
    // If something is still busy, keep the timer alive.
    if (this.isRunning()) {
      this.resetIdleTimer();
      return;
    }
    // No activity → clean up the session.
    this.destroy();
  }, 10 * 60 * 1000); // ← 10‑minute idle timeout
}

```

According to the source code at lines 61-70, this method first clears any existing timer to prevent duplicate timeouts, then schedules a new check. If the session is busy when the timer fires, the method recursively calls itself to extend the timeout period.

### Activity Events That Reset the Timer

Two primary actions refresh the idle deadline:

- **`start()`** – Initializes the timer when a session begins (lines 44-46)
- **`send()`** – Resets the timer on every incoming RPC command including prompts, abort requests, and Bash executions (lines 105-107)

Any interaction with the session through these methods extends the lifecycle by another 10 minutes from the moment of activity.

## Session Lifecycle Integration

The idle timeout integrates seamlessly with the wrapper's lifecycle methods to provide transparent resource management.

### Automatic Timer Initialization

When you create a new session via `startRpcSession()` in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) (lines 34-45), the wrapper automatically invokes `start()`, which calls `resetIdleTimer()` to begin the inactivity countdown immediately:

```typescript
import { startRpcSession } from "./lib/rpc-manager";

const { session } = await startRpcSession(
  "my-session-id",   // requested ID (may be generated)
  "",                // no pre‑existing session file → new session
  "/home/user/project",
  []                 // optional tool list
);
// `session.start()` is called inside `startRpcSession`, which
// starts the 10‑minute idle timer.

```

### Continuous Refresh on RPC Commands

Every command sent through the session extends its lifetime. When you call `send()` with any RPC payload, the wrapper executes `resetIdleTimer()` before processing the request:

```typescript
await session.send({ type: "prompt", message: "Explain the code." });
// `resetIdleTimer()` runs, extending the idle deadline by another 10 min.

```

This design ensures that long-running conversations or batch operations maintain session persistence as long as commands arrive within the 10-minute window.

### The isRunning() Safety Mechanism

Before destroying a session, the timeout handler verifies that no operations are active through the `isRunning()` helper (lines 40-42). This method returns `true` if the session is processing a prompt, streaming a response, running compaction, or executing a Bash command. When `isRunning()` returns `true`, `resetIdleTimer()` recurses instead of calling `destroy()`, preventing interruption of active workloads.

## Practical Implementation Examples

### Creating a Session with Auto-Cleanup

Sessions begin their idle countdown immediately upon creation:

```typescript
import { startRpcSession } from "./lib/rpc-manager";

const { session } = await startRpcSession(
  "production-agent-001",
  "",
  "/var/app",
  ["file-editor", "bash"]
);
// Idle timer starts automatically. If no commands sent for 10 minutes,
// session.destroy() runs automatically.

```

### Maintaining Session Activity

Keep sessions alive by sending periodic commands or heartbeats through the `send()` method:

```typescript
// This resets the 10-minute timer
await session.send({ type: "prompt", message: "Status check" });

// Timer is now reset to 10 minutes from this moment

```

### Manual Cleanup Before Timeout

You can bypass the idle timeout entirely by explicitly destroying the session:

```typescript
// Immediate teardown, bypassing the idle timer
session.destroy();

```

Calling `destroy()` marks the wrapper as dead, removes event listeners, aborts any running Bash processes, and notifies the UI immediately.

## Summary

- **10-minute hardcoded limit**: The idle timeout is fixed at `10 * 60 * 1000` milliseconds in [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts) and cannot be configured at runtime
- **Activity resets timer**: Any call to `start()` or `send()` invokes `resetIdleTimer()`, extending the session deadline by another 10 minutes
- **Busy-state protection**: The `isRunning()` method prevents destruction during active prompts, streaming, compaction, or Bash operations by recursively resetting the timer
- **Automatic resource reclamation**: When the timeout fires on an idle session, `destroy()` cleans up listeners, aborts subprocesses, and notifies the UI without requiring manual intervention

## Frequently Asked Questions

### Can I configure the idle timeout duration?

No, the timeout is hard-coded to 10 minutes in the `resetIdleTimer()` method at line 69 of [`lib/rpc-manager.ts`](https://github.com/agegr/pi-web/blob/main/lib/rpc-manager.ts). The value `10 * 60 * 1000` is not exposed as a configuration parameter, so modifying the timeout requires changing the source code and rebuilding the application.

### What happens if a command is running when the idle timer fires?

The session remains alive. When the timer callback executes, it checks `isRunning()` to detect active prompts, streaming responses, compaction tasks, or Bash processes. If any operation is active, the method calls `resetIdleTimer()` recursively instead of `destroy()`, effectively extending the timeout until the operation completes and the next idle period begins.

### How can I manually terminate a session before the idle timeout?

Call the `destroy()` method directly on the session instance. This immediately triggers cleanup logic including listener removal, Bash process abortion, and UI notification, bypassing the 10-minute idle wait. This is useful when you know a session is complete and want to free resources immediately.

### Which specific activities prevent the session from being destroyed?

The `isRunning()` method (lines 40-42) returns `true` and prevents destruction when the session has an active prompt request, is streaming a response back to the client, is running compaction operations, or has an executing Bash command. Only when none of these states are active will the idle timeout successfully call `destroy()`.