Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/fast_agent/history/compaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from fast_agent.constants import FAST_AGENT_COMPACTION_CHANNEL
from fast_agent.core.logging.logger import get_logger
from fast_agent.event_progress import ProgressAction
from fast_agent.mcp.helpers.content_helpers import get_text
from fast_agent.mcp.prompt import Prompt
from fast_agent.types.llm_stop_reason import LlmStopReason

Expand Down Expand Up @@ -185,6 +186,10 @@ def estimate_tokens(messages: list[PromptMessageExtended]) -> int:
for message in messages:
chars += len(message.all_text())
for content in message.content:
if get_text(content) is not None:
# Text is already counted via all_text() above; only serialize
# non-text payloads here (matches the "non-text" docstring).
continue
try:
chars += len(content.model_dump_json())
except Exception:
Expand Down
7 changes: 7 additions & 0 deletions tests/unit/fast_agent/history/test_compaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from fast_agent.config import CompactionSettings, Settings, get_settings
from fast_agent.context import Context
from fast_agent.history.compaction import (
_CHARS_PER_TOKEN,
DEFAULT_COMPACTION_PROMPT,
FAST_AGENT_COMPACTION_CHANNEL,
CompactionSkipped,
Expand Down Expand Up @@ -359,6 +360,12 @@ def test_counts_non_text_content_and_channels(self):

assert estimate_tokens([msg]) > plain + 5_000

def test_does_not_double_count_text(self):
# Text is counted once via all_text(); the per-content loop must skip it
# (docstring: "Count text plus serialized non-text payloads").
text = "x" * 1200
assert estimate_tokens([_user(text)]) == len(text) // _CHARS_PER_TOKEN


class _FakeLLM:
def __init__(self, summary: str = "SUMMARY OF WORK") -> None:
Expand Down
Loading