mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-10 14:55:16 -05:00
fix(backend/chat): Resolve symlinks in session file path for --resume
The CLI resolves symlinks when computing its project directory (e.g. /tmp -> /private/tmp on macOS), so our session file writes must use the resolved path to match. Also adds cwd to ClaudeAgentOptions and debug logging for SDK messages.
This commit is contained in:
@@ -287,6 +287,7 @@ async def stream_chat_completion_sdk(
|
||||
mcp_servers={"copilot": mcp_server}, # type: ignore[arg-type]
|
||||
allowed_tools=COPILOT_TOOL_NAMES,
|
||||
hooks=create_security_hooks(user_id), # type: ignore[arg-type]
|
||||
cwd="/tmp",
|
||||
resume=resume_id,
|
||||
)
|
||||
|
||||
@@ -326,6 +327,9 @@ async def stream_chat_completion_sdk(
|
||||
|
||||
# Receive messages from the SDK
|
||||
async for sdk_msg in client.receive_messages():
|
||||
logger.debug(
|
||||
f"[SDK] Received: {type(sdk_msg).__name__} {getattr(sdk_msg, 'subtype', '')}"
|
||||
)
|
||||
for response in adapter.convert_message(sdk_msg):
|
||||
if isinstance(response, StreamStart):
|
||||
continue
|
||||
|
||||
@@ -26,8 +26,13 @@ def _encode_cwd(cwd: str) -> str:
|
||||
|
||||
|
||||
def _get_project_dir(cwd: str) -> Path:
|
||||
"""Get the CLI project directory for a given working directory."""
|
||||
return _CLAUDE_PROJECTS_DIR / _encode_cwd(cwd)
|
||||
"""Get the CLI project directory for a given working directory.
|
||||
|
||||
Resolves symlinks to match the CLI's behavior (e.g. /tmp -> /private/tmp
|
||||
on macOS).
|
||||
"""
|
||||
resolved = str(Path(cwd).resolve())
|
||||
return _CLAUDE_PROJECTS_DIR / _encode_cwd(resolved)
|
||||
|
||||
|
||||
def write_session_file(
|
||||
@@ -45,6 +50,7 @@ def write_session_file(
|
||||
return None
|
||||
|
||||
session_id = session.session_id
|
||||
resolved_cwd = str(Path(cwd).resolve())
|
||||
project_dir = _get_project_dir(cwd)
|
||||
project_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -62,7 +68,7 @@ def write_session_file(
|
||||
"parentUuid": prev_uuid,
|
||||
"isSidechain": False,
|
||||
"userType": "external",
|
||||
"cwd": cwd,
|
||||
"cwd": resolved_cwd,
|
||||
"sessionId": session_id,
|
||||
"type": "user",
|
||||
"message": {"role": "user", "content": msg.content},
|
||||
@@ -77,7 +83,7 @@ def write_session_file(
|
||||
"parentUuid": prev_uuid,
|
||||
"isSidechain": False,
|
||||
"userType": "external",
|
||||
"cwd": cwd,
|
||||
"cwd": resolved_cwd,
|
||||
"sessionId": session_id,
|
||||
"type": "assistant",
|
||||
"message": {
|
||||
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from ..model import ChatMessage, ChatSession
|
||||
from .session_file import cleanup_session_file, write_session_file
|
||||
from .session_file import _get_project_dir, cleanup_session_file, write_session_file
|
||||
|
||||
_NOW = datetime.now(UTC)
|
||||
|
||||
@@ -172,3 +172,51 @@ def test_cleanup_no_error_if_missing(tmp_path: Path):
|
||||
return_value=tmp_path,
|
||||
):
|
||||
cleanup_session_file("nonexistent") # Should not raise
|
||||
|
||||
|
||||
# -- _get_project_dir --------------------------------------------------------
|
||||
|
||||
|
||||
def test_get_project_dir_resolves_symlinks(tmp_path: Path):
|
||||
"""_get_project_dir should resolve symlinks so the path matches the CLI."""
|
||||
# Create a symlink: tmp_path/link -> tmp_path/real
|
||||
real_dir = tmp_path / "real"
|
||||
real_dir.mkdir()
|
||||
link = tmp_path / "link"
|
||||
link.symlink_to(real_dir)
|
||||
|
||||
with patch(
|
||||
"backend.api.features.chat.sdk.session_file._CLAUDE_PROJECTS_DIR",
|
||||
tmp_path / "projects",
|
||||
):
|
||||
result = _get_project_dir(str(link))
|
||||
|
||||
# Should resolve the symlink and encode the real path
|
||||
expected_encoded = "-" + str(real_dir).lstrip("/").replace("/", "-")
|
||||
assert result.name == expected_encoded
|
||||
|
||||
|
||||
def test_write_uses_resolved_cwd_in_messages(tmp_path: Path):
|
||||
"""The cwd field in JSONL messages should use the resolved path."""
|
||||
session = _make_session(
|
||||
[
|
||||
ChatMessage(role="user", content="hello"),
|
||||
ChatMessage(role="assistant", content="Hi!"),
|
||||
ChatMessage(role="user", content="current"),
|
||||
],
|
||||
session_id="sess-cwd",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"backend.api.features.chat.sdk.session_file._get_project_dir",
|
||||
return_value=tmp_path,
|
||||
):
|
||||
write_session_file(session, cwd="/tmp")
|
||||
|
||||
file_path = tmp_path / "sess-cwd.jsonl"
|
||||
lines = file_path.read_text().strip().split("\n")
|
||||
for line in lines:
|
||||
obj = json.loads(line)
|
||||
# On macOS /tmp resolves to /private/tmp; on Linux stays /tmp
|
||||
resolved = str(Path("/tmp").resolve())
|
||||
assert obj["cwd"] == resolved
|
||||
|
||||
Reference in New Issue
Block a user