# NousResearch/hermes-agent · cua-driver session timeout and reconnect fixes

## Open now

- Nothing open on GitHub.

These issues and PRs address cua-driver session startup timeouts, dead session reconnection, and improved error messaging when sessions fail to become ready. Multiple timeout increases and a reconnect mechanism are proposed or discussed.

## TL;DR

- 4 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 2 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #58760. Verify it addresses your case.
- **Recommended:** read PR #58760 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-58801`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.50`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #57025: Windows/Desktop computer_use wrapper times out while cua-driver doctor and MCP test pass

## Prior & competing PRs

- **#58760: fix(computer-use): raise cua-driver session startup timeout to 30s + phase timing log (salvage #57034)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `tools/computer_use/cua_backend.py`
  - fix hunks:
  - `tools/computer_use/cua_backend.py`

    ```diff
    @@ -567,6 +567,7 @@ async def _lifecycle_coro(self) -> None:
             different task than it was entered in" warning emitted by the
             previous _aenter/_aexit split.
             """
    +        import time as _time
             from mcp import ClientSession, StdioServerParameters
             from mcp.client.stdio import stdio_client
             from tools.environments.local import _sanitize_subprocess_env
    ```

    ```diff
    @@ -574,6 +575,7 @@ async def _lifecycle_coro(self) -> None:
             # Build the shutdown event on the loop's thread so the asyncio
             # primitive belongs to the correct loop.
             self._shutdown_event = asyncio.Event()
    +        _t0 = _time.monotonic()
     
             try:
                 if not cua_driver_binary_available():
    ```

    ```diff
    @@ -583,6 +585,7 @@ async def _lifecycle_coro(self) -> None:
                 # the MCP server, instead of hardcoding ["mcp"]. Falls back
                 # transparently for older drivers / any discovery failure.
                 command, args = _resolve_mcp_invocation(_CUA_DRIVER_CMD)
    +            _t_manifest = _time.monotonic()
                 params = StdioServerParameters(
                     command=command,
                     args=args,
    ```

    ```diff
    @@ -594,12 +597,20 @@ async def _lifecycle_coro(self) -> None:
                 async with stdio_client(params) as (read, write):
                     async with ClientSession(read, write) as session:
                         await session.initialize()
    +                    _t_init = _time.monotonic()
                         # Populate capabilities + capability_version BEFORE
                         # exposing the session to callers, so the first
                         # tool call already sees them.
                         await self._populate_capabilities(session)
                         self._session = session
                         self._ready_event.set()
    +                    logger.info(
    +                        "cua-driver session ready in %.1fs "
    +                        "(manifest=%.1fs, mcp_init=%.1fs)",
    +                        _time.monotonic() - _t0,
    +                        _t_manifest - _t0,
    +                        _t_init - _t_manifest,
    +                    )
                         # Hold the contexts open until stop() / restart asks
                         # us to wind down. Tool calls run as their own tasks
                         # on the same loop and touch self._session directly.
    ```

    ```diff
    @@ -677,10 +688,10 @@ def _start_lifecycle_locked(self) -> None:
             self._lifecycle_future = asyncio.run_coroutine_threadsafe(
                 self._lifecycle_coro(), loop
             )
    -        if not self._ready_event.wait(timeout=15.0):
    +        if not self._ready_event.wait(timeout=30.0):
                 # Best-effort: signal shutdown if the future is still alive.
                 self._signal_shutdown_locked()
    -            raise RuntimeError("cua-driver session never reached ready (timeout 15s)")
    +            raise RuntimeError("cua-driver session never reached ready (timeout 30s)")
             # If setup failed, the lifecycle coroutine set _setup_error
             # before setting _ready_event. Re-raise it on the caller's thread.
             if self._setup_error is not None:
    ```
- **#58801: fix(computer-use): name the wedged startup phase in the session ready-timeout error**. merged to main · fix tier `suggested`
  - maintainer direction: category `merged`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#57034: fix(computer-use): increase cua-driver session startup timeout from 15s to 30s**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#58760`

## Fix status

- Merged to main in PR #58760 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-05`.
- Subsystem: `agent`
