Spaces:
Running
Running
| from app.services.context_budget import ( | |
| ContextSummary, | |
| DEFAULT_CONTEXT, | |
| DEFAULT_REPLY_BUDGET, | |
| SUMMARIZE_THRESHOLD, | |
| TRIM_THRESHOLD, | |
| build_compressed_messages, | |
| context_window_for, | |
| estimate_messages_tokens, | |
| select_summarizer_model_id, | |
| should_summarize, | |
| ) | |
| def test_context_window_known_model(): | |
| assert context_window_for("gpt-4.1-mini") == 128_000 | |
| def test_context_window_unknown_falls_back(): | |
| assert context_window_for("totally-unknown") == DEFAULT_CONTEXT | |
| def test_context_window_neon_falls_back(): | |
| assert context_window_for("neon:Foo/Bar@2025.10.01:Researcher") == DEFAULT_CONTEXT | |
| def test_estimate_tokens_grows_with_text(): | |
| a = estimate_messages_tokens([{"role": "user", "content": "hi"}]) | |
| b = estimate_messages_tokens([{"role": "user", "content": "hi" * 1000}]) | |
| assert b > a | |
| def test_should_summarize_below_threshold(): | |
| """A small ~10-token prompt against a 1M-token gemini window: never | |
| should we trigger summarize. | |
| """ | |
| summary = ContextSummary() | |
| api = [{"role": "user", "content": "hello"}] | |
| needs_sum, needs_trim, _ = should_summarize("gemini-2.5-flash", api, summary) | |
| assert needs_sum is False | |
| assert needs_trim is False | |
| def test_should_summarize_above_threshold_triggers_summarize(): | |
| summary = ContextSummary() | |
| big = "x" * 10_000 # ~2500 estimated tokens | |
| api = [ | |
| {"role": "system", "content": big}, | |
| {"role": "user", "content": big}, | |
| ] | |
| # Small 8K-window model -> 6K input budget -> 55% = 3300; we're way over. | |
| needs_sum, _, budget = should_summarize("totally-unknown", api, summary) | |
| assert needs_sum is True | |
| assert budget >= 2_048 | |
| def test_should_trim_only_when_summary_exists(): | |
| """Even at 70%, trim should only happen once we already have a | |
| running summary - otherwise we'd drop history with no replacement. | |
| """ | |
| summary = ContextSummary() | |
| big = "x" * 30_000 | |
| api = [ | |
| {"role": "system", "content": big}, | |
| {"role": "user", "content": big}, | |
| ] | |
| _, needs_trim_no_sum, _ = should_summarize("totally-unknown", api, summary) | |
| assert needs_trim_no_sum is False | |
| summary.summary_text = "Previously, the group discussed X." | |
| _, needs_trim_yes_sum, _ = should_summarize("totally-unknown", api, summary) | |
| assert needs_trim_yes_sum is True | |
| def test_build_compressed_keeps_system_and_recent(): | |
| summary = ContextSummary(summary_text="condensed history") | |
| msgs = [ | |
| {"role": "system", "content": "you are X"}, | |
| {"role": "user", "content": "old1"}, | |
| {"role": "assistant", "content": "oldA"}, | |
| {"role": "user", "content": "old2"}, | |
| {"role": "assistant", "content": "oldB"}, | |
| {"role": "user", "content": "recent"}, | |
| ] | |
| out = build_compressed_messages(msgs, summary, needs_trim=True) | |
| # head + summary + last KEEP_RECENT_MESSAGES (=6) <= len(msgs) so we | |
| # might end up with everything; the contract is just that the | |
| # original system and the running summary are preserved. | |
| assert out[0] == msgs[0] | |
| assert any("Summary of earlier" in m["content"] for m in out) | |
| def test_select_summarizer_falls_back(): | |
| # Override wins | |
| assert select_summarizer_model_id("custom", "orch") == "custom" | |
| # Falls back to orchestrator if no override | |
| assert select_summarizer_model_id(None, "orch") == "orch" | |