From 4684858164709717d97759747fdc64e5c6bdbec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=EC=84=B1=EC=A4=80?= Date: Sat, 26 Sep 2026 13:12:46 +0900 Subject: [PATCH] =?UTF-8?q?fix(host):=20=EC=9E=91=EC=97=85=20=EA=B3=B5?= =?UTF-8?q?=EA=B0=84=EC=9D=B4=20=EC=82=AC=EC=9A=A9=EC=9E=90=20PC=20?= =?UTF-8?q?=EC=9D=B8=20=EB=AA=A8=EB=93=9C(=EC=BB=A4=EB=84=A5=ED=84=B0=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EB=8F=99=EA=B8=B0=ED=99=94)=EB=8A=94=20?= =?UTF-8?q?=EB=B9=A0=EB=A5=B8=20=EA=B2=BD=EB=A1=9C=EC=97=90=20=EB=84=A3?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=EB=8B=A4=20(4.63.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4.63.0 빠른 경로는 서버 sandbox 에서만 측정했다. 커넥터 로컬 동기화 모드에서는 스냅샷이 사용자 PC 로 가는 원격 실행이고(PC 에 python3 필요) "Bash 한 번에 다 하라" 는 지시가 사용자 PC 에서 돈다 — DeX 의 위험 명령 확인(_Exec)도 아직 배포 전이다. 요청 파일 첨부(referenced_files)와 같은 기준으로 이 모드를 건너뛴다. sandbox.is_connector_local 이면 파일을 건드리기 전에 reason=connector_local 로 원래 루프. 테스트는 수정 전 실패 확인. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 10 +++++++++ pyproject.toml | 2 +- .../host/workspace_fast_path.py | 6 +++++ tests/unit/test_workspace_fast_path.py | 22 +++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) 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")