# How GenericAgent Preserves Browser Session State and Login Sessions: A Deep Dive into the TMWebDriver Architecture

> GenericAgent safeguards browser session state and login sessions by keeping WebDriver in memory and serializing credentials to disk. Survivor browser tabs and authenticated sessions across restarts.

- Repository: [LJQ/GenericAgent](https://github.com/lsdefine/GenericAgent)
- Tags: deep-dive
- Published: 2026-04-16

---

**GenericAgent maintains browser sessions in memory via a singleton WebDriver instance while serializing login credentials to disk, ensuring that browser tabs and authenticated sessions survive across multiple tool calls and process restarts.**

The `lsdefine/GenericAgent` repository implements a stateful browser automation system that allows LLM agents to interact with web pages without losing context between operations. Unlike ephemeral browser instances that terminate after each action, this architecture preserves both **browser session state** (open tabs, navigation history) and **login sessions** (authentication tokens) through persistent in-memory data structures and local file storage.

## How Browser Sessions Survive Across Tool Calls

### The WebSocket and HTTP Server Architecture

At the core of session persistence lies `TMWebDriver`, which initializes both a **WebSocket server** for Chrome DevTools Protocol communication and an **HTTP long-poll server** for browser extension connectivity. These servers start immediately upon instantiation in `TMWebDriver.__init__`, creating the infrastructure that maintains persistent connections to browser tabs【[TMWebDriver.py#L37-L46](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py#L37-L46)】.

Because these servers run continuously within the Python process, they maintain open channels to the browser extension, eliminating the need to re-establish connections for every automation command.

### Session Objects and State Tracking

Each browser tab maps to a `Session` instance that stores critical state metadata. The `Session` class definition in [`TMWebDriver.py`](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py) captures:

- `id` – the unique tab identifier
- `url` – current page location
- `connect_at` / `disconnect_at` – activity timestamps for lifecycle management
- `type` – connection protocol (`'ws'`, `'ext_ws'`, or `'http'`)
- **client** reference – either a WebSocket object or HTTP Queue【[TMWebDriver.py#L8-L15](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py#L8-L15)】

This object-oriented approach ensures that tab-specific state remains accessible throughout the agent's execution, enabling seamless interaction with specific pages across multiple LLM tool invocations.

### Registration and Auto-Reconnection Logic

When a browser extension connects (signaled by `type == 'ready'`), the `_register_client` method either creates a new `Session` or updates an existing one. If a tab disconnects unexpectedly, `Session.mark_disconnected` flags the session while preserving its metadata, allowing the driver to **auto-switch** to the most recent active tab without losing the session registry【[TMWebDriver.py#L65-L75](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py#L65-L75)】.

This reconnection tolerance ensures that temporary network interruptions or browser hibernation do not force the agent to restart its browsing workflow.

### Automatic Cleanup of Stale Sessions

To prevent memory leaks while preserving valid sessions, `TMWebDriver.clean_sessions` removes entries disconnected for more than 10 minutes. This background maintenance runs automatically, keeping the session dictionary lean without terminating active tabs that the agent might need to revisit【[TMWebDriver.py#L14-L20](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py#L14-L20)】.

### Default Tab Tracking for Multi-Tab Workflows

The driver maintains `self.default_session_id`, which points to the currently active tab. This reference updates whenever new tabs arrive or when explicit switching occurs via `web_scan` or `web_execute_js` calls【[TMWebDriver.py#L41-L43](https://github.com/lsdefine/GenericAgent/blob/main/TMWebDriver.py#L41-L43)】.

By tracking a default session, the agent can execute JavaScript or capture screenshots without specifying a tab ID every time, streamlining the interaction model while maintaining full multi-tab capability.

### Singleton Pattern in ga.py

The [`ga.py`](https://github.com/lsdefine/GenericAgent/blob/main/ga.py) module instantiates a single `TMWebDriver` object at startup through `first_init_driver`. All subsequent tool calls—whether scanning pages, executing JavaScript, or navigating URLs—reuse this same driver instance【[ga.py#L99-L104](https://github.com/lsdefine/GenericAgent/blob/main/ga.py#L99-L104)】.

Because the driver persists in RAM for the entire process lifetime, the `self.sessions` dictionary remains intact across all LLM interactions, effectively freezing browser state between reasoning cycles.

## Persisting Login Sessions to Disk

### WeChat Token Persistence Example

For authentication that must survive process restarts, GenericAgent implements file-based persistence. The WeChat frontend ([`frontends/wechatapp.py`](https://github.com/lsdefine/GenericAgent/blob/main/frontends/wechatapp.py)) demonstrates this pattern through its `WxBotClient` class:

After QR-code authentication succeeds, the `_save` method writes `bot_token` and `ilink_bot_id` to `~/.wxbot/token.json`【[wechatapp.py#L34-L38](https://github.com/lsdefine/GenericAgent/blob/main/frontends/wechatapp.py#L34-L38)】. On subsequent startups, the constructor calls `_load` to read this file, bypassing the QR login if valid credentials exist【[wechatapp.py#L29-L33](https://github.com/lsdefine/GenericAgent/blob/main/frontends/wechatapp.py#L29-L33)】.

### Generic Pattern for Frontend Authentication

This approach generalizes across any authentication-dependent frontend: store credentials in a user-specific JSON file outside the source tree, then load them during initialization. The agent never embeds secrets in [`mykey.py`](https://github.com/lsdefine/GenericAgent/blob/main/mykey.py) or version control; only the local token file holds persistent authentication state.

## Practical Implementation Examples

```python

# 1️⃣ Initialise the driver (done automatically by GenericAgent)

from TMWebDriver import TMWebDriver
driver = TMWebDriver()               # starts WS & HTTP servers

# 2️⃣ List all active browser tabs – the session IDs are stable

sessions = driver.get_all_sessions()
print(sessions)                      # [{'id': '12345', 'url': 'https://example.com/...'}, ...]

# 3️⃣ Switch the default tab (e.g. the second tab) before running JS

second_tab_id = sessions[1]['id']
driver.default_session_id = second_tab_id

# 4️⃣ Execute JavaScript in the current default tab

result = driver.execute_js("document.title")
print(result)                        # {'js_return': 'Example Domain', ...}

# 5️⃣ The driver automatically cleans up dead tabs

driver.clean_sessions()              # removes sessions idle >10 min

# -----------------------------------------------------------------

# 6️⃣ WeChat login persistence (run once, then reuse)

from frontends.wechatapp import WxBotClient

bot = WxBotClient()
if not bot.token:                     # first run – QR login required

    bot.login_qr()                    # stores token in ~/.wxbot/token.json

else:
    print("Already logged in as", bot.bot_id)   # token read from file

```

## Summary

- **In-memory session persistence**: `TMWebDriver` maintains a `sessions` dictionary that maps tab IDs to `Session` objects, surviving across all tool calls within a single process.
- **Dual-server architecture**: WebSocket and HTTP long-poll servers provide robust communication channels that handle reconnections without losing browser context.
- **Automatic lifecycle management**: The `clean_sessions` method prevents memory leaks by purging disconnected tabs after 10 minutes while keeping active sessions intact.
- **Default tab tracking**: The `default_session_id` attribute enables seamless multi-tab workflows without explicit tab selection on every operation.
- **Authentication serialization**: Frontend modules like [`wechatapp.py`](https://github.com/lsdefine/GenericAgent/blob/main/wechatapp.py) demonstrate persisting login tokens to `~/.wxbot/token.json`, eliminating redundant authentication after restarts.

## Frequently Asked Questions

### How does GenericAgent handle browser disconnections?

The `TMWebDriver` marks disconnected sessions via `Session.mark_disconnected` but retains their metadata in memory. When the browser extension reconnects, `_register_client` matches the new connection to existing session data using the tab ID, allowing seamless continuation of interrupted workflows without restarting the browser instance.

### Where are login credentials stored?

Login credentials serialize to local JSON files within the user's home directory (e.g., `~/.wxbot/token.json` for WeChat). This keeps sensitive data out of the source repository while ensuring that `WxBotClient` can authenticate immediately upon initialization without requiring manual QR-code scanning on every startup.

### Can GenericAgent maintain multiple browser tabs simultaneously?

Yes. The driver maintains a dictionary of `Session` objects, each representing a distinct browser tab with its own URL, connection type, and client reference. The `default_session_id` property determines which tab receives commands, but agents can switch contexts dynamically by updating this pointer or addressing specific session IDs directly.

### What happens to sessions when the Python process restarts?

Browser sessions (tab states) exist only in RAM and disappear upon process termination, requiring the browser extension to reconnect and re-register tabs. However, **login sessions** persist because the authentication tokens serialize to disk; the WeChat frontend automatically reloads these credentials via `_load`, restoring authenticated state without user intervention.