Follow-up to the two salvaged commits (#111777, #111781 by @KoNit-K): - agent/prompt_builder.py::_truncate_content — with queue_warning=False the logged line no longer tells the operator to "pin a larger context_file_max_chars, or use a larger-context model": the subdirectory hint cap is a constant neither knob raises. It now points at the read_file recovery the marker already discloses. - tests/gateway/test_startup_environment_probe.py — replace the call-detection test with the behavioural invariant: an oversized SOUL.md in HERMES_HOME and a warm-up leave the truncation-warning queue empty for the next default-executor task (the api_server turn path runs on that executor without copy_context, which is how the boot warning reached a foreign session). - tests/agent/test_subdirectory_hints.py — fold the new drain assertion into the existing oversized-hint test (same fixture) and pin that the log carries no context_file_max_chars advice. - agent/AGENTS.md, website/docs/.../context-files.md — the hint cap is 32,000 (docs said 8,000) and is fixed; document that it is logged, not surfaced as a chat warning.
61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
"""The gateway boot warm-up primes the local toolchain probe the first prompt build reads (#106064)."""
|
|
|
|
import pytest
|
|
|
|
from agent import prompt_builder
|
|
import model_tools
|
|
from gateway import run as gateway_run
|
|
from tools import env_probe
|
|
from tools.terminal_scope import reset_terminal_scope, set_terminal_scope
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _probe_cache(monkeypatch):
|
|
monkeypatch.setattr(model_tools, "get_tool_definitions", lambda **_: [])
|
|
env_probe._reset_cache_for_tests()
|
|
yield
|
|
env_probe._reset_cache_for_tests()
|
|
|
|
|
|
def _warm(tmp_path, monkeypatch, agent_section: dict, backend: str) -> None:
|
|
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
|
(tmp_path / "config.yaml").write_text(f"agent: {agent_section!r}\n", encoding="utf-8")
|
|
token = set_terminal_scope({"TERMINAL_ENV": backend})
|
|
try:
|
|
gateway_run._warm_turn_machinery_sync()
|
|
finally:
|
|
reset_terminal_scope(token)
|
|
|
|
|
|
def test_warmup_leaves_probe_cached_for_first_prompt(tmp_path, monkeypatch):
|
|
calls = []
|
|
monkeypatch.setattr(env_probe, "_build_probe_line", lambda: calls.append(1) or "Python toolchain: fixture.")
|
|
|
|
_warm(tmp_path, monkeypatch, {}, "local")
|
|
|
|
assert env_probe._PROBE_DONE.is_set()
|
|
assert env_probe.get_environment_probe_line() == "Python toolchain: fixture."
|
|
assert calls == [1] # single worker; the first turn reuses the cache
|
|
|
|
|
|
def test_warmup_queues_no_context_file_warning_for_later_turns(tmp_path, monkeypatch):
|
|
"""Boot has no agent and no model, so the warm-up must not read context files: an identity file over
|
|
the model-less default cap would otherwise queue a truncation warning into the executor thread's context,
|
|
where the next default-executor turn drains it as its own (#111773)."""
|
|
(tmp_path / "SOUL.md").write_text("x" * (prompt_builder.CONTEXT_FILE_MAX_CHARS + 1), encoding="utf-8")
|
|
prompt_builder.drain_truncation_warnings()
|
|
|
|
_warm(tmp_path, monkeypatch, {}, "local")
|
|
|
|
assert prompt_builder.drain_truncation_warnings() == []
|
|
|
|
|
|
@pytest.mark.parametrize("agent_section,backend", [({"environment_probe": False}, "local"), ({}, "ssh")])
|
|
def test_warmup_skips_probe_when_disabled_or_remote(tmp_path, monkeypatch, agent_section, backend):
|
|
monkeypatch.setattr(env_probe, "_build_probe_line", lambda: pytest.fail("host inspected"))
|
|
|
|
_warm(tmp_path, monkeypatch, agent_section, backend)
|
|
|
|
assert not env_probe._PROBE_DONE.is_set()
|
|
assert env_probe._PROBE_THREAD is None
|