Files
chopratejas--headroom/tests/test_memory_injection_budget.py
wehub-resource-sync 0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:03:20 +08:00

131 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests for :class:`headroom.proxy.memory_injection.MemoryInjectionBudget`.
Pre-PR Headroom had **no token cap on injected memory**: top_k=10
candidates × ~400 tokens each = up to ~4000 tokens injected per
request. None of Letta/Mem0/Cognee/Supermemory ship a token-uncapped
injection path on the hot wire.
``MemoryInjectionBudget`` is the single configurable cap applied to
every injection site so all 5 sites are uniformly bounded — set the
budget once, apply at every handler, dashboards see the same shape.
"""
from __future__ import annotations
from dataclasses import FrozenInstanceError
from headroom.proxy.memory_injection import MemoryInjectionBudget
# ── Value-type contract ───────────────────────────────────────────────
def test_budget_is_frozen() -> None:
b = MemoryInjectionBudget()
try:
b.max_tokens = 99 # type: ignore[misc]
except FrozenInstanceError:
pass
else:
raise AssertionError("MemoryInjectionBudget must be frozen")
def test_budget_defaults() -> None:
"""Default budget is conservative — 1024 tokens, 10 entries, 0.3
similarity floor. Operators can override via config; the default
is hard-set so a misconfiguration can't accidentally unbound
injection."""
b = MemoryInjectionBudget()
assert b.max_tokens == 1024
assert b.max_entries == 10
assert b.min_similarity == 0.3
def test_budget_value_equal() -> None:
a = MemoryInjectionBudget(max_tokens=512, max_entries=5, min_similarity=0.5)
b = MemoryInjectionBudget(max_tokens=512, max_entries=5, min_similarity=0.5)
assert a == b
# ── apply_to_text — bounding the formatted context block ─────────────
def test_apply_to_text_returns_input_when_under_budget() -> None:
"""Short context passes through unchanged — no spurious mutation."""
b = MemoryInjectionBudget(max_tokens=1024)
text = "## Relevant Memories\n1. small fact\n"
out = b.apply_to_text(text)
assert out == text
def test_apply_to_text_truncates_when_over_budget() -> None:
"""Large context is bounded — truncated at the budget. The
truncation here is on the OUTPUT (the formatted injection block),
NOT on the INPUT (which keeps full fidelity per MemoryQuery
contract)."""
# 4 tokens/char heuristic in our cap — make the input clearly
# over even the most generous budget.
b = MemoryInjectionBudget(max_tokens=128) # ~512 chars at 4 char/token
huge = "x" * 100000
out = b.apply_to_text(huge)
# Output should be substantially smaller than input.
assert len(out) < len(huge)
def test_apply_to_text_preserves_full_lines() -> None:
"""When truncating, prefer cutting at line boundaries so the
dashboard renders intact memory entries (no half-truncated bullet
point)."""
b = MemoryInjectionBudget(max_tokens=64) # very tight
text = "## Relevant Memories\n" + "".join(f"{i}. fact {i}\n" for i in range(100))
out = b.apply_to_text(text)
# No partial last line — every retained line ends in newline or is
# the final line.
if out and not out.endswith("\n"):
# The last char is the closing of the final line; it must not
# be in the middle of "fact " — easy heuristic: must not end
# mid-word with a hanging digit-then-period.
assert ". fact" not in out[-15:] or out.rstrip().endswith(("fact 0", "fact 1", "fact 2"))
def test_apply_to_text_handles_empty_input() -> None:
"""Empty input → empty output."""
assert MemoryInjectionBudget().apply_to_text("") == ""
# ── apply_to_entries — bounding the list before formatting ───────────
def test_apply_to_entries_caps_entry_count() -> None:
"""Even if the backend returns 100 candidates, the budget caps
entry count to ``max_entries``."""
b = MemoryInjectionBudget(max_entries=3)
entries = [{"content": f"entry {i}", "score": 0.9 - i * 0.01} for i in range(20)]
out = b.apply_to_entries(entries)
assert len(out) == 3
def test_apply_to_entries_preserves_order_of_input() -> None:
"""Budget doesn't re-rank — the backend's order is preserved. (The
backend should already have ranked by score; budget just caps.)"""
b = MemoryInjectionBudget(max_entries=2)
entries = [
{"content": "alpha", "score": 0.9},
{"content": "beta", "score": 0.8},
{"content": "gamma", "score": 0.7},
]
out = b.apply_to_entries(entries)
assert [e["content"] for e in out] == ["alpha", "beta"]
def test_apply_to_entries_filters_below_min_similarity() -> None:
"""Entries below ``min_similarity`` are dropped, regardless of
entry-count budget remaining."""
b = MemoryInjectionBudget(max_entries=10, min_similarity=0.5)
entries = [
{"content": "kept", "score": 0.9},
{"content": "dropped", "score": 0.3},
{"content": "kept2", "score": 0.55},
]
out = b.apply_to_entries(entries)
assert {e["content"] for e in out} == {"kept", "kept2"}