feat(compression): add summary_base_url + move compression config to YAML-only

- Add summary_base_url config option to compression block for custom
  OpenAI-compatible endpoints (e.g. zai, DeepSeek, Ollama)
- Remove compression env var bridges from cli.py and gateway/run.py
  (CONTEXT_COMPRESSION_* env vars no longer set from config)
- Switch run_agent.py to read compression config directly from
  config.yaml instead of env vars
- Fix backwards-compat block in _resolve_task_provider_model to also
  fire when auxiliary.compression.provider is 'auto' (DEFAULT_CONFIG
  sets this, which was silently preventing the compression section's
  summary_* keys from being read)
- Add test for summary_base_url config-to-client flow
- Update docs to show compression as config.yaml-only

Closes #1591
Based on PR #1702 by @uzaylisak
This commit is contained in:
Teknium 2026-03-17 04:46:15 -07:00 committed by GitHub
parent 867a96c051
commit d1d17f4f0a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 194 additions and 98 deletions

View file

@ -28,22 +28,10 @@ def _run_auxiliary_bridge(config_dict, monkeypatch):
"AUXILIARY_VISION_BASE_URL", "AUXILIARY_VISION_API_KEY",
"AUXILIARY_WEB_EXTRACT_PROVIDER", "AUXILIARY_WEB_EXTRACT_MODEL",
"AUXILIARY_WEB_EXTRACT_BASE_URL", "AUXILIARY_WEB_EXTRACT_API_KEY",
"CONTEXT_COMPRESSION_PROVIDER", "CONTEXT_COMPRESSION_MODEL",
):
monkeypatch.delenv(key, raising=False)
# Compression bridge
compression_cfg = config_dict.get("compression", {})
if compression_cfg and isinstance(compression_cfg, dict):
compression_env_map = {
"enabled": "CONTEXT_COMPRESSION_ENABLED",
"threshold": "CONTEXT_COMPRESSION_THRESHOLD",
"summary_model": "CONTEXT_COMPRESSION_MODEL",
"summary_provider": "CONTEXT_COMPRESSION_PROVIDER",
}
for cfg_key, env_var in compression_env_map.items():
if cfg_key in compression_cfg:
os.environ[env_var] = str(compression_cfg[cfg_key])
# Compression config is read directly from config.yaml — no env var bridging.
# Auxiliary bridge
auxiliary_cfg = config_dict.get("auxiliary", {})
@ -134,17 +122,6 @@ class TestAuxiliaryConfigBridge:
assert os.environ.get("AUXILIARY_VISION_API_KEY") == "local-key"
assert os.environ.get("AUXILIARY_VISION_MODEL") == "qwen2.5-vl"
def test_compression_provider_bridged(self, monkeypatch):
config = {
"compression": {
"summary_provider": "nous",
"summary_model": "gemini-3-flash",
}
}
_run_auxiliary_bridge(config, monkeypatch)
assert os.environ.get("CONTEXT_COMPRESSION_PROVIDER") == "nous"
assert os.environ.get("CONTEXT_COMPRESSION_MODEL") == "gemini-3-flash"
def test_empty_values_not_bridged(self, monkeypatch):
config = {
"auxiliary": {
@ -186,18 +163,12 @@ class TestAuxiliaryConfigBridge:
def test_all_tasks_with_overrides(self, monkeypatch):
config = {
"compression": {
"summary_provider": "main",
"summary_model": "local-model",
},
"auxiliary": {
"vision": {"provider": "openrouter", "model": "google/gemini-2.5-flash"},
"web_extract": {"provider": "nous", "model": "gemini-3-flash"},
}
}
_run_auxiliary_bridge(config, monkeypatch)
assert os.environ.get("CONTEXT_COMPRESSION_PROVIDER") == "main"
assert os.environ.get("CONTEXT_COMPRESSION_MODEL") == "local-model"
assert os.environ.get("AUXILIARY_VISION_PROVIDER") == "openrouter"
assert os.environ.get("AUXILIARY_VISION_MODEL") == "google/gemini-2.5-flash"
assert os.environ.get("AUXILIARY_WEB_EXTRACT_PROVIDER") == "nous"
@ -240,12 +211,12 @@ class TestGatewayBridgeCodeParity:
assert "AUXILIARY_WEB_EXTRACT_BASE_URL" in content
assert "AUXILIARY_WEB_EXTRACT_API_KEY" in content
def test_gateway_has_compression_provider(self):
"""Gateway must bridge compression.summary_provider."""
def test_gateway_no_compression_env_bridge(self):
"""Gateway should NOT bridge compression config to env vars (config-only)."""
gateway_path = Path(__file__).parent.parent / "gateway" / "run.py"
content = gateway_path.read_text()
assert "summary_provider" in content
assert "CONTEXT_COMPRESSION_PROVIDER" in content
assert "CONTEXT_COMPRESSION_PROVIDER" not in content
assert "CONTEXT_COMPRESSION_MODEL" not in content
# ── Vision model override tests ──────────────────────────────────────────────
@ -308,6 +279,12 @@ class TestDefaultConfigShape:
assert "summary_provider" in compression
assert compression["summary_provider"] == "auto"
def test_compression_base_url_default(self):
from hermes_cli.config import DEFAULT_CONFIG
compression = DEFAULT_CONFIG["compression"]
assert "summary_base_url" in compression
assert compression["summary_base_url"] is None
# ── CLI defaults parity ─────────────────────────────────────────────────────