diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b23358..c4a5fc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to `xgen-agent-runtime` are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/). +## [4.63.1] — 2026-09-26 + +### Fixed — 작업 공간이 사용자 PC 인 모드(커넥터 로컬 동기화)는 빠른 경로에 넣지 않는다 + +4.63.0 의 작은 작업 폴더 빠른 경로는 서버 sandbox 에서만 측정했다. 커넥터 로컬 동기화 모드에서는 스냅샷이 +사용자 PC 로 가는 원격 실행이고(PC 에 python3 필요), "Bash 한 번에 다 하라" 는 지시가 사용자 PC 에서 돈다. +요청 파일 첨부(`referenced_files`)도 같은 이유로 이 모드를 건너뛴다. `prepare_workspace_fast_path` 가 +`sandbox.is_connector_local` 이면 파일을 건드리기 전에 `reason="connector_local"` 로 원래 루프에 보낸다. +PC 모드에서 따로 측정하기 전까지 유지한다. + ## [4.63.0] — 2026-09-26 ### Added — 작은 작업 폴더 빠른 경로 (기본 꺼짐) + Bash 산출물 계약 diff --git a/pyproject.toml b/pyproject.toml index bdbd1b0..4d11fd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "xgen-agent-runtime" -version = "4.63.0" +version = "4.63.1" description = "Harness-engineered agent pipeline library with 21-stage dual-abstraction architecture, built on the Anthropic API" readme = "README.md" license = "Apache-2.0" diff --git a/src/xgen_agent_runtime/host/workspace_fast_path.py b/src/xgen_agent_runtime/host/workspace_fast_path.py index eb0d06a..2e76945 100644 --- a/src/xgen_agent_runtime/host/workspace_fast_path.py +++ b/src/xgen_agent_runtime/host/workspace_fast_path.py @@ -154,6 +154,12 @@ async def prepare_workspace_fast_path( return WorkspaceFastPath(text=text, active=False, reason="disabled") if context is None: return WorkspaceFastPath(text=text, active=False, reason="workspace_unavailable") + # 작업 공간이 사용자 PC 인 모드(커넥터 로컬 동기화)는 빠른 경로에 넣지 않는다. 이 경로는 + # 서버 sandbox 에서만 측정했다 — PC 에서는 스냅샷이 원격 왕복(python3 이 PC 에 있어야 한다)이고, + # "Bash 한 번에 다 하라" 는 지시가 사용자 PC 에서 돈다. 요청 파일 첨부(referenced_files)도 같은 + # 이유로 이 모드를 건너뛴다. PC 모드에서 따로 측정하기 전까지는 원래 루프. + if getattr(getattr(context, "sandbox", None), "is_connector_local", False): + return WorkspaceFastPath(text=text, active=False, reason="connector_local") fs = tool_fs(context) try: diff --git a/tests/unit/test_workspace_fast_path.py b/tests/unit/test_workspace_fast_path.py index 90920b1..936b3a6 100644 --- a/tests/unit/test_workspace_fast_path.py +++ b/tests/unit/test_workspace_fast_path.py @@ -38,6 +38,28 @@ def test_disabled_fast_path_does_not_touch_the_filesystem() -> None: assert plan.reason == "disabled" +class _UserPcSandbox: + """커넥터 로컬 동기화 — 작업 공간이 사용자 PC 다. 건드리면 실패한다.""" + + is_connector_local = True + + def __getattr__(self, name): + raise AssertionError(f"PC 작업 공간을 건드렸다: {name}") + + +def test_user_pc_workspace_never_takes_the_fast_path(tmp_path) -> None: + """PC 모드는 측정하지 않은 경로다 — 스냅샷도 찍지 않고 원래 루프로 간다.""" + (tmp_path / "notes.md").write_text("x", encoding="utf-8") + context = ToolContext(working_dir=str(tmp_path), allowed_paths=[str(tmp_path)]) + context.sandbox = _UserPcSandbox() + plan = asyncio.run( + prepare_workspace_fast_path(f"{tmp_path}/notes.md 고쳐 줘", (), context, enabled=True) + ) + assert plan.active is False + assert plan.reason == "connector_local" + assert plan.text == f"{tmp_path}/notes.md 고쳐 줘" + + def test_small_complete_workspace_with_explicit_root_is_injected(tmp_path) -> None: (tmp_path / "INPUT").write_text("alpha", encoding="utf-8") (tmp_path / "data.oddity").write_text("beta", encoding="utf-8")