fix(code): clean offloaded history when deleting a thread - #4751
Conversation
Deleting a thread via the /threads switcher (or the threads delete CLI) only removed its SQLite checkpoints, leaving the per-thread offloaded conversation-history archive orphaned under ~/.deepagents. Add delete_offloaded_history to remove that archive and call it from delete_thread. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
| if _UNIQUE_OFFLOAD_FALLBACK_ROOT is not None: | ||
| # Unlike the persistent and predictable temp paths, a directory created | ||
| # by `mkdtemp` cannot be derived again. Keep returning the root already | ||
| # used by the archive backend so cleanup reaches the same files. | ||
| _EPHEMERAL_OFFLOAD_STORAGE = True | ||
| return _UNIQUE_OFFLOAD_FALLBACK_ROOT |
There was a problem hiding this comment.
🟡 Cached fallback skips directory hardening
When the unique temp fallback is cached, later calls return it without re-running _prepare_temp_dir. If that temp directory is removed during the process lifetime (for example by a temp cleaner or user cleanup), the next offload still builds a FilesystemBackend on this stale path; its write() recreates the missing root and conversation_history parents with default permissions (typically 0755) and the archive as 0644, instead of the intended private 0700 tree. Revalidate/harden the cached fallback root (and clear/recreate it if unusable) before returning it so conversation history cannot be recreated world-readable under /tmp.
(Refers to lines 201-206)
Your feedback helps Open SWE learn. React with 👍 or 👎 to tell us if this review comment was useful.
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Release notes preview: keep this section in sync with the package `CHANGELOG.md`. The published GitHub release body is extracted from the merged `CHANGELOG.md` by `release.yml`, not from this PR description._ --- ## [0.1.40](deepagents-code==0.1.39...deepagents-code==0.1.40) (2026-07-16) ### Features - Added plugin marketplace support ([#4554](#4554)). - Added an “always allow” option to the project MCP approval prompt ([#4562](#4562)). - Improved `/goal` workflows: criteria generation now runs server-side, YOLO mode auto-accepts criteria, goals complete after satisfied grading, and goal review editing now supports `Ctrl+X` ([#4754](#4754), [#4784](#4784), [#4781](#4781), [#4780](#4780)). - Reasoning effort now persists across restarts ([#4728](#4728)). - Added a toast prompting you to re-paste when a chat paste collapses ([#4742](#4742)). ### Bug Fixes - Tool calls awaiting approval are now surfaced correctly ([#4739](#4739)). - Fixed transcript tail hydration when scrolled to the bottom edge ([#4733](#4733)). - Kept chat input responsive during MCP viewer `Ctrl+R` reconnects ([#4753](#4753)). - Improved inline free-text prompts by sharing paste handling and matching primary-input `Ctrl+D` behavior ([#4736](#4736), [#4729](#4729)). - Fixed local offloaded tool results to use the real filesystem ([#4740](#4740)). - Cleaned offloaded history when deleting a thread ([#4751](#4751)). - Removed duplicated content from the system prompt by overwriting the base prompt ([#4516](#4516)). - Closed subprocess transport during install teardown ([#4735](#4735)). - Added targeted `uv` constraints for prerelease dependencies ([#4744](#4744)). _End release notes preview._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com>
…ai#4751) Deleting a thread now also removes its offloaded conversation history from `~/.deepagents`. --- Deleting a thread through the `/threads` switcher (and the `threads delete` CLI) only removed the thread's SQLite checkpoints, leaving its offloaded conversation-history archive orphaned under `~/.deepagents/conversation_history/{thread_id}.md`. Over time these files accumulate for threads the user believes are gone. `delete_thread` now also removes the per-thread archive via a new `delete_offloaded_history` helper in `offload.py`, which resolves the same offload root used when writing history. The helper guards against a crafted `thread_id` escaping the archive directory and is a no-op when no archive exists (e.g. server/sandbox mode, where history lives on the sandbox backend). Made by [Open SWE](https://openswe.vercel.app/agents/1ca83aca-3d44-5887-c9c2-3ea96c440136) --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
> [!CAUTION] > Merging this PR will automatically publish to **PyPI** and create a **GitHub release**. For the full release process, see [`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md). --- _Release notes preview: keep this section in sync with the package `CHANGELOG.md`. The published GitHub release body is extracted from the merged `CHANGELOG.md` by `release.yml`, not from this PR description._ --- ## [0.1.40](langchain-ai/deepagents@deepagents-code==0.1.39...deepagents-code==0.1.40) (2026-07-16) ### Features - Added plugin marketplace support ([langchain-ai#4554](langchain-ai#4554)). - Added an “always allow” option to the project MCP approval prompt ([langchain-ai#4562](langchain-ai#4562)). - Improved `/goal` workflows: criteria generation now runs server-side, YOLO mode auto-accepts criteria, goals complete after satisfied grading, and goal review editing now supports `Ctrl+X` ([langchain-ai#4754](langchain-ai#4754), [langchain-ai#4784](langchain-ai#4784), [langchain-ai#4781](langchain-ai#4781), [langchain-ai#4780](langchain-ai#4780)). - Reasoning effort now persists across restarts ([langchain-ai#4728](langchain-ai#4728)). - Added a toast prompting you to re-paste when a chat paste collapses ([langchain-ai#4742](langchain-ai#4742)). ### Bug Fixes - Tool calls awaiting approval are now surfaced correctly ([langchain-ai#4739](langchain-ai#4739)). - Fixed transcript tail hydration when scrolled to the bottom edge ([langchain-ai#4733](langchain-ai#4733)). - Kept chat input responsive during MCP viewer `Ctrl+R` reconnects ([langchain-ai#4753](langchain-ai#4753)). - Improved inline free-text prompts by sharing paste handling and matching primary-input `Ctrl+D` behavior ([langchain-ai#4736](langchain-ai#4736), [langchain-ai#4729](langchain-ai#4729)). - Fixed local offloaded tool results to use the real filesystem ([langchain-ai#4740](langchain-ai#4740)). - Cleaned offloaded history when deleting a thread ([langchain-ai#4751](langchain-ai#4751)). - Removed duplicated content from the system prompt by overwriting the base prompt ([langchain-ai#4516](langchain-ai#4516)). - Closed subprocess transport during install teardown ([langchain-ai#4735](langchain-ai#4735)). - Added targeted `uv` constraints for prerelease dependencies ([langchain-ai#4744](langchain-ai#4744)). _End release notes preview._ --- > [!NOTE] > A **New Contributors** section is appended to the GitHub release notes automatically at publish time (see [Release Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline), step 2). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com>
Deleting a thread now also removes its offloaded conversation history from
~/.deepagents.Deleting a thread through the
/threadsswitcher (and thethreads deleteCLI) only removed the thread's SQLite checkpoints, leaving its offloaded conversation-history archive orphaned under~/.deepagents/conversation_history/{thread_id}.md. Over time these files accumulate for threads the user believes are gone.delete_threadnow also removes the per-thread archive via a newdelete_offloaded_historyhelper inoffload.py, which resolves the same offload root used when writing history. The helper guards against a craftedthread_idescaping the archive directory and is a no-op when no archive exists (e.g. server/sandbox mode, where history lives on the sandbox backend).Made by Open SWE