mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-08-28 05:25:04 +00:00
refactor(memory): restructure file-based memory components and enhance message handling (#145)
This commit is contained in:
parent
d0c9d89092
commit
5e08aa48b8
23 changed files with 148 additions and 105 deletions
35
README.md
35
README.md
|
|
@ -20,7 +20,7 @@
|
|||
<strong>A memory management toolkit for AI agents — Remember Me, Refine Me.</strong><br>
|
||||
</p>
|
||||
|
||||
> For the older version, please refer to the [0.2.x documentation](docs/README_0_2_x_ZH.md).
|
||||
> For the older version, please refer to the [0.2.x documentation](docs/README_0_2_x.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -64,17 +64,17 @@ working_dir/
|
|||
[ReMeLight](reme/reme_light.py) is the core class of the file-based memory system. It provides full memory management
|
||||
capabilities for AI agents:
|
||||
|
||||
| Method | Function | Key components |
|
||||
|------------------------|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `check_context` | 📊 Check context size | [ContextChecker](reme/memory/file_based/component/context_checker.py) — checks whether context exceeds thresholds and splits messages |
|
||||
| `compact_memory` | 📦 Compact history into summary | [Compactor](reme/memory/file_based/component/compactor.py) — ReActAgent that generates structured context summaries |
|
||||
| `summary_memory` | 📝 Persist important memory to files | [Summarizer](reme/memory/file_based/component/summarizer.py) — ReActAgent + file tools (`read` / `write` / `edit`) |
|
||||
| `compact_tool_result` | ✂️ Compact long tool outputs | [ToolResultCompactor](reme/memory/file_based/component/tool_result_compactor.py) — truncates long tool outputs and stores them in `tool_result/` while keeping file references in messages |
|
||||
| `memory_search` | 🔍 Semantic memory search | [MemorySearch](reme/memory/file_based/tools/memory_search.py) — hybrid retrieval with vectors + BM25 |
|
||||
| `ReMeInMemoryMemory` | 🗂️ In-session memory class | [ReMeInMemoryMemory](reme/memory/file_based/reme_in_memory_memory.py) — token-aware memory management with summary compression and state serialization |
|
||||
| `pre_reasoning_hook` | 🔄 Pre-reasoning hook | `compact_tool_result` + `check_context` + `compact_memory` + `summary_memory` (async) |
|
||||
| `start` | 🚀 Start memory system | Initialize file storage, file watcher, and embedding cache; clean up expired tool result files |
|
||||
| `close` | 📕 Shutdown and cleanup | Clean up tool result files, stop file watcher, and persist embedding cache |
|
||||
| Method | Function | Key components |
|
||||
|-----------------------|--------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `check_context` | 📊 Check context size | [ContextChecker](reme/memory/file_based/components/context_checker.py) — checks whether context exceeds thresholds and splits messages |
|
||||
| `compact_memory` | 📦 Compact history into summary | [Compactor](reme/memory/file_based/components/compactor.py) — ReActAgent that generates structured context summaries |
|
||||
| `summary_memory` | 📝 Persist important memory to files | [Summarizer](reme/memory/file_based/components/summarizer.py) — ReActAgent + file tools (`read` / `write` / `edit`) |
|
||||
| `compact_tool_result` | ✂️ Compact long tool outputs | [ToolResultCompactor](reme/memory/file_based/components/tool_result_compactor.py) — truncates long tool outputs and stores them in `tool_result/` while keeping file references in messages |
|
||||
| `memory_search` | 🔍 Semantic memory search | [MemorySearch](reme/memory/file_based/tools/memory_search.py) — hybrid retrieval with vectors + BM25 |
|
||||
| `ReMeInMemoryMemory` | 🗂️ In-session memory class | [ReMeInMemoryMemory](reme/memory/file_based/reme_in_memory_memory.py) — token-aware memory management with summary compression and state serialization |
|
||||
| `pre_reasoning_hook` | 🔄 Pre-reasoning hook | `compact_tool_result` + `check_context` + `compact_memory` + `summary_memory` (async) |
|
||||
| `start` | 🚀 Start memory system | Initialize file storage, file watcher, and embedding cache; clean up expired tool result files |
|
||||
| `close` | 📕 Shutdown and cleanup | Clean up tool result files, stop file watcher, and persist embedding cache |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ graph LR
|
|||
CC -->|Exceeds limit| SM[summary_memory<br>Async persistence]
|
||||
SM -->|ReAct + FileIO| Files[memory/*.md]
|
||||
Agent -->|Explicit call| Search[memory_search<br>Vector+BM25]
|
||||
Agent -->|In-session| InMem[ReMeInMemoryMemory<br>Token-aware memory]
|
||||
Agent -->|In - session| InMem[ReMeInMemoryMemory<br>Token-aware memory]
|
||||
Files -.->|FileWatcher| Store[(FileStore<br>Vector+FTS index)]
|
||||
Search --> Store
|
||||
```
|
||||
|
|
@ -195,7 +195,7 @@ graph LR
|
|||
|
||||
#### 1. `check_context` — context checking
|
||||
|
||||
[ContextChecker](reme/memory/file_based/component/context_checker.py) uses token counting to determine whether the
|
||||
[ContextChecker](reme/memory/file_based/components/context_checker.py) uses token counting to determine whether the
|
||||
context exceeds thresholds and automatically splits messages into a "to compact" group and a "to keep" group.
|
||||
|
||||
```mermaid
|
||||
|
|
@ -217,7 +217,7 @@ graph LR
|
|||
|
||||
#### 2. `compact_memory` — conversation compaction
|
||||
|
||||
[Compactor](reme/memory/file_based/component/compactor.py) uses a ReActAgent to compact conversation history into a *
|
||||
[Compactor](reme/memory/file_based/components/compactor.py) uses a ReActAgent to compact conversation history into a *
|
||||
*structured context summary**.
|
||||
|
||||
```mermaid
|
||||
|
|
@ -245,7 +245,7 @@ graph LR
|
|||
|
||||
#### 3. `summary_memory` — persistent memory
|
||||
|
||||
[Summarizer](reme/memory/file_based/component/summarizer.py) uses a **ReAct + file tools** pattern so that the AI can
|
||||
[Summarizer](reme/memory/file_based/components/summarizer.py) uses a **ReAct + file tools** pattern so that the AI can
|
||||
decide what to write and where to write it.
|
||||
|
||||
```mermaid
|
||||
|
|
@ -271,7 +271,7 @@ graph LR
|
|||
|
||||
#### 4. `compact_tool_result` — tool result compaction
|
||||
|
||||
[ToolResultCompactor](reme/memory/file_based/component/tool_result_compactor.py) addresses the problem of long tool
|
||||
[ToolResultCompactor](reme/memory/file_based/components/tool_result_compactor.py) addresses the problem of long tool
|
||||
outputs bloating the context.
|
||||
|
||||
```mermaid
|
||||
|
|
@ -534,7 +534,6 @@ We evaluate ReMe on the BFCL-V3 multi-turn-base task (random split 50 train / 15
|
|||
|
||||
For more details on how to reproduce the experiments, see [quickstart.md](benchmark/bfcl/quickstart.md).
|
||||
|
||||
|
||||
## ⭐ Community & support
|
||||
|
||||
- **Star & Watch**: Starring helps more agent developers discover ReMe; Watching keeps you up to date with new releases
|
||||
|
|
|
|||
32
README_ZH.md
32
README_ZH.md
|
|
@ -60,17 +60,18 @@ working_dir/
|
|||
|
||||
[ReMeLight](reme/reme_light.py) 是该记忆系统的核心类,为 AI Agent 提供完整的记忆管理能力:
|
||||
|
||||
| 方法 | 功能 | 关键组件 |
|
||||
|------------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------|
|
||||
| `check_context` | 📊 检查上下文大小 | [ContextChecker](reme/memory/file_based/component/context_checker.py) — 检查上下文是否超出阈值并拆分Message |
|
||||
| `compact_memory` | 📦 压缩历史对话为摘要 | [Compactor](reme/memory/file_based/component/compactor.py) — ReActAgent 生成结构化上下文摘要 |
|
||||
| `summary_memory` | 📝 将重要记忆写入文件 | [Summarizer](reme/memory/file_based/component/summarizer.py) — ReActAgent + 文件工具(read / write / edit) |
|
||||
| `compact_tool_result` | ✂️ 压缩超长工具输出 | [ToolResultCompactor](reme/memory/file_based/component/tool_result_compactor.py) — 截断超长的工具调用结果并转存到 `tool_result/`,消息中保留文件引用 |
|
||||
| `memory_search` | 🔍 语义搜索记忆 | [MemorySearch](reme/memory/file_based/tools/memory_search.py) — 向量 + BM25 混合检索 |
|
||||
| `ReMeInMemoryMemory` | 🗂️ 会话内存类 | [ReMeInMemoryMemory](reme/memory/file_based/reme_in_memory_memory.py) — Token 感知的内存管理,支持压缩摘要和状态序列化 |
|
||||
| `pre_reasoning_hook` | 🔄 推理前预处理钩子 | compact_tool_result + check_context + compact_memory + summary_memory(async) |
|
||||
| `start` | 🚀 启动记忆系统 | 初始化文件存储、文件监控、Embedding 缓存;清理过期工具结果文件 |
|
||||
| `close` | 📕 关闭并清理 | 清理工具结果文件、停止文件监控、保存 Embedding 缓存 |·
|
||||
| 方法 | 功能 | 关键组件 |
|
||||
|-----------------------|--------------|------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `check_context` | 📊 检查上下文大小 | [ContextChecker](reme/memory/file_based/components/context_checker.py) — 检查上下文是否超出阈值并拆分Message |
|
||||
| `compact_memory` | 📦 压缩历史对话为摘要 | [Compactor](reme/memory/file_based/components/compactor.py) — ReActAgent 生成结构化上下文摘要 |
|
||||
| `summary_memory` | 📝 将重要记忆写入文件 | [Summarizer](reme/memory/file_based/components/summarizer.py) — ReActAgent + 文件工具(read / write / edit) |
|
||||
| `compact_tool_result` | ✂️ 压缩超长工具输出 | [ToolResultCompactor](reme/memory/file_based/components/tool_result_compactor.py) — 截断超长的工具调用结果并转存到 `tool_result/`,消息中保留文件引用 |
|
||||
| `memory_search` | 🔍 语义搜索记忆 | [MemorySearch](reme/memory/file_based/tools/memory_search.py) — 向量 + BM25 混合检索 |
|
||||
| `ReMeInMemoryMemory` | 🗂️ 会话内存类 | [ReMeInMemoryMemory](reme/memory/file_based/reme_in_memory_memory.py) — Token 感知的内存管理,支持压缩摘要和状态序列化 |
|
||||
| `pre_reasoning_hook` | 🔄 推理前预处理钩子 | compact_tool_result + check_context + compact_memory + summary_memory(async) |
|
||||
| `start` | 🚀 启动记忆系统 | 初始化文件存储、文件监控、Embedding 缓存;清理过期工具结果文件 |
|
||||
| `close` | 📕 关闭并清理 | 清理工具结果文件、停止文件监控、保存 Embedding 缓存 |·
|
||||
|
||||
---
|
||||
|
||||
### 🚀 快速开始
|
||||
|
|
@ -188,7 +189,7 @@ graph LR
|
|||
|
||||
#### 1. check_context — 上下文检查
|
||||
|
||||
[ContextChecker](reme/memory/file_based/component/context_checker.py) 基于 Token 计数判断上下文是否超限,自动拆分为「待压缩」和「保留」两组消息。
|
||||
[ContextChecker](reme/memory/file_based/components/context_checker.py) 基于 Token 计数判断上下文是否超限,自动拆分为「待压缩」和「保留」两组消息。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
|
@ -208,7 +209,7 @@ graph LR
|
|||
|
||||
#### 2. compact_memory — 对话压缩
|
||||
|
||||
[Compactor](reme/memory/file_based/component/compactor.py) 使用 ReActAgent 将历史对话压缩为**结构化上下文摘要**。
|
||||
[Compactor](reme/memory/file_based/components/compactor.py) 使用 ReActAgent 将历史对话压缩为**结构化上下文摘要**。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
|
@ -235,7 +236,7 @@ graph LR
|
|||
|
||||
#### 3. summary_memory — 记忆持久化
|
||||
|
||||
[Summarizer](reme/memory/file_based/component/summarizer.py) 采用 **ReAct + 文件工具** 模式,让 AI 自主决定写什么、写到哪。
|
||||
[Summarizer](reme/memory/file_based/components/summarizer.py) 采用 **ReAct + 文件工具** 模式,让 AI 自主决定写什么、写到哪。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
|
@ -260,7 +261,7 @@ graph LR
|
|||
|
||||
#### 4. compact_tool_result — 工具结果压缩
|
||||
|
||||
[ToolResultCompactor](reme/memory/file_based/component/tool_result_compactor.py) 解决工具输出过长导致上下文膨胀的问题。
|
||||
[ToolResultCompactor](reme/memory/file_based/components/tool_result_compactor.py) 解决工具输出过长导致上下文膨胀的问题。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
|
|
@ -518,7 +519,6 @@ Pass@K 衡量在生成 K 个候选中,至少一个成功完成任务(score=1
|
|||
|
||||
关于如何复现实验的更多细节,见 [quickstart.md](benchmark/bfcl/quickstart.md)
|
||||
|
||||
|
||||
## ⭐ 社区与支持
|
||||
|
||||
- **Star 与 Watch**:Star 可让更多智能体开发者发现 ReMe;Watch 可助你第一时间获知新版本与特性。
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ class AsBlockStat(BaseModel):
|
|||
"""Return a short preview of the block content."""
|
||||
return self.format(_DEFAULT_MAX_BLOCK_TEXT_PREVIEW_LENGTH)
|
||||
|
||||
def _truncate(self, text: str, max_length: int) -> str:
|
||||
"""Simple truncation with ellipsis."""
|
||||
if len(text) <= max_length:
|
||||
return text
|
||||
return text[:max_length] + "..."
|
||||
|
||||
# pylint: disable=too-many-return-statements
|
||||
def format(self, max_length: int = _DEFAULT_MAX_FORMATTER_TEXT_LENGTH, include_thinking: bool = True) -> str:
|
||||
"""Format block content to string representation.
|
||||
|
|
@ -37,22 +43,25 @@ class AsBlockStat(BaseModel):
|
|||
Returns:
|
||||
Formatted string representation of the block.
|
||||
"""
|
||||
from ..utils import truncate_text
|
||||
|
||||
if self.block_type == "text":
|
||||
return truncate_text(self.text, max_length) if self.text else ""
|
||||
if not self.text:
|
||||
return ""
|
||||
return f"<text>{self._truncate(self.text, max_length)}</text>"
|
||||
if self.block_type == "thinking":
|
||||
if include_thinking and self.text:
|
||||
return f"<thinking>\n{truncate_text(self.text, max_length)}\n</thinking>"
|
||||
return ""
|
||||
if not include_thinking or not self.text:
|
||||
return ""
|
||||
return f"<thinking>{self._truncate(self.text, max_length)}</thinking>"
|
||||
if self.block_type in ("image", "audio", "video"):
|
||||
return f"[{self.block_type}] {self.media_url}" if self.media_url else f"[{self.block_type}]"
|
||||
if self.block_type in ("tool_use", "tool_result"):
|
||||
if self.block_type == "tool_use":
|
||||
return f" - tool_call={self.tool_name} params={truncate_text(self.tool_input, max_length)}"
|
||||
else:
|
||||
output = truncate_text(self.tool_output, max_length)
|
||||
return f" - tool_result={self.tool_name} output={output}" if output else ""
|
||||
content = self.media_url if self.media_url else ""
|
||||
return f"<{self.block_type}>{content}</{self.block_type}>"
|
||||
if self.block_type == "tool_use":
|
||||
content = f"{self.tool_name} params={self._truncate(self.tool_input, max_length)}"
|
||||
return f"<tool_use>{content}</tool_use>"
|
||||
if self.block_type == "tool_result":
|
||||
if not self.tool_output:
|
||||
return ""
|
||||
content = f"{self.tool_name} output={self._truncate(self.tool_output, max_length)}"
|
||||
return f"<tool_result>{content}</tool_result>"
|
||||
return ""
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +1,13 @@
|
|||
"""File-based Memory Module.
|
||||
"""File-based Memory Module."""
|
||||
|
||||
This module provides memory management components for CoPaw (Cooperative Paw) agents,
|
||||
including memory formatting, compaction, summarization, and file I/O operations.
|
||||
|
||||
Components:
|
||||
- ReMeInMemoryMemory: Extended InMemoryMemory with bugfixes and summary support
|
||||
- AsMsgHandler: Handles AgentScope message statistics, formatting, and context checking
|
||||
- Summarizer: Generates memory summaries using LLM
|
||||
- Compactor: Compacts memory content to reduce token usage
|
||||
- ToolResultCompactor: Truncates large tool results and saves full content to files
|
||||
- ContextChecker: Checks context size and splits messages for compaction
|
||||
"""
|
||||
|
||||
from .as_msg_handler import AsMsgHandler
|
||||
from .component.compactor import Compactor
|
||||
from .component.context_checker import ContextChecker
|
||||
from .component.summarizer import Summarizer
|
||||
from .component.tool_result_compactor import ToolResultCompactor
|
||||
from . import components
|
||||
from . import tools
|
||||
from . import utils
|
||||
from .reme_in_memory_memory import ReMeInMemoryMemory
|
||||
|
||||
__all__ = [
|
||||
"AsMsgHandler",
|
||||
"tools",
|
||||
"utils",
|
||||
"components",
|
||||
"ReMeInMemoryMemory",
|
||||
"Summarizer",
|
||||
"Compactor",
|
||||
"ContextChecker",
|
||||
"ToolResultCompactor",
|
||||
]
|
||||
|
|
|
|||
13
reme/memory/file_based/components/__init__.py
Normal file
13
reme/memory/file_based/components/__init__.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"""components"""
|
||||
|
||||
from .compactor import Compactor
|
||||
from .context_checker import ContextChecker
|
||||
from .summarizer import Summarizer
|
||||
from .tool_result_compactor import ToolResultCompactor
|
||||
|
||||
__all__ = [
|
||||
"Compactor",
|
||||
"Summarizer",
|
||||
"ContextChecker",
|
||||
"ToolResultCompactor",
|
||||
]
|
||||
|
|
@ -4,7 +4,7 @@ from agentscope.agent import ReActAgent
|
|||
from agentscope.message import Msg
|
||||
from agentscope.token import HuggingFaceTokenCounter
|
||||
|
||||
from ..as_msg_handler import AsMsgHandler
|
||||
from ..utils import AsMsgHandler
|
||||
from ....core.op import BaseOp
|
||||
from ....core.utils import get_std_logger
|
||||
|
||||
|
|
@ -32,10 +32,13 @@ class Compactor(BaseOp):
|
|||
if not messages:
|
||||
return ""
|
||||
|
||||
before_token_count = self.msg_handler.count_msgs_token(messages)
|
||||
history_formatted_str: str = self.msg_handler.format_msgs_to_str(
|
||||
messages=messages,
|
||||
memory_compact_threshold=self.memory_compact_threshold,
|
||||
)
|
||||
after_token_count = self.msg_handler.count_str_token(history_formatted_str)
|
||||
logger.info(f"Compactor before_token_count={before_token_count} after_token_count={after_token_count}")
|
||||
|
||||
if not history_formatted_str:
|
||||
logger.warning(f"No history to compact. messages={messages}")
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
from agentscope.message import Msg
|
||||
from agentscope.token import HuggingFaceTokenCounter
|
||||
|
||||
from ..as_msg_handler import AsMsgHandler
|
||||
from ..utils import AsMsgHandler
|
||||
from ....core.op import BaseOp
|
||||
from ....core.utils import get_std_logger
|
||||
|
||||
|
|
@ -87,11 +87,12 @@ class ContextChecker(BaseOp):
|
|||
memory_compact_reserve=self.memory_compact_reserve,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"ContextChecker Result: "
|
||||
f"to_compact={len(messages_to_compact)}, "
|
||||
f"to_keep={len(messages_to_keep)}, "
|
||||
f"is_valid={is_valid}",
|
||||
)
|
||||
if messages_to_compact:
|
||||
logger.info(
|
||||
f"ContextChecker Result: "
|
||||
f"to_compact={len(messages_to_compact)}, "
|
||||
f"to_keep={len(messages_to_keep)}, "
|
||||
f"is_valid={is_valid}",
|
||||
)
|
||||
|
||||
return messages_to_compact, messages_to_keep, is_valid
|
||||
|
|
@ -7,7 +7,7 @@ from agentscope.message import Msg
|
|||
from agentscope.token import HuggingFaceTokenCounter
|
||||
from agentscope.tool import Toolkit
|
||||
|
||||
from ..as_msg_handler import AsMsgHandler
|
||||
from ..utils import AsMsgHandler
|
||||
from ....core.op import BaseOp
|
||||
from ....core.utils import get_std_logger
|
||||
|
||||
|
|
@ -40,10 +40,13 @@ class Summarizer(BaseOp):
|
|||
if not messages:
|
||||
return ""
|
||||
|
||||
before_token_count = self.msg_handler.count_msgs_token(messages)
|
||||
history_formatted_str: str = self.msg_handler.format_msgs_to_str(
|
||||
messages=messages,
|
||||
memory_compact_threshold=self.memory_compact_threshold,
|
||||
)
|
||||
after_token_count = self.msg_handler.count_str_token(history_formatted_str)
|
||||
logger.info(f"Summarizer before_token_count={before_token_count} after_token_count={after_token_count}")
|
||||
|
||||
if not history_formatted_str:
|
||||
logger.warning(f"No history to summarize. messages={messages}")
|
||||
|
|
@ -5,7 +5,7 @@ from agentscope.memory import InMemoryMemory
|
|||
from agentscope.message import Msg
|
||||
from agentscope.token import HuggingFaceTokenCounter
|
||||
|
||||
from .as_msg_handler import AsMsgHandler
|
||||
from .utils import AsMsgHandler
|
||||
from ...core.utils import get_std_logger
|
||||
|
||||
logger = get_std_logger()
|
||||
|
|
|
|||
7
reme/memory/file_based/utils/__init__.py
Normal file
7
reme/memory/file_based/utils/__init__.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"""utils"""
|
||||
|
||||
from .as_msg_handler import AsMsgHandler
|
||||
|
||||
__all__ = [
|
||||
"AsMsgHandler",
|
||||
]
|
||||
|
|
@ -5,8 +5,8 @@ import json
|
|||
from agentscope.message import Msg
|
||||
from agentscope.token import HuggingFaceTokenCounter
|
||||
|
||||
from ...core.schema import AsMsgStat, AsBlockStat
|
||||
from ...core.utils import get_std_logger
|
||||
from ....core.schema import AsMsgStat, AsBlockStat
|
||||
from ....core.utils import get_std_logger
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
|
@ -111,6 +111,19 @@ class AsMsgHandler:
|
|||
metadata=message.metadata or {},
|
||||
)
|
||||
|
||||
if not isinstance(message.content, list):
|
||||
logger.warning(
|
||||
"Unexpected message.content type %s, expected str or list, returning empty stat.",
|
||||
type(message.content),
|
||||
)
|
||||
return AsMsgStat(
|
||||
name=message.name or message.role,
|
||||
role=message.role,
|
||||
content=blocks,
|
||||
timestamp=message.timestamp or "",
|
||||
metadata=message.metadata or {},
|
||||
)
|
||||
|
||||
for block in message.content:
|
||||
block_type = block.get("type", "unknown")
|
||||
|
||||
|
|
@ -155,7 +168,7 @@ class AsMsgHandler:
|
|||
|
||||
elif block_type == "tool_use":
|
||||
tool_name = block.get("name", "")
|
||||
tool_input = block.get("raw_input", "")
|
||||
tool_input = block.get("input", "")
|
||||
try:
|
||||
input_str = json.dumps(tool_input, ensure_ascii=False)
|
||||
except (TypeError, ValueError):
|
||||
|
|
@ -227,7 +240,8 @@ class AsMsgHandler:
|
|||
formatted_content = stat.format(include_thinking=include_thinking)
|
||||
content_token_count = self.count_str_token(formatted_content)
|
||||
|
||||
if total_token_count + content_token_count > memory_compact_threshold:
|
||||
is_latest = i == len(messages) - 1
|
||||
if not is_latest and total_token_count + content_token_count > memory_compact_threshold:
|
||||
logger.info(
|
||||
"Skipping older messages: adding %d tokens would exceed threshold %d (current: %d)",
|
||||
content_token_count,
|
||||
|
|
@ -236,6 +250,13 @@ class AsMsgHandler:
|
|||
)
|
||||
break
|
||||
|
||||
if is_latest and content_token_count > memory_compact_threshold:
|
||||
logger.warning(
|
||||
"Latest message alone (%d tokens) exceeds threshold %d, including it anyway.",
|
||||
content_token_count,
|
||||
memory_compact_threshold,
|
||||
)
|
||||
|
||||
formatted_parts.append(formatted_content)
|
||||
total_token_count += content_token_count
|
||||
|
||||
|
|
@ -324,6 +345,10 @@ class AsMsgHandler:
|
|||
accumulated_tokens = 0
|
||||
|
||||
for i in range(len(msg_stats) - 1, -1, -1):
|
||||
# Skip messages already added as tool_use dependencies to avoid double-counting tokens
|
||||
if i in keep_indices:
|
||||
continue
|
||||
|
||||
msg, stat = msg_stats[i]
|
||||
|
||||
# Check if adding this message would exceed reserve limit
|
||||
|
|
@ -26,16 +26,15 @@ from agentscope.tool import Toolkit, ToolResponse
|
|||
from .config import ReMeConfigParser
|
||||
from .core import Application
|
||||
from .core.utils import get_hf_token_counter, get_std_logger
|
||||
from .memory.file_based import (
|
||||
from .memory.file_based import ReMeInMemoryMemory
|
||||
from .memory.file_based.components import (
|
||||
Compactor,
|
||||
ContextChecker,
|
||||
Summarizer,
|
||||
ToolResultCompactor,
|
||||
ReMeInMemoryMemory,
|
||||
AsMsgHandler,
|
||||
)
|
||||
from .memory.file_based import MemorySearch
|
||||
from .memory.file_based.tools import FileIO
|
||||
from .memory.file_based.tools import FileIO, MemorySearch
|
||||
from .memory.file_based.utils import AsMsgHandler
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
|
@ -487,7 +486,7 @@ class ReMeLight(Application):
|
|||
- compact_ratio: Compaction threshold ratio
|
||||
|
||||
Note:
|
||||
- Completed/failed/cancelled tasks are cleaned up before adding new ones
|
||||
- Completed/failed/canceled tasks are cleaned up before adding new ones
|
||||
- Task results and errors are logged automatically
|
||||
- Use await_summary_tasks() to wait for all pending tasks to complete
|
||||
"""
|
||||
|
|
@ -561,7 +560,7 @@ class ReMeLight(Application):
|
|||
|
||||
Returns:
|
||||
tuple[list[Msg], str]: A tuple containing:
|
||||
- list[Msg]: Messages to keep in context (may be reduced)
|
||||
- list[Msg]: Messages to keep in context (maybe reduced)
|
||||
- str: Updated compressed summary incorporating compacted messages
|
||||
|
||||
Note:
|
||||
|
|
@ -584,10 +583,11 @@ class ReMeLight(Application):
|
|||
compact_msgs = messages[:-tool_result_compact_keep_n]
|
||||
await self.compact_tool_result(compact_msgs)
|
||||
|
||||
messages_to_compact, messages_to_keep, is_valid = msg_handler.context_check(
|
||||
messages_to_compact, messages_to_keep, is_valid = await self.check_context(
|
||||
messages=messages,
|
||||
memory_compact_threshold=left_compact_threshold,
|
||||
memory_compact_reserve=memory_compact_reserve,
|
||||
token_counter=token_counter,
|
||||
)
|
||||
|
||||
if not messages_to_compact:
|
||||
|
|
@ -626,7 +626,7 @@ class ReMeLight(Application):
|
|||
Wait for all background summary tasks to complete and collect results.
|
||||
|
||||
Blocks until all pending summary tasks in the task list have completed,
|
||||
cancelled, or failed. Collects status information from each task and
|
||||
canceled, or failed. Collects status information from each task and
|
||||
clears the task list after processing.
|
||||
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
import asyncio
|
||||
|
||||
from agentscope.message import Msg
|
||||
|
||||
from test_utils import (
|
||||
get_dash_chat_model,
|
||||
get_formatter,
|
||||
|
|
@ -11,8 +10,7 @@ from test_utils import (
|
|||
)
|
||||
|
||||
from reme.core.utils import get_std_logger
|
||||
from reme.memory.file_based import Compactor
|
||||
|
||||
from reme.memory.file_based.components import Compactor
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
"""Tests for AsMsgHandler.context_check method."""
|
||||
|
||||
from agentscope.message import Msg
|
||||
|
||||
from test_utils import get_token_counter
|
||||
|
||||
from reme.core.utils import get_std_logger
|
||||
from reme.memory.file_based.as_msg_handler import AsMsgHandler
|
||||
from reme.memory.file_based.utils import AsMsgHandler
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
import sys
|
||||
|
||||
from agentscope.message import Msg
|
||||
|
||||
from test_utils import get_token_counter
|
||||
|
||||
from reme.core.utils import get_std_logger
|
||||
from reme.memory.file_based.as_msg_handler import AsMsgHandler
|
||||
from reme.memory.file_based.utils import AsMsgHandler
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@ from pathlib import Path
|
|||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.tool import Toolkit
|
||||
|
||||
from test_utils import (
|
||||
get_dash_chat_model,
|
||||
get_formatter,
|
||||
get_token_counter,
|
||||
)
|
||||
from reme.core.utils import get_std_logger
|
||||
from reme.memory.file_based import Summarizer
|
||||
from reme.memory.file_based.components import Summarizer
|
||||
from reme.memory.file_based.tools import FileIO
|
||||
|
||||
|
||||
logger = get_std_logger()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ from datetime import datetime, timedelta
|
|||
from pathlib import Path
|
||||
|
||||
from agentscope.message import Msg
|
||||
from reme.memory.file_based import ToolResultCompactor
|
||||
|
||||
from reme.core.utils import is_truncated
|
||||
from reme.memory.file_based.components import ToolResultCompactor
|
||||
|
||||
|
||||
def create_tool_result_msg(output: str | list, tool_name: str = "test_tool") -> Msg:
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import tempfile
|
|||
|
||||
import pytest
|
||||
|
||||
from reme.memory.file_based.tools.shell import Shell
|
||||
from reme.memory.file_based.tools.file_io import FileIO
|
||||
from reme.memory.file_based.tools.shell import Shell
|
||||
from reme.memory.file_based.tools.utils import DEFAULT_MAX_LINES, DEFAULT_MAX_BYTES
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import os
|
|||
|
||||
from agentscope.message import Msg, ThinkingBlock, TextBlock, ToolUseBlock, ToolResultBlock
|
||||
|
||||
from reme.memory.file_based import AsMsgHandler
|
||||
from reme.memory.file_based.utils import AsMsgHandler
|
||||
|
||||
|
||||
def get_token_counter():
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue