mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 22:20:33 +00:00
fix(config): delete thread dir through extended-length path to avoid WinError 145 (#8144)
Co-authored-by: Nan Gao <thunderggnn@gmail.com>
This commit is contained in:
parent
b80191fad3
commit
98e8598adb
@ -60,6 +60,12 @@ This section accumulates work toward the **2.3.0** milestone
|
||||
|
||||
### Fixed
|
||||
|
||||
- **threads:** Deleting a conversation on Windows no longer fails with
|
||||
`Failed to delete local thread data.` when the workspace holds a file whose
|
||||
path exceeds `MAX_PATH`. The thread directory is now resolved through the
|
||||
Windows extended-length namespace before removal.
|
||||
([#8144](https://github.com/bytedance/deer-flow/pull/8144))
|
||||
|
||||
- **channels:** A WeCom group command that follows the bot mention now runs as a
|
||||
command. WeCom keeps the mention inside the message text (`@RobotA /new`), and
|
||||
the classifier required a bare leading `/`, so `/new` and `/status` sent in a
|
||||
|
||||
@ -508,12 +508,18 @@ class Paths:
|
||||
def delete_thread_dir(self, thread_id: str, *, user_id: str | None = None) -> None:
|
||||
"""Delete all persisted data for a thread.
|
||||
|
||||
Idempotent: missing thread directories are ignored. A file the host marks
|
||||
read-only is retried once after clearing that bit, because Windows refuses
|
||||
to unlink it where POSIX only needs a writable parent; a file that stays
|
||||
undeletable still raises.
|
||||
Idempotent: missing thread directories are ignored. The tree is removed
|
||||
through the Windows extended-length namespace so a nested file whose full
|
||||
path exceeds ``MAX_PATH`` (for example a plugin's ``files/<sha256>.docx``
|
||||
under a deep user/thread workspace) is still unlinked. Without the prefix
|
||||
``shutil.rmtree`` leaves the long child behind and ``os.rmdir`` fails with
|
||||
``WinError 145``.
|
||||
|
||||
A file the host marks read-only is retried once after clearing that bit,
|
||||
because Windows refuses to unlink it where POSIX only needs a writable
|
||||
parent; a file that stays undeletable still raises.
|
||||
"""
|
||||
thread_dir = self.thread_dir(thread_id, user_id=user_id)
|
||||
thread_dir = extended_length_path(self.thread_dir(thread_id, user_id=user_id))
|
||||
try:
|
||||
shutil.rmtree(thread_dir)
|
||||
except FileNotFoundError:
|
||||
|
||||
@ -307,6 +307,25 @@ class TestEnsureAndDeleteWithUserId:
|
||||
paths.delete_thread_dir("t1", user_id="u1")
|
||||
assert paths.thread_dir("t1", user_id="u1").exists()
|
||||
|
||||
def test_delete_thread_dir_uses_extended_length_path(self, paths: Paths, monkeypatch):
|
||||
"""``shutil.rmtree`` receives the path resolved through ``extended_length_path``.
|
||||
|
||||
The fix for the ``MAX_PATH`` deletion failure is a single line: resolve
|
||||
the thread directory through ``extended_length_path`` before removing it.
|
||||
That call is a no-op on POSIX, so this pins the wiring by patching the
|
||||
resolver to return a marker and asserting ``shutil.rmtree`` receives it.
|
||||
"""
|
||||
from deerflow.config import paths as paths_module
|
||||
|
||||
marker = object()
|
||||
monkeypatch.setattr(paths_module, "extended_length_path", lambda _path: marker)
|
||||
received = []
|
||||
monkeypatch.setattr(paths_module.shutil, "rmtree", lambda path, *args, **kwargs: received.append(path))
|
||||
|
||||
paths.ensure_thread_dirs("t1", user_id="u1")
|
||||
paths.delete_thread_dir("t1", user_id="u1")
|
||||
assert received == [marker]
|
||||
|
||||
def test_ensure_thread_dirs_legacy_still_works(self, paths: Paths):
|
||||
paths.ensure_thread_dirs("t1")
|
||||
assert paths.sandbox_work_dir("t1").is_dir()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user