mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-04 22:12:20 +02:00
Squash Odysseus development history
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
"""Issue #1170 — the agent input-token budget adapts to the model context window.
|
||||
|
||||
Pins the pure budget computation and the explicit-override detection.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
from src.context_budget import (
|
||||
DEFAULT_HARD_MAX,
|
||||
bound_trim_reserve,
|
||||
compute_input_token_budget,
|
||||
compute_trim_context_window,
|
||||
)
|
||||
|
||||
|
||||
def test_trim_reserve_cannot_consume_small_effective_budget():
|
||||
assert bound_trim_reserve(1638, 2048) == 819
|
||||
assert bound_trim_reserve(100, 2048) == 50
|
||||
assert bound_trim_reserve(4096, 512) == 512
|
||||
|
||||
|
||||
def test_trim_window_adds_response_reserve_to_input_budget_once():
|
||||
trim_window, reserve = compute_trim_context_window(1638, 4096, 1024)
|
||||
|
||||
assert trim_window == 2662
|
||||
assert reserve == 1024
|
||||
assert trim_window - reserve == 1638
|
||||
|
||||
|
||||
def test_trim_window_keeps_half_of_tiny_context_for_input():
|
||||
trim_window, reserve = compute_trim_context_window(435, 512, 1024)
|
||||
|
||||
assert trim_window == 512
|
||||
assert reserve == 256
|
||||
assert trim_window - reserve == 256
|
||||
|
||||
|
||||
def test_default_scales_to_context_window():
|
||||
# Not explicit, big window -> ~85% of the window (the old code capped at 6000).
|
||||
assert compute_input_token_budget(6000, 128000, explicit=False) == int(128000 * 0.85)
|
||||
|
||||
|
||||
def test_default_capped_at_hard_max_for_huge_windows():
|
||||
assert compute_input_token_budget(6000, 1_000_000, explicit=False) == DEFAULT_HARD_MAX
|
||||
|
||||
|
||||
def test_explicit_budget_is_honoured():
|
||||
# User explicitly chose 6000 -> keep it even on a 128K model.
|
||||
assert compute_input_token_budget(6000, 128000, explicit=True) == 6000
|
||||
# A larger explicit budget is honoured too, clamped to the window.
|
||||
assert compute_input_token_budget(50000, 128000, explicit=True) == 50000
|
||||
|
||||
|
||||
def test_explicit_budget_clamped_to_window():
|
||||
assert compute_input_token_budget(200000, 32000, explicit=True) == 32000
|
||||
|
||||
|
||||
def test_unknown_window_falls_back_to_configured():
|
||||
assert compute_input_token_budget(6000, 0, explicit=False) == 6000
|
||||
assert compute_input_token_budget(0, 0, explicit=False) == 6000 # default
|
||||
|
||||
|
||||
def test_invalid_numeric_inputs_fall_back_cleanly():
|
||||
assert compute_input_token_budget("bad", "also bad", explicit=False) == 6000
|
||||
assert compute_input_token_budget("bad", 128000, explicit=True) == int(128000 * 0.85)
|
||||
|
||||
|
||||
def test_is_setting_overridden_reads_raw_saved_file(tmp_path, monkeypatch):
|
||||
import src.settings as settings
|
||||
|
||||
f = tmp_path / "settings.json"
|
||||
f.write_text(json.dumps({"agent_input_token_budget": 12000}), encoding="utf-8")
|
||||
monkeypatch.setattr(settings, "SETTINGS_FILE", str(f))
|
||||
assert settings.is_setting_overridden("agent_input_token_budget") is True
|
||||
assert settings.is_setting_overridden("some_unset_key") is False
|
||||
|
||||
f.write_text(json.dumps({}), encoding="utf-8")
|
||||
assert settings.is_setting_overridden("agent_input_token_budget") is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configurable hard_max — the ceiling on the auto-derived path is a setting
|
||||
# (`agent_input_token_hard_max`), not a hidden constant. History: a reviewer
|
||||
# required it on #1190, the merged #1230 shipped without it, and #1273 added it.
|
||||
# This test pins the function-level override (the `hard_max` parameter); without
|
||||
# a raisable ceiling, admins on 1M+ context APIs would be stuck at the 200K default.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_custom_hard_max_overrides_default_in_auto_branch():
|
||||
"""A caller-supplied hard_max lifts the auto-derived ceiling."""
|
||||
# Without override: 1M ctx -> capped at DEFAULT_HARD_MAX (200K)
|
||||
assert compute_input_token_budget(6000, 1_000_000, explicit=False) == DEFAULT_HARD_MAX
|
||||
# With explicit raise: 1M ctx -> 850K (85% of 1M), under the raised ceiling
|
||||
assert compute_input_token_budget(6000, 1_000_000, explicit=False, hard_max=900_000) == int(1_000_000 * 0.85)
|
||||
|
||||
|
||||
def test_custom_hard_max_lowers_default_for_cost_paranoid_setups():
|
||||
"""A lower ceiling caps the auto-derived budget below the default."""
|
||||
# 128K ctx, default ceiling 200K -> 85% of 128K = 108800
|
||||
assert compute_input_token_budget(6000, 128_000, explicit=False) == int(128_000 * 0.85)
|
||||
# Same ctx, ceiling lowered to 50K -> capped at 50K instead
|
||||
assert compute_input_token_budget(6000, 128_000, explicit=False, hard_max=50_000) == 50_000
|
||||
|
||||
|
||||
def test_hard_max_has_no_effect_on_explicit_branch():
|
||||
"""When the user set an explicit budget, hard_max must not silently cap it."""
|
||||
# User chose 900K explicitly; ctx is 1M; ceiling is 100K — user's choice wins.
|
||||
assert compute_input_token_budget(900_000, 1_000_000, explicit=True, hard_max=100_000) == 900_000
|
||||
|
||||
|
||||
def test_default_settings_registers_hard_max_key():
|
||||
"""Required so /api/auth/settings and manage_settings can persist the key."""
|
||||
from src.settings import DEFAULT_SETTINGS
|
||||
assert "agent_input_token_hard_max" in DEFAULT_SETTINGS
|
||||
assert DEFAULT_SETTINGS["agent_input_token_hard_max"] == DEFAULT_HARD_MAX
|
||||
|
||||
|
||||
def test_alias_map_registers_friendly_names():
|
||||
"""`manage_settings` should accept 'hard max' and friends."""
|
||||
from pathlib import Path
|
||||
# manage_settings (and its alias map) moved to agent_tools/admin_tools.py in #3629.
|
||||
src = Path("src/agent_tools/admin_tools.py").read_text()
|
||||
assert '"hard max": "agent_input_token_hard_max"' in src
|
||||
assert '"token budget cap": "agent_input_token_hard_max"' in src
|
||||
assert '"input budget cap": "agent_input_token_hard_max"' in src
|
||||
|
||||
|
||||
def test_agent_loop_reads_hard_max_setting(tmp_path, monkeypatch):
|
||||
"""End-to-end: a saved settings.json value for agent_input_token_hard_max
|
||||
must reach compute_input_token_budget on the real agent_loop call path."""
|
||||
import src.settings as settings
|
||||
# Point SETTINGS_FILE at a temp file with our override.
|
||||
f = tmp_path / "settings.json"
|
||||
f.write_text(json.dumps({"agent_input_token_hard_max": 750_000}), encoding="utf-8")
|
||||
monkeypatch.setattr(settings, "SETTINGS_FILE", str(f))
|
||||
monkeypatch.setattr(settings, "_settings_cache", None)
|
||||
# Read via the same import path the agent loop uses.
|
||||
assert settings.get_setting("agent_input_token_hard_max", DEFAULT_HARD_MAX) == 750_000
|
||||
|
||||
# Malformed value falls back to DEFAULT_HARD_MAX (defensive, matches the
|
||||
# try/except in src/agent_loop.py).
|
||||
f.write_text(json.dumps({"agent_input_token_hard_max": "huge"}), encoding="utf-8")
|
||||
monkeypatch.setattr(settings, "_settings_cache", None)
|
||||
raw = settings.get_setting("agent_input_token_hard_max", DEFAULT_HARD_MAX)
|
||||
try:
|
||||
parsed = int(raw)
|
||||
except (TypeError, ValueError):
|
||||
parsed = DEFAULT_HARD_MAX
|
||||
if parsed <= 0:
|
||||
parsed = DEFAULT_HARD_MAX
|
||||
assert parsed == DEFAULT_HARD_MAX
|
||||
Reference in New Issue
Block a user