fix(context): scale replay cap with context window

This commit is contained in:
chengyongru
2026-06-29 14:23:55 +08:00
committed by Xubin Ren
parent dacc699293
commit 40282e3b74
5 changed files with 83 additions and 11 deletions
+15 -3
View File
@@ -57,7 +57,11 @@ from nanobot.session.goal_state import (
sustained_goal_active,
)
from nanobot.session.keys import UNIFIED_SESSION_KEY, session_key_for_channel
from nanobot.session.manager import DEFAULT_REPLAY_MAX_MESSAGES, Session, SessionManager
from nanobot.session.manager import (
Session,
SessionManager,
replay_max_messages_for_context,
)
from nanobot.utils.document import extract_documents, reference_non_image_attachments
from nanobot.utils.helpers import image_placeholder_text
from nanobot.utils.helpers import truncate_text as truncate_text_fn
@@ -201,7 +205,7 @@ class AgentLoop:
timezone: str | None = None,
session_ttl_minutes: int = 0,
consolidation_ratio: float = 0.5,
max_messages: int = DEFAULT_REPLAY_MAX_MESSAGES,
max_messages: int = 0,
hooks: list[AgentHook] | None = None,
unified_session: bool = False,
disabled_skills: list[str] | None = None,
@@ -292,8 +296,11 @@ class AgentLoop:
llm_wall_timeout_for_session=lambda sk: runner_wall_llm_timeout_s(self.sessions, sk),
)
self._unified_session = unified_session
self._explicit_max_messages = max_messages > 0
self._max_messages = (
max_messages if max_messages > 0 else DEFAULT_REPLAY_MAX_MESSAGES
max_messages
if self._explicit_max_messages
else replay_max_messages_for_context(self.context_window_tokens)
)
self._running = False
self._mcp_servers = mcp_servers or {}
@@ -422,6 +429,7 @@ class AgentLoop:
self.runner.provider = provider
self.subagents.set_provider(provider, model)
self.consolidator.set_provider(provider, model, context_window_tokens)
self._sync_replay_max_messages()
self._provider_signature = snapshot.signature
if publish_update and self._runtime_model_publisher is not None:
self._runtime_model_publisher(
@@ -435,6 +443,10 @@ class AgentLoop:
)
logger.info("Runtime model switched for next turn: {} -> {}", old_model, model)
def _sync_replay_max_messages(self) -> None:
if not self._explicit_max_messages:
self._max_messages = replay_max_messages_for_context(self.context_window_tokens)
def _refresh_provider_snapshot(self) -> None:
if self._provider_snapshot_loader is None:
return
+3
View File
@@ -438,6 +438,9 @@ class MyTool(Tool, ContextAware):
setattr(self._runtime_state, key, value)
if key == "model":
self._runtime_state._active_preset = None
sync_replay = getattr(self._runtime_state, "_sync_replay_max_messages", None)
if key == "context_window_tokens" and callable(sync_replay):
sync_replay()
if key == "max_iterations" and hasattr(self._runtime_state, "_sync_subagent_runtime_limits"):
self._runtime_state._sync_subagent_runtime_limits()
self._audit("modify", f"{key}: {old!r} -> {value!r}")
+12 -1
View File
@@ -27,7 +27,9 @@ from nanobot.utils.helpers import (
from nanobot.utils.subagent_channel_display import scrub_subagent_announce_body
FILE_MAX_MESSAGES = 2000
DEFAULT_REPLAY_MAX_MESSAGES = 500
MIN_REPLAY_MAX_MESSAGES = 120
REPLAY_TOKENS_PER_MESSAGE = 100
DEFAULT_REPLAY_MAX_MESSAGES = FILE_MAX_MESSAGES
_MESSAGE_TIME_PREFIX_RE = re.compile(r"^\[Message Time: [^\]]+\]\n?")
_LOCAL_IMAGE_BREADCRUMB_RE = re.compile(r"^\[image: (?:/|~)[^\]]+\]\s*$")
_TOOL_CALL_ECHO_RE = re.compile(r'^\s*(?:generate_image|message)\([^)]*\)\s*$')
@@ -44,6 +46,15 @@ _FORK_VOLATILE_METADATA_KEYS = {
}
def replay_max_messages_for_context(context_window_tokens: int | None) -> int:
if not context_window_tokens or context_window_tokens <= 0:
return DEFAULT_REPLAY_MAX_MESSAGES
return min(
FILE_MAX_MESSAGES,
max(MIN_REPLAY_MAX_MESSAGES, context_window_tokens // REPLAY_TOKENS_PER_MESSAGE),
)
def _sanitize_assistant_replay_text(content: str) -> str:
"""Remove internal replay artifacts that the model may have copied before.