refactor(prompt): route context-file cwd through runtime_cwd resolver

This commit is contained in:
firefly
2026-05-29 17:41:14 -04:00
committed by Teknium
parent c79b80a8a5
commit f90777a6b8
2 changed files with 63 additions and 7 deletions

View File

@ -24,7 +24,6 @@ Pure helpers that read the agent's state. AIAgent keeps thin forwarders.
from __future__ import annotations
import json
import os
from typing import Any, Dict, List, Optional
from agent.prompt_builder import (
@ -41,6 +40,7 @@ from agent.prompt_builder import (
TOOL_USE_ENFORCEMENT_GUIDANCE,
TOOL_USE_ENFORCEMENT_MODELS,
)
from agent.runtime_cwd import resolve_context_cwd
def _ra():
@ -288,13 +288,12 @@ def build_system_prompt_parts(agent: Any, system_message: Optional[str] = None)
context_parts.append(system_message)
if not agent.skip_context_files:
# Use TERMINAL_CWD for context file discovery when set (gateway
# mode). The gateway process runs from the hermes-agent install
# dir, so os.getcwd() would pick up the repo's AGENTS.md and
# other dev files — inflating token usage by ~10k for no benefit.
_context_cwd = os.getenv("TERMINAL_CWD") or None
# Prefer the configured TERMINAL_CWD (gateway mode). When unset (local
# CLI), None lets build_context_files_prompt fall back to the launch
# dir — the user's real cwd there, but the install dir for the gateway
# daemon, which is why the gateway sets TERMINAL_CWD.
context_files_prompt = _r.build_context_files_prompt(
cwd=_context_cwd, skip_soul=_soul_loaded)
cwd=resolve_context_cwd(), skip_soul=_soul_loaded)
if context_files_prompt:
context_parts.append(context_files_prompt)

View File

@ -0,0 +1,57 @@
"""Tests for agent/system_prompt.py — context-file cwd wiring."""
from types import SimpleNamespace
from unittest.mock import patch
from agent.system_prompt import build_system_prompt_parts
def _make_agent(**overrides):
base = dict(
load_soul_identity=False,
skip_context_files=False,
valid_tool_names=[],
_task_completion_guidance=False,
_tool_use_enforcement=False,
_environment_probe=False,
_kanban_worker_guidance="",
_memory_store=None,
_memory_manager=None,
model="",
provider="",
platform="",
pass_session_id=False,
session_id="",
)
base.update(overrides)
return SimpleNamespace(**base)
def _captured_context_cwd(agent):
"""The cwd build_system_prompt_parts hands to build_context_files_prompt."""
captured = {}
def fake_context_files(cwd=None, skip_soul=False):
captured["cwd"] = cwd
return ""
with (
patch("run_agent.load_soul_md", return_value=""),
patch("run_agent.build_nous_subscription_prompt", return_value=""),
patch("run_agent.build_environment_hints", return_value=""),
patch("run_agent.build_context_files_prompt", side_effect=fake_context_files),
):
build_system_prompt_parts(agent)
return captured["cwd"]
class TestContextFileCwd:
def test_none_when_terminal_cwd_unset(self, monkeypatch):
# Unset → None, so discovery falls back to the launch dir inside
# build_context_files_prompt (the local-CLI #19242 contract).
monkeypatch.delenv("TERMINAL_CWD", raising=False)
assert _captured_context_cwd(_make_agent()) is None
def test_configured_dir_when_terminal_cwd_set(self, monkeypatch, tmp_path):
monkeypatch.setenv("TERMINAL_CWD", str(tmp_path))
assert _captured_context_cwd(_make_agent()) == tmp_path