Port from PrimeIntellect-ai/prime-agent#628: resolve symlink aliases in ACP cwd comparison
macOS reports editor workspaces as /var/... while sessions are stored under /private/var/... (same for /tmp vs /private/tmp), so the lexical normpath comparison in _normalize_cwd_for_compare treated them as different directories and ACP history filters silently dropped a workspace's own sessions. Canonicalize with os.path.realpath; nonexistent paths (e.g. WSL-translated Windows drives on a Linux host) keep the previous lexical behavior since realpath(strict=False) is lexical for them.
This commit is contained in:
parent
0957277f2f
commit
4d8181fd84
|
|
@ -56,7 +56,18 @@ def _normalize_cwd_for_compare(cwd: str | None) -> str:
|
|||
elif re.match(r"^/mnt/[A-Za-z]/", expanded):
|
||||
expanded = f"/mnt/{expanded[5].lower()}/{expanded[7:]}"
|
||||
|
||||
return os.path.normpath(expanded)
|
||||
# Resolve symlink aliases so equivalent spellings of the same directory
|
||||
# compare equal — macOS reports editor workspaces as ``/var/...`` while
|
||||
# sessions get stored under ``/private/var/...`` (and ``/tmp`` vs
|
||||
# ``/private/tmp``), which made ACP history filters silently drop a
|
||||
# workspace's own sessions. ``os.path.realpath`` is lexical for missing
|
||||
# paths (strict=False), so cwds that don't exist on this host — e.g.
|
||||
# WSL-translated Windows drives — keep the previous normpath behavior.
|
||||
# Ported from PrimeIntellect-ai/prime-agent#628.
|
||||
try:
|
||||
return os.path.realpath(expanded)
|
||||
except OSError:
|
||||
return os.path.normpath(expanded)
|
||||
|
||||
|
||||
def _build_session_title(title: Any, preview: Any, cwd: str | None) -> str:
|
||||
|
|
|
|||
|
|
@ -158,6 +158,54 @@ class TestWslCwdTranslation:
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestSymlinkAliasNormalization:
|
||||
"""Ported from PrimeIntellect-ai/prime-agent#628 — symlink aliases of the
|
||||
same directory (macOS ``/var`` vs ``/private/var``, ``/tmp`` vs
|
||||
``/private/tmp``) must compare equal, or ACP history filters silently drop
|
||||
a workspace's own sessions."""
|
||||
|
||||
def test_symlink_alias_compares_equal(self, tmp_path):
|
||||
real = tmp_path / "real"
|
||||
real.mkdir()
|
||||
alias = tmp_path / "alias"
|
||||
alias.symlink_to(real)
|
||||
assert acp_session._normalize_cwd_for_compare(
|
||||
str(alias)
|
||||
) == acp_session._normalize_cwd_for_compare(str(real))
|
||||
|
||||
def test_distinct_dirs_still_compare_different(self, tmp_path):
|
||||
a = tmp_path / "a"
|
||||
b = tmp_path / "b"
|
||||
a.mkdir()
|
||||
b.mkdir()
|
||||
assert acp_session._normalize_cwd_for_compare(
|
||||
str(a)
|
||||
) != acp_session._normalize_cwd_for_compare(str(b))
|
||||
|
||||
def test_missing_path_keeps_lexical_normalization(self):
|
||||
# realpath(strict=False) is lexical for nonexistent paths, so cwds
|
||||
# that don't exist on this host (e.g. WSL-translated drives) behave
|
||||
# exactly as the old normpath comparison did.
|
||||
assert acp_session._normalize_cwd_for_compare(
|
||||
"/nonexistent-hermes-test/x/../y"
|
||||
) == "/nonexistent-hermes-test/y"
|
||||
|
||||
def test_list_sessions_matches_symlink_alias_cwd(self, manager, tmp_path):
|
||||
real = tmp_path / "proj"
|
||||
real.mkdir()
|
||||
alias = tmp_path / "link"
|
||||
alias.symlink_to(real)
|
||||
state = manager.create_session(cwd=str(real))
|
||||
state.history.append({"role": "user", "content": "hello"})
|
||||
listed = manager.list_sessions(cwd=str(alias))
|
||||
assert [s["session_id"] for s in listed] == [state.session_id]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# list / cleanup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestListAndCleanup:
|
||||
def test_list_sessions_empty(self, manager):
|
||||
assert manager.list_sessions() == []
|
||||
|
|
|
|||
Loading…
Reference in New Issue