mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
test(compression): behavioral + config wiring coverage for threshold_tokens
Follow-up for salvaged #24279: - cli-config.yaml.example: document compression.threshold_tokens (commented-out, default null = disabled) - contributors/emails: map maly.dan@gmail.com -> DanielMaly - tests: should_compress() fires at the absolute cap below the pct threshold (first-fires-wins); DEFAULT_CONFIG ships None and 0/None are behavior-neutral incl. across update_model(); the small-context pct floor is unaffected by the cap and re-derives correctly on model switch
This commit is contained in:
parent
e5078e3152
commit
020bd1ba0a
3 changed files with 71 additions and 0 deletions
|
|
@ -424,6 +424,15 @@ compression:
|
|||
# "claude-sonnet": 0.35
|
||||
# "gpt-5": 0.30
|
||||
|
||||
# Optional absolute token cap for the compression trigger (default: null = disabled).
|
||||
# When set, compression fires at the LOWER of the ratio-based threshold and this
|
||||
# absolute token count — first-fires-wins. It never fires later than this count
|
||||
# regardless of which model is active (useful when switching between models with
|
||||
# very different context windows). Clamped to the model's context length at
|
||||
# apply-time, so a cap above the window is a no-op (ratio-based threshold wins).
|
||||
# Survives model switches and fallback activations.
|
||||
# threshold_tokens: 200000
|
||||
|
||||
# Existing Codex gpt-5.5 behavior: raise Hermes' compaction trigger to 85%
|
||||
# for the ChatGPT Codex OAuth route. Set false to opt back down to threshold.
|
||||
codex_gpt55_autoraise: true
|
||||
|
|
|
|||
1
contributors/emails/maly.dan@gmail.com
Normal file
1
contributors/emails/maly.dan@gmail.com
Normal file
|
|
@ -0,0 +1 @@
|
|||
DanielMaly
|
||||
|
|
@ -3306,6 +3306,67 @@ class TestThresholdTokensCap:
|
|||
)
|
||||
assert comp_str.threshold_tokens_cap is None
|
||||
|
||||
def test_should_compress_fires_at_cap_below_ratio_threshold(self):
|
||||
"""Behavioral: with a cap below the ratio-based threshold,
|
||||
should_compress() fires once usage crosses the cap — even though
|
||||
the percentage threshold has not been reached (first-fires-wins)."""
|
||||
with patch("agent.context_compressor.get_model_context_length", return_value=1_000_000):
|
||||
comp = ContextCompressor(
|
||||
"model-a", threshold_percent=0.50, quiet_mode=True,
|
||||
threshold_tokens_cap=200_000,
|
||||
)
|
||||
# Ratio-based would be 500K; cap pulls the trigger down to 200K.
|
||||
assert comp.should_compress(150_000) is False # below cap
|
||||
assert comp.should_compress(200_000) is True # at cap (below 500K pct)
|
||||
assert comp.should_compress(250_000) is True # above cap
|
||||
|
||||
def test_default_config_disabled_and_no_behavior_change(self):
|
||||
"""DEFAULT_CONFIG ships threshold_tokens=None (disabled) and both
|
||||
None and 0 leave the ratio-based trigger byte-identical."""
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
assert DEFAULT_CONFIG["compression"]["threshold_tokens"] is None
|
||||
|
||||
with patch("agent.context_compressor.get_model_context_length", return_value=1_000_000):
|
||||
baseline = ContextCompressor(
|
||||
"model-a", threshold_percent=0.50, quiet_mode=True,
|
||||
)
|
||||
comp_none = ContextCompressor(
|
||||
"model-a", threshold_percent=0.50, quiet_mode=True,
|
||||
threshold_tokens_cap=None,
|
||||
)
|
||||
comp_zero = ContextCompressor(
|
||||
"model-a", threshold_percent=0.50, quiet_mode=True,
|
||||
threshold_tokens_cap=0,
|
||||
)
|
||||
assert comp_none.threshold_tokens == baseline.threshold_tokens
|
||||
assert comp_zero.threshold_tokens == baseline.threshold_tokens
|
||||
# And after a model switch, still identical to baseline.
|
||||
baseline.update_model("model-b", context_length=200_000)
|
||||
comp_none.update_model("model-b", context_length=200_000)
|
||||
comp_zero.update_model("model-b", context_length=200_000)
|
||||
assert comp_none.threshold_tokens == baseline.threshold_tokens
|
||||
assert comp_zero.threshold_tokens == baseline.threshold_tokens
|
||||
|
||||
def test_pct_floor_unaffected_by_cap(self):
|
||||
"""The small-context pct floor (raise-only to 0.75 under 512K) is
|
||||
computed independently of the cap: the cap clamps the resulting
|
||||
token threshold but never changes threshold_percent, and a
|
||||
cap-free small-context model keeps the floored pct."""
|
||||
with patch("agent.context_compressor.get_model_context_length", return_value=200_000):
|
||||
comp = ContextCompressor(
|
||||
"model-a", threshold_percent=0.50, quiet_mode=True,
|
||||
threshold_tokens_cap=100_000,
|
||||
)
|
||||
# Floor raised pct to 0.75 (200K < 512K) regardless of the cap.
|
||||
assert comp.threshold_percent == 0.75
|
||||
# Cap clamps the token trigger below the floored pct value (150K).
|
||||
assert comp.threshold_tokens == 100_000
|
||||
# Switching to a large-context model drops the pct back to the
|
||||
# configured 0.50 — cap presence doesn't perturb the re-derivation.
|
||||
comp.update_model("model-b", context_length=1_000_000)
|
||||
assert comp.threshold_percent == 0.50
|
||||
assert comp.threshold_tokens == 100_000 # cap still wins over 500K
|
||||
|
||||
|
||||
class TestTruncateToolCallArgsJson:
|
||||
"""Regression tests for #11762.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue