Skip to content

perf(cli): speed up /threads first-open - #1481

Merged
Mason Daugherty (mdrxy) merged 8 commits into
mainfrom
mdrxy/fix-thread-loading
Mar 1, 2026
Merged

perf(cli): speed up /threads first-open#1481
Mason Daugherty (mdrxy) merged 8 commits into
mainfrom
mdrxy/fix-thread-loading

Conversation

@mdrxy

Copy link
Copy Markdown
Member

... with startup prewarm and cached selector data


Fixes #1471


/threads had noticeable first-open latency and UI stutter due to DB/query work and row remounting during selector initialization.

  • Added non-blocking startup prewarm of thread-selector data
  • Added session-layer caches:
    • message-count cache keyed by thread freshness (latest_checkpoint_id / updated_at)
    • recent thread snapshot cache keyed by (agent_name, limit)
  • Added helpers to prewarm, read cached thread snapshots, and apply cached counts.
  • Updated /threads open path to pass cached rows into the selector when available.
  • Updated selector to accept thread_limit + initial_threads (thread_limit already existed, re-use to avoid re-reading config)
    • render prefetched rows immediately (skip loading placeholder on cache hit)
    • fall back to async load on cache miss
  • Added cache cleanup for thread deletion paths.

@github-actions github-actions Bot added internal User is a member of the `langchain-ai` GitHub organization cli Related to `deepagents-cli` performance Code change that improves performance and removed internal User is a member of the `langchain-ai` GitHub organization labels Feb 21, 2026
@mdrxy
Mason Daugherty (mdrxy) merged commit b248b15 into main Mar 1, 2026
24 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the mdrxy/fix-thread-loading branch March 1, 2026 23:33
Mason Daugherty (mdrxy) added a commit that referenced this pull request Mar 3, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.0.26](deepagents-cli==0.0.25...deepagents-cli==0.0.26)
(2026-03-03)


### Features

* Compaction hook
([#1420](#1420))
([e87cdad](e87cdad))
* `/compact` command
([#1579](#1579))
([46e9e95](46e9e95))
* Add `--profile-override` CLI flag
([#1605](#1605))
([1984099](1984099))
* Add model profile overrides to config
([#1603](#1603))
([d3d6899](d3d6899))
* Show summarization status and notification
([#919](#919))
([2e3cb74](2e3cb74))

### Bug Fixes

* Fix image path pasting qualms
([#1560](#1560))
([8caaf3e](8caaf3e))
* Load `.agents` skill alias directories at interactive startup
([#1556](#1556))
([af0a759](af0a759))
* Coerce execute timeout to int before formatting tool display
([#1588](#1588))
([04b8c72](04b8c72)),
closes [#1586](#1586)
* Add missing flags to help screen
([#1619](#1619))
([6067749](6067749))
* Align compaction messaging across `/compact` and
`compact_conversation`
([#1583](#1583))
([d455a6b](d455a6b))
* Apply profile overrides in `/compact`
([#1612](#1612))
([a9dc2c5](a9dc2c5))
* Disambiguate `/tokens` vs `/compact` token reporting
([#1618](#1618))
([51c3347](51c3347))
* Make LangSmith URL lookups non-blocking
([#1595](#1595))
([572eaee](572eaee))
* Only exit input mode on backspace, not text clear
([#1479](#1479))
([da0965e](da0965e))
* Retry langsmith project url lookup until project exists
([#1562](#1562))
([e137a63](e137a63))
* Show model info in `/tokens` before first usage
([#1607](#1607))
([7b01ae7](7b01ae7))
* Support `timeout=0` for sandbox `execute()`
([#1558](#1558))
([ed14443](ed14443))
* Unreachable `except` block
([#1535](#1535))
([0e17e35](0e17e35))

### Performance Improvements

* Optimize thread resume path with prefetch and batched hydration
([#1561](#1561))
([068d112](068d112))
* Parallelize detection scripts for faster first-turn
([#1541](#1541))
([dad8b6e](dad8b6e))
* Speed up `/threads` first-open
([#1481](#1481))
([b248b15](b248b15))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
james8814 pushed a commit to james8814/deepagents that referenced this pull request Mar 6, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.0.26](langchain-ai/deepagents@deepagents-cli==0.0.25...deepagents-cli==0.0.26)
(2026-03-03)


### Features

* Compaction hook
([langchain-ai#1420](langchain-ai#1420))
([e87cdad](langchain-ai@e87cdad))
* `/compact` command
([langchain-ai#1579](langchain-ai#1579))
([46e9e95](langchain-ai@46e9e95))
* Add `--profile-override` CLI flag
([langchain-ai#1605](langchain-ai#1605))
([1984099](langchain-ai@1984099))
* Add model profile overrides to config
([langchain-ai#1603](langchain-ai#1603))
([d3d6899](langchain-ai@d3d6899))
* Show summarization status and notification
([langchain-ai#919](langchain-ai#919))
([2e3cb74](langchain-ai@2e3cb74))

### Bug Fixes

* Fix image path pasting qualms
([langchain-ai#1560](langchain-ai#1560))
([8caaf3e](langchain-ai@8caaf3e))
* Load `.agents` skill alias directories at interactive startup
([langchain-ai#1556](langchain-ai#1556))
([af0a759](langchain-ai@af0a759))
* Coerce execute timeout to int before formatting tool display
([langchain-ai#1588](langchain-ai#1588))
([04b8c72](langchain-ai@04b8c72)),
closes [langchain-ai#1586](langchain-ai#1586)
* Add missing flags to help screen
([langchain-ai#1619](langchain-ai#1619))
([6067749](langchain-ai@6067749))
* Align compaction messaging across `/compact` and
`compact_conversation`
([langchain-ai#1583](langchain-ai#1583))
([d455a6b](langchain-ai@d455a6b))
* Apply profile overrides in `/compact`
([langchain-ai#1612](langchain-ai#1612))
([a9dc2c5](langchain-ai@a9dc2c5))
* Disambiguate `/tokens` vs `/compact` token reporting
([langchain-ai#1618](langchain-ai#1618))
([51c3347](langchain-ai@51c3347))
* Make LangSmith URL lookups non-blocking
([langchain-ai#1595](langchain-ai#1595))
([572eaee](langchain-ai@572eaee))
* Only exit input mode on backspace, not text clear
([langchain-ai#1479](langchain-ai#1479))
([da0965e](langchain-ai@da0965e))
* Retry langsmith project url lookup until project exists
([langchain-ai#1562](langchain-ai#1562))
([e137a63](langchain-ai@e137a63))
* Show model info in `/tokens` before first usage
([langchain-ai#1607](langchain-ai#1607))
([7b01ae7](langchain-ai@7b01ae7))
* Support `timeout=0` for sandbox `execute()`
([langchain-ai#1558](langchain-ai#1558))
([ed14443](langchain-ai@ed14443))
* Unreachable `except` block
([langchain-ai#1535](langchain-ai#1535))
([0e17e35](langchain-ai@0e17e35))

### Performance Improvements

* Optimize thread resume path with prefetch and batched hydration
([langchain-ai#1561](langchain-ai#1561))
([068d112](langchain-ai@068d112))
* Parallelize detection scripts for faster first-turn
([langchain-ai#1541](langchain-ai#1541))
([dad8b6e](langchain-ai@dad8b6e))
* Speed up `/threads` first-open
([langchain-ai#1481](langchain-ai#1481))
([b248b15](langchain-ai@b248b15))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
... with startup prewarm and cached selector data

---

Fixes langchain-ai#1471

---

`/threads` had noticeable first-open latency and UI stutter due to
DB/query work and row remounting during selector initialization.

- Added non-blocking startup prewarm of thread-selector data
- Added session-layer caches:
- message-count cache keyed by thread freshness (`latest_checkpoint_id`
/ `updated_at`)
  - recent thread snapshot cache keyed by `(agent_name, limit)`
- Added helpers to prewarm, read cached thread snapshots, and apply
cached counts.
- Updated `/threads` open path to pass cached rows into the selector
when available.
- Updated selector to accept `thread_limit` + `initial_threads`
(`thread_limit` already existed, re-use to avoid re-reading config)
- render prefetched rows immediately (skip loading placeholder on cache
hit)
  - fall back to async load on cache miss
- Added cache cleanup for thread deletion paths.
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.0.26](langchain-ai/deepagents@deepagents-cli==0.0.25...deepagents-cli==0.0.26)
(2026-03-03)


### Features

* Compaction hook
([langchain-ai#1420](langchain-ai#1420))
([e87cdad](langchain-ai@e87cdad))
* `/compact` command
([langchain-ai#1579](langchain-ai#1579))
([46e9e95](langchain-ai@46e9e95))
* Add `--profile-override` CLI flag
([langchain-ai#1605](langchain-ai#1605))
([1984099](langchain-ai@1984099))
* Add model profile overrides to config
([langchain-ai#1603](langchain-ai#1603))
([d3d6899](langchain-ai@d3d6899))
* Show summarization status and notification
([langchain-ai#919](langchain-ai#919))
([2e3cb74](langchain-ai@2e3cb74))

### Bug Fixes

* Fix image path pasting qualms
([langchain-ai#1560](langchain-ai#1560))
([8caaf3e](langchain-ai@8caaf3e))
* Load `.agents` skill alias directories at interactive startup
([langchain-ai#1556](langchain-ai#1556))
([af0a759](langchain-ai@af0a759))
* Coerce execute timeout to int before formatting tool display
([langchain-ai#1588](langchain-ai#1588))
([04b8c72](langchain-ai@04b8c72)),
closes [langchain-ai#1586](langchain-ai#1586)
* Add missing flags to help screen
([langchain-ai#1619](langchain-ai#1619))
([6067749](langchain-ai@6067749))
* Align compaction messaging across `/compact` and
`compact_conversation`
([langchain-ai#1583](langchain-ai#1583))
([d455a6b](langchain-ai@d455a6b))
* Apply profile overrides in `/compact`
([langchain-ai#1612](langchain-ai#1612))
([a9dc2c5](langchain-ai@a9dc2c5))
* Disambiguate `/tokens` vs `/compact` token reporting
([langchain-ai#1618](langchain-ai#1618))
([51c3347](langchain-ai@51c3347))
* Make LangSmith URL lookups non-blocking
([langchain-ai#1595](langchain-ai#1595))
([572eaee](langchain-ai@572eaee))
* Only exit input mode on backspace, not text clear
([langchain-ai#1479](langchain-ai#1479))
([da0965e](langchain-ai@da0965e))
* Retry langsmith project url lookup until project exists
([langchain-ai#1562](langchain-ai#1562))
([e137a63](langchain-ai@e137a63))
* Show model info in `/tokens` before first usage
([langchain-ai#1607](langchain-ai#1607))
([7b01ae7](langchain-ai@7b01ae7))
* Support `timeout=0` for sandbox `execute()`
([langchain-ai#1558](langchain-ai#1558))
([ed14443](langchain-ai@ed14443))
* Unreachable `except` block
([langchain-ai#1535](langchain-ai#1535))
([0e17e35](langchain-ai@0e17e35))

### Performance Improvements

* Optimize thread resume path with prefetch and batched hydration
([langchain-ai#1561](langchain-ai#1561))
([068d112](langchain-ai@068d112))
* Parallelize detection scripts for faster first-turn
([langchain-ai#1541](langchain-ai#1541))
([dad8b6e](langchain-ai@dad8b6e))
* Speed up `/threads` first-open
([langchain-ai#1481](langchain-ai#1481))
([b248b15](langchain-ai@b248b15))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Mason Daugherty (mdrxy) added a commit that referenced this pull request Aug 4, 2026
Interrupting a turn, or exiting while a background thread-cache refresh
is in flight, no longer strands an unawaited coroutine or an open SQLite
handle.

---

The unit suite emitted three families of warnings, all at teardown. Two
are ours and are fixed here; the third is upstream and is filtered.

### An unawaited turn coroutine

`_send_to_agent` handed `run_worker` an already-built `_run_agent_task`
coroutine. Textual never runs the work of a worker cancelled before its
first event-loop step, so that coroutine was finalized unawaited — a
`RuntimeWarning`, and (once interpreter teardown had gone far enough to
break the import machinery its cleanup relies on) an unraisable
`KeyError: '__import__'`. Passing a callable means the coroutine only
exists if the worker actually runs, so there is nothing to strand.
Several tests were closing that coroutine by hand purely to silence the
warning; those workarounds are gone, and a new test pins the callable
contract.

**Where it started:** #5196. Handing `run_worker` a coroutine dates all
the way back to the original Textual REPL (#686), but it was harmless
until something cancelled a worker before its first step. #5196 added
the recovery path for exactly that situation along with the tests that
exercise it. Its parent commit runs the app test module with zero `never
awaited` warnings; #5196 itself produces three.

### An unclosed SQLite handle

`aiosqlite` opens the database on its worker thread and hands the raw
`sqlite3.Connection` back through a future, recording it on the
connection only when the awaiting coroutine resumes. A cancel landing
anywhere in that window left the handle unreachable from the cleanup
that follows, so the garbage collector reported `ResourceWarning:
unclosed database`. There are two halves to the window, and both are now
covered:

- Cancelled while the worker is still opening, the library has no handle
recorded yet, so the cleanup it queues closes nothing. The session
module now records the handle from the worker thread the moment the
connector returns.
- Cancelled after the handle is delivered but before the coroutine
resumes, the library clears its own reference before that queued cleanup
can run — so it again closes nothing. The guard now also queues an
explicit close ahead of the library's cleanup, while the handle is still
reachable.

Both closes run on the thread that opened the handle, and closing twice
is a no-op, so neither disturbs a normal shutdown. `get_checkpointer`
builds its connection through the same helper rather than
`AsyncSqliteSaver.from_conn_string`, so it gets the same guard.

**Where it started:** #5174. The prewarm that reads the session database
has existed since #1481, but it ran once at startup, so it had normally
finished before anything cancelled it. #5174 re-fires it after every
turn, which reliably leaves a session-DB read in flight when a test app
exits. Counting handles that `aiosqlite` opened and never closed across
the goal-command tests: zero on the parent commit, fourteen on #5174.

### A `typing` deprecation from `google-genai`

`google.genai.types` builds a union alias out of
`typing._UnionGenericAlias`, which CPython 3.14 deprecates, and it fires
at import before any of this package's code runs. This one is not a
regression from any change here — `deepagents-code` has been tested on
the 3.14 leg since the package was created in #3027, and the warning
appears wherever a test imports the Google integration. It is tracked
upstream as
[googleapis/python-genai#1640](googleapis/python-genai#1640)
and still unfixed as of `google-genai` 2.13.0, so it is filtered
narrowly (message, category, and module) rather than worked around.

Made by [Open
SWE](https://openswe.vercel.app/agents/f42590ef-0fe4-0b9f-6880-1c48b28446d5)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli Related to `deepagents-cli` performance Code change that improves performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Thread screen loading performance

1 participant