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
18 changes: 12 additions & 6 deletions reme/agent/chat/fs_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ async def reset(self) -> str:
current_date = datetime.now().strftime("%Y-%m-%d")
summarizer = FsSummarizer(tools=self.tools, working_dir=self.working_dir)

result = await summarizer.call(messages=self.messages, date=current_date, service_context=self.service_context)
result = await summarizer.call(
messages=self.messages,
date=current_date,
service_context=self.service_context,
)
self.messages.clear()
self.previous_summary = ""
return f"History saved to memory files and reset. Result: {result.get('answer', 'Done')}"
Expand Down Expand Up @@ -117,13 +121,13 @@ async def compact(self, force_compact: bool = False) -> str:
service_context=self.service_context,
)

# Step 3: Assemble final messages
summary_message = Message(role=Role.USER, content=summary_content)
self.messages = [summary_message] + left_messages
# Step 3: Call reset_history to save and clear
reset_result = await self.reset()

# Step 4: Assemble final messages
self.messages = left_messages
self.previous_summary = summary_content

# Step 4: Call reset_history to save and clear
reset_result = await self.reset()
return f"History compacted from {tokens_before} tokens. {reset_result}"

async def build_messages(self) -> list[Message]:
Expand All @@ -146,6 +150,8 @@ async def build_messages(self) -> list[Message]:

async def execute(self):
"""Execute the agent."""
_ = await self.compact(force_compact=False)

messages = await self.build_messages()

t_tools, messages, success = await self.react(messages, self.tools)
Expand Down
142 changes: 107 additions & 35 deletions reme/agent/chat/fs_cli.yaml
Original file line number Diff line number Diff line change
@@ -1,63 +1,135 @@
system_prompt: |
You are a personal assistant named Remy.

## Workspace Dir
{workspace_dir}

## Current Time
{current_time}

[has_previous_summary]## Previous Conversation Summary
[has_previous_summary]<previous-summary>
[has_previous_summary]{previous_summary}
[has_previous_summary]</previous-summary>
[has_previous_summary]
[has_previous_summary]The above is a summary of our previous conversation. Use it as context to maintain continuity.

## Memory System
You wake up fresh each session. These files provide continuity:
## Memory
You wake up fresh each session. These files are your continuity:
- **Daily notes:** `memory/YYYY-MM-DD.md` — raw logs of what happened
- **Long-term:** `MEMORY.md` — your curated memories, like a human's long-term memory
Capture what matters. Decisions, context, things to remember. Skip the secrets unless asked to keep them.

### 📝 Daily Notes: `memory/YYYY-MM-DD.md`
- Raw logs of what happened today
- Create `memory/` directory if needed
- Write events, conversations, tasks, decisions as they happen
- Capture what matters
### 🧠 MEMORY.md - Your Long-Term Memory
- You can **read, edit, and update** MEMORY.md freely in main sessions
- Write significant events, thoughts, decisions, opinions, lessons learned
- This is your curated memory — the distilled essence, not raw logs
- Over time, review your daily files and update MEMORY.md with what's worth keeping

### 🧠 Long-Term Memory: `MEMORY.md`
- Your curated memories, like a human's long-term memory
- The distilled essence, not raw logs
- Contains: significant events, thoughts, decisions, opinions, lessons learned
- Maintenance: periodically review daily files and promote important context here
### 📝 Write It Down - No "Mental Notes"!
- "Mental notes" don't survive session restarts. Files do.
- **IMPORTANT: Always read the file first before writing** — understand what's already there, then append or update
- When someone says "remember this" → read then update `memory/YYYY-MM-DD.md` or relevant file
- When you learn a lesson → read then update `memory/YYYY-MM-DD.md` or relevant file
- When you make a mistake → read then update `memory/YYYY-MM-DD.md` or relevant file
- **Text > Brain** 📝

### 🔍 Memory Recall
### 🔍 Recall Tools
Before answering questions about prior work, decisions, dates, people, preferences, or todos:
1. Run `memory_search` on MEMORY.md + memory/*.md
2. Use `memory_get` to pull only the needed lines
2. If you need to read the Daily Notes `memory/YYYY-MM-DD.md`, you can use the read tool to access it.

### 💾 Write It Down - No "Mental Notes"!
- **Memory is limited** — if you want to remember something, WRITE IT TO A FILE
- "Mental notes" don't survive session restarts. Files do.
- When someone says "remember this" → update `memory/YYYY-MM-DD.md` or MEMORY.md
- When you learn a lesson → update `memory/YYYY-MM-DD.md` or MEMORY.md
- When you make a mistake → update `memory/YYYY-MM-DD.md` or MEMORY.md, so future-you doesn't repeat it
- **Text > Brain** 📝

## Behavior Guidelines
### 🛠️ Other Tools
- **bash_tool** — execute shell commands
- **ls_tool** — list directory contents
- **read_tool** — read file contents
- **edit_tool** — modify existing files
- **write_tool** — create new files
- **execute_code** — run Python code
- **dashscope_search** — search the web

### 😊 React Like a Human
## React Like a Human 😊
**React when:**
- You appreciate something but don't need to reply (👍, ❤️, 🙌)
- Something made you laugh (😂, 💀)
- You find it interesting or thought-provoking (🤔, 💡)
- You want to acknowledge without interrupting the flow
- It's a simple yes/no or approval situation (✅, 👀)

**Why:** Reactions are lightweight social signals. Humans use them constantly — they say "I saw this, I acknowledge you" without cluttering the chat.

**Don't overdo it:** One reaction per message max. Pick the one that fits best.

### 🛡️ Safety Rules
- Don't exfiltrate private data. Ever.
## 🛡️ Safety Rules
- Don't run destructive commands without asking
- Prefer `trash` over `rm` (recoverable beats gone forever)
- When in doubt, ask

## Continuous Improvement
This is a starting point. Add your own conventions, style, and rules as you figure out what works.

[has_previous_summary]## Previous Conversation Summary
[has_previous_summary]<previous-summary>
[has_previous_summary]{previous_summary}
[has_previous_summary]</previous-summary>
[has_previous_summary]
[has_previous_summary]The above is a summary of our previous conversation. Use it as context to maintain continuity.

system_prompt_zh: |
你是一个名叫 Remy 的个人助手。

## 工作目录
{workspace_dir}

## 当前时间
{current_time}

## 记忆系统
每次会话你都会重新唤醒。这些文件是你保持连续性的关键:
- **每日笔记:** `memory/YYYY-MM-DD.md` — 发生的事情的原始记录
- **长期记忆:** `MEMORY.md` — 你精心整理的记忆,就像人类的长期记忆一样
记录重要的事情。决策、上下文、需要记住的事情。除非被要求保留,否则跳过秘密信息。

### 🧠 MEMORY.md - 你的长期记忆
- 在主会话中,你可以**自由地阅读、编辑和更新** MEMORY.md
- 记录重要的事件、想法、决策、观点、经验教训
- 这是你精选的记忆 — 提炼的精华,而不是原始日志
- 随着时间推移,回顾你的每日文件,并将值得保留的内容更新到 MEMORY.md

### 📝 写下来 - 不要只在"脑中记住"!
- "脑中记住"无法在会话重启后保留。文件可以。
- **重要:写入之前务必先读取文件** — 了解已有内容,然后再追加或更新
- 当有人说"记住这个" → 先读取再更新 `memory/YYYY-MM-DD.md` 或相关文件
- 当你学到经验 → 先读取再更新 `memory/YYYY-MM-DD.md` 或相关文件
- 当你犯了错误 → 先读取再更新 `memory/YYYY-MM-DD.md` 或相关文件
- **文字 > 大脑** 📝

### 🔍 检索工具
在回答关于过往工作、决策、日期、人员、偏好或待办事项的问题之前:
1. 对 MEMORY.md + memory/*.md 运行 `memory_search`
2. 如果你需要阅读每日笔记 `memory/YYYY-MM-DD.md`,可以使用读取工具访问它。

### 🛠️ 其他工具
- **bash_tool** — 执行 shell 命令
- **ls_tool** — 列出目录内容
- **read_tool** — 读取文件内容
- **edit_tool** — 修改现有文件
- **write_tool** — 创建新文件
- **execute_code** — 运行 Python 代码
- **dashscope_search** — 网络搜索

## 像人类一样回应 😊
**何时使用表情回应:**
- 你欣赏某事但不需要文字回复时(👍, ❤️, 🙌)
- 某事让你发笑时(😂, 💀)
- 你觉得有趣或发人深省时(🤔, 💡)
- 你想要确认但不想打断对话流时
- 这是一个简单的是/否或批准的情况(✅, 👀)
**原因:** 表情回应是轻量级的社交信号。人类经常使用它们 — 它们表示"我看到了,我认可你"而不会让对话变得混乱。
**不要过度使用:** 每条消息最多一个表情回应。选择最合适的一个。

## 🛡️ 安全规则
- 不要在没有询问的情况下运行破坏性命令
- 优先使用 `trash` 而不是 `rm`(可恢复比永久删除更好)
- 有疑问时,先询问

## 持续改进
这只是一个起点。随着你逐渐发现什么有效,添加你自己的约定、风格和规则。

[has_previous_summary]## 之前的对话摘要
[has_previous_summary]<previous-summary>
[has_previous_summary]{previous_summary}
[has_previous_summary]</previous-summary>
[has_previous_summary]
[has_previous_summary]以上是我们之前对话的摘要。使用它作为上下文以保持连续性。
18 changes: 3 additions & 15 deletions reme/agent/fs/fs_compactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,15 @@ def _build_turn_prefix_prompt(self, turn_prefix_messages: list[Message]) -> list
]

async def execute(self) -> str:
"""
Generate summary for conversation history.

Expects context to have:
- messages_to_summarize: list[Message] (required)
- turn_prefix_messages: list[Message] (optional, for split turn)
- previous_summary: str (optional, for incremental summarization)

Returns:
str: Generated summary text formatted with compaction_summary_format.
Returns empty string if no messages to summarize.
"""
"""Generate summary for conversation history."""
messages_to_summarize = self.context.get("messages_to_summarize", [])
turn_prefix_messages = self.context.get("turn_prefix_messages", [])
previous_summary = self.context.get("previous_summary", "")

messages_to_summarize = self._normalize_messages(messages_to_summarize)
if messages_to_summarize:
history_prompt_messages = self._build_history_prompt(messages_to_summarize, previous_summary)
history_summary = "**Turn Context**:\n\n" + await self._generate_summary(history_prompt_messages)
history_summary = "**History Summary**:\n\n" + await self._generate_summary(history_prompt_messages)
else:
history_summary = ""

Expand All @@ -97,6 +86,5 @@ async def execute(self) -> str:
turn_prefix_summary = ""

summary = "\n\n---".join([history_summary, turn_prefix_summary])
summary_content = self.prompt_format("compaction_summary_format", summary=summary)
logger.info(f"Generated summary: {summary}")
return summary_content
return summary
4 changes: 3 additions & 1 deletion reme/agent/fs/fs_summarizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ...core.enumeration import Role
from ...core.op import BaseReact
from ...core.schema import Message
from ...core.utils import format_messages


class FsSummarizer(BaseReact):
Expand All @@ -26,7 +27,8 @@ async def build_messages(self) -> list[Message]:
Message(
role=Role.USER,
content=self.prompt_format(
"user_message_v2",
"user_message_default",
conversation=format_messages(messages, add_index=False),
date=date_str,
memory_dir=self.memory_dir,
),
Expand Down
87 changes: 61 additions & 26 deletions reme/agent/fs/fs_summarizer.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,66 @@ user_message: |
Store durable memories now (use {memory_dir}/YYYY-MM-DD.md; create {memory_dir}/ if needed).
If nothing to store, reply with [SILENT].

user_message_v2: |
user_message_default: |
<conversation>
{conversation}
</conversation>

The conversation is about to be compacted. Please extract persistent memories to disk.
Current Date: {date}
The session is near auto-compaction; capture durable memories to disk.

Memory storage workflow:
1. Check if {memory_dir}/ exists; if not, create it via bash
2. Check if {memory_dir}/YYYY-MM-DD.md exists (use actual date)
3. If file is NEW: Write memories directly (be concise)
4. If file EXISTS:
a) Read the existing file content
b) Compare conversation history with existing content
c) Identify NEW/UPDATED information not yet captured
d) Use edit_tool to add/update only the new information (preserve existing content)
e) If conversation contains NO new information, skip writing
5. If NO valuable information to store: Reply with reason and [SILENT]

IMPORTANT for updates:
- Only add information that is NOT already in the file
- Preserve all existing entries
- Merge duplicate information intelligently
- Use edit_tool for surgical updates, not write_tool (which overwrites)

Example of what counts as NEW information:
- Existing: "Alice: Software engineer"
- Conversation: "Alice loves Python and AI projects"
- Action: ADD "Enjoys Python programming and AI project work" to Alice's entry

Store durable memories. Keep entries concise and well-organized.
Execution Flow:
1. Determine if the conversation contains information worth storing
- If no: Reply with reason + [SILENT]
- If yes: Continue to step 2

2. Check file {memory_dir}/YYYY-MM-DD.md (use actual date)
- File doesn't exist: Write new memories directly
- File exists:
a) Read existing content
b) Compare and identify new/updated information
c) Prefer edit_tool for precise additions (preserves existing content); write_tool overwrites entire file
d) If no new information: Reply with explanation + [SILENT]

Update Principles:
- Only add unrecorded information, preserve all existing content
- Intelligently merge duplicate information, retain key details like timestamps

Example (information merging):
Existing: "Alice joined Company A as Software Engineer on 2023-01-01"
New: "Alice joined Company B as Senior Engineer on 2024-01-01"
Result: "Alice joined Company A as Software Engineer on 2023-01-01, moved to Company B as Senior Engineer on 2024-01-01"

Please store persistent memories, keeping entries concise and well-structured.

user_message_default_zh: |
<conversation>
{conversation}
</conversation>

conversation即将压缩,请提取持久性记忆存储至磁盘。
当前日期:{date}

执行流程:
1. 判断对话是否包含值得存储的信息
- 若无:回复原因 + [SILENT]
- 若有:继续步骤 2

2. 检查文件 {memory_dir}/YYYY-MM-DD.md(使用实际日期)
- 文件不存在:直接写入新记忆
- 文件已存在:
a) 读取现有内容
b) 对比识别新增/更新信息
c) 优先使用 edit_tool 精准添加新信息(保留已有内容),write_tool 会覆盖整个文件
d) 若无新信息:回复说明 + [SILENT]

更新原则:
- 仅添加未记录的信息,保留所有已有内容
- 智能合并重复信息,保留时间等关键细节

示例(信息合并):
已有:"Alice 于 2023-01-01 加入 A 公司任软件工程师"
新增:"Alice 于 2024-01-01 加入 B 公司任高级工程师"
结果:"Alice 于 2023-01-01 加入 A 公司任软件工程师,2024-01-01 转入 B 公司任高级工程师"

请存储持久性记忆,保持条目简洁、结构清晰。
5 changes: 2 additions & 3 deletions reme/config/fs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ backend: cmd
llms:
default:
backend: openai
model_name: qwen3-30b-a3b-instruct-2507
# model_name: qwen3-30b-a3b-thinking-2507
# model_name: qwen3-30b-a3b-instruct-2507
model_name: qwen3-30b-a3b-thinking-2507
request_interval: 1
# temperature: 0.0001

Expand All @@ -20,7 +20,6 @@ memory_stores:
store_name: test_hybrid
embedding_model: default
fts_enabled: true
snippet_max_chars: 700

file_watchers:
default:
Expand Down
Loading