37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
|
|
"""Context budget estimation and compaction."""
|
||
|
|
from typing import Optional
|
||
|
|
|
||
|
|
|
||
|
|
def estimate_tokens(text: str) -> int:
|
||
|
|
"""Rough token count estimation (chars / 4)."""
|
||
|
|
if not text:
|
||
|
|
return 0
|
||
|
|
return max(1, len(text) // 4)
|
||
|
|
|
||
|
|
|
||
|
|
def estimate_ratio(estimated_tokens: int, max_context_tokens: int) -> float:
|
||
|
|
"""Return ratio of used tokens to max context."""
|
||
|
|
if max_context_tokens <= 0:
|
||
|
|
return 0.0
|
||
|
|
return estimated_tokens / max_context_tokens
|
||
|
|
|
||
|
|
|
||
|
|
def should_warn(ratio: float, threshold: float = 0.8) -> bool:
|
||
|
|
"""Check if a warning should be issued based on usage ratio."""
|
||
|
|
return ratio >= threshold
|
||
|
|
|
||
|
|
|
||
|
|
def should_hard_compact(ratio: float, threshold: float = 0.9) -> bool:
|
||
|
|
"""Check if forced compaction is needed."""
|
||
|
|
return ratio >= threshold
|
||
|
|
|
||
|
|
|
||
|
|
def compact_text(text: str, max_lines: int = 80) -> str:
|
||
|
|
"""Compress text by keeping head and tail lines, inserting a compaction marker."""
|
||
|
|
lines = text.splitlines()
|
||
|
|
if len(lines) <= max_lines:
|
||
|
|
return text
|
||
|
|
head = lines[:max_lines // 2]
|
||
|
|
tail = lines[-max_lines // 2:]
|
||
|
|
return "\n".join(head + ["", "... [compacted] ...", ""] + tail)
|