fix(prompt): skip bundled AGENTS.md for desktop launch cwd
This commit is contained in:
@@ -892,8 +892,16 @@ def build_system_prompt_parts(agent: Any, system_message: Optional[str] = None)
|
||||
# (developing Hermes). Every other surface (desktop chat panel,
|
||||
# gateway daemons) self-spawns into the install tree, where the
|
||||
# fallback would inject this repo's contributor AGENTS.md (#64590).
|
||||
context_cwd = resolve_context_cwd()
|
||||
if getattr(agent, "_context_cwd_is_launch_artifact", False):
|
||||
# Desktop session creation pins the backend launch directory so
|
||||
# tools have a deterministic cwd even when the user picked no
|
||||
# workspace. Preserve that tool routing, but let context discovery
|
||||
# see it as the fallback it really is. The install-tree guard can
|
||||
# then reject Hermes's bundled contributor AGENTS.md (#97448).
|
||||
context_cwd = None
|
||||
context_files_prompt = _r.build_context_files_prompt(
|
||||
cwd=resolve_context_cwd(), skip_soul=_soul_loaded,
|
||||
cwd=context_cwd, skip_soul=_soul_loaded,
|
||||
context_length=_ctx_len,
|
||||
allow_install_tree_fallback=agent.platform in ("cli", "tui"),
|
||||
home_override=_agent_home(agent))
|
||||
|
||||
@@ -66,6 +66,50 @@ class TestContextFileCwd:
|
||||
monkeypatch.setenv("TERMINAL_CWD", str(tmp_path))
|
||||
assert _captured_context_cwd(_make_agent()) == tmp_path
|
||||
|
||||
def test_desktop_launch_artifact_does_not_load_bundled_agents_md(
|
||||
self, monkeypatch, tmp_path
|
||||
):
|
||||
import agent.runtime_cwd as runtime_cwd
|
||||
|
||||
monkeypatch.setattr(runtime_cwd, "_PACKAGE_ROOT", tmp_path.resolve())
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "AGENTS.md").write_text("bundled contributor instructions")
|
||||
|
||||
agent = _make_agent(
|
||||
platform="desktop",
|
||||
_context_cwd_is_launch_artifact=True,
|
||||
)
|
||||
with (
|
||||
patch("run_agent.load_soul_md", return_value=""),
|
||||
patch("run_agent.build_environment_hints", return_value=""),
|
||||
patch("agent.system_prompt.resolve_context_cwd", return_value=tmp_path),
|
||||
):
|
||||
context = build_system_prompt_parts(agent)["context"]
|
||||
|
||||
assert "bundled contributor instructions" not in context
|
||||
|
||||
def test_desktop_explicit_install_tree_workspace_still_loads_agents_md(
|
||||
self, monkeypatch, tmp_path
|
||||
):
|
||||
import agent.runtime_cwd as runtime_cwd
|
||||
|
||||
monkeypatch.setattr(runtime_cwd, "_PACKAGE_ROOT", tmp_path.resolve())
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "AGENTS.md").write_text("chosen workspace instructions")
|
||||
|
||||
agent = _make_agent(
|
||||
platform="desktop",
|
||||
_context_cwd_is_launch_artifact=False,
|
||||
)
|
||||
with (
|
||||
patch("run_agent.load_soul_md", return_value=""),
|
||||
patch("run_agent.build_environment_hints", return_value=""),
|
||||
patch("agent.system_prompt.resolve_context_cwd", return_value=tmp_path),
|
||||
):
|
||||
context = build_system_prompt_parts(agent)["context"]
|
||||
|
||||
assert "chosen workspace instructions" in context
|
||||
|
||||
|
||||
def _stable_prompt(agent):
|
||||
with (
|
||||
|
||||
@@ -496,6 +496,21 @@ def test_desktop_launch_cwd_is_not_persisted_as_a_workspace():
|
||||
) == "/picked/repo"
|
||||
|
||||
|
||||
def test_desktop_launch_cwd_is_marked_as_context_artifact():
|
||||
assert server._context_cwd_is_launch_artifact(
|
||||
{"source": "desktop", "cwd": "/opt/hermes"}
|
||||
) is True
|
||||
|
||||
|
||||
def test_explicit_desktop_and_terminal_cwds_are_context_workspaces():
|
||||
assert server._context_cwd_is_launch_artifact(
|
||||
{"source": "desktop", "cwd": "/picked/repo", "explicit_cwd": True}
|
||||
) is False
|
||||
assert server._context_cwd_is_launch_artifact(
|
||||
{"source": "tui", "cwd": "/opt/hermes"}
|
||||
) is False
|
||||
|
||||
|
||||
def test_home_container_dirs_are_never_a_workspace(tmp_path):
|
||||
"""`/home` and `/Users` hold homes; they are not workspaces themselves.
|
||||
|
||||
|
||||
@@ -573,6 +573,9 @@ class ComputeHost:
|
||||
reasoning_config_override=frame.get("reasoning_config_override"),
|
||||
service_tier_override=frame.get("service_tier_override"),
|
||||
platform_override=frame.get("source"),
|
||||
context_cwd_is_launch_artifact=bool(
|
||||
frame.get("context_cwd_is_launch_artifact", False)
|
||||
),
|
||||
session_db=session_db,
|
||||
)
|
||||
if server._transfer_db_to_agent(agent, session_db):
|
||||
|
||||
@@ -945,6 +945,10 @@ def _(rid, params: dict) -> dict:
|
||||
session_id=target,
|
||||
session_db=db,
|
||||
platform_override=source,
|
||||
context_cwd_is_launch_artifact=(
|
||||
source in _LAUNCH_CWD_NOT_A_WORKSPACE
|
||||
and not profile_resume_cwd
|
||||
),
|
||||
**stored_runtime_overrides,
|
||||
)
|
||||
finally:
|
||||
@@ -3304,6 +3308,9 @@ def _(rid, params: dict) -> dict:
|
||||
session_id=new_key,
|
||||
session_db=branch_db,
|
||||
platform_override=source,
|
||||
context_cwd_is_launch_artifact=(
|
||||
_context_cwd_is_launch_artifact(session)
|
||||
),
|
||||
)
|
||||
finally:
|
||||
_clear_session_context(tokens)
|
||||
|
||||
+22
-1
@@ -2634,6 +2634,7 @@ def _compute_host_turn_frame(
|
||||
"history_version": history_version,
|
||||
"cols": int(session.get("cols", 80) or 80),
|
||||
"cwd": _session_cwd(session),
|
||||
"context_cwd_is_launch_artifact": _context_cwd_is_launch_artifact(session),
|
||||
"profile_home": session.get("profile_home") or "",
|
||||
"model_override": session.get("model_override"),
|
||||
"reasoning_config_override": session.get("create_reasoning_override"),
|
||||
@@ -3568,6 +3569,15 @@ def _session_cwd(session: dict | None) -> str:
|
||||
_LAUNCH_CWD_NOT_A_WORKSPACE = {"desktop"}
|
||||
|
||||
|
||||
def _context_cwd_is_launch_artifact(session: dict | None) -> bool:
|
||||
"""Whether the session cwd came from app launch rather than user intent."""
|
||||
return bool(
|
||||
session
|
||||
and not session.get("explicit_cwd")
|
||||
and _session_source(session) in _LAUNCH_CWD_NOT_A_WORKSPACE
|
||||
)
|
||||
|
||||
|
||||
def _persisted_session_cwd(session: dict) -> str | None:
|
||||
"""The cwd to stamp on the session's DB row, or None to leave it unset.
|
||||
|
||||
@@ -8832,6 +8842,7 @@ def _make_agent(
|
||||
reasoning_config_override: dict | None = None,
|
||||
service_tier_override: str | None = None,
|
||||
platform_override: str | None = None,
|
||||
context_cwd_is_launch_artifact: bool | None = None,
|
||||
):
|
||||
# AC-4 test seam: dead unless explicitly armed by the isolated certify
|
||||
# harness. Both inline and compute-host paths construct through _make_agent,
|
||||
@@ -8961,7 +8972,7 @@ def _make_agent(
|
||||
raise RuntimeError("Auth fallback resolved without a model")
|
||||
model = resolution.selected_model
|
||||
_pr = _load_provider_routing()
|
||||
return AIAgent(
|
||||
agent = AIAgent(
|
||||
model=model,
|
||||
max_iterations=_cfg_max_turns(cfg, 500),
|
||||
provider=runtime.get("provider"),
|
||||
@@ -9008,6 +9019,16 @@ def _make_agent(
|
||||
fallback_model=_load_fallback_model(),
|
||||
**_agent_cbs(sid),
|
||||
)
|
||||
if context_cwd_is_launch_artifact is None:
|
||||
with _sessions_lock:
|
||||
context_session = _sessions.get(sid)
|
||||
context_cwd_is_launch_artifact = _context_cwd_is_launch_artifact(
|
||||
context_session
|
||||
)
|
||||
agent._context_cwd_is_launch_artifact = bool(
|
||||
context_cwd_is_launch_artifact
|
||||
)
|
||||
return agent
|
||||
|
||||
|
||||
def _init_session(
|
||||
|
||||
Reference in New Issue
Block a user