mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-10-09 03:20:54 +00:00
feat(cli): enable vector search and improve chat history management
This commit is contained in:
parent
cdda48aab4
commit
a8604af78f
7 changed files with 85 additions and 31 deletions
19
docs/make_mp4.md
Normal file
19
docs/make_mp4.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
```shell
|
||||
ffmpeg -i /Users/yuli/Desktop/remecli_en.mov \
|
||||
-vf "scale=-2:1080,setpts=0.333*PTS" \
|
||||
-c:v libx264 \
|
||||
-crf 28 \
|
||||
-preset fast \
|
||||
-c:a aac \
|
||||
-b:a 96k \
|
||||
/Users/yuli/Desktop/remecli_en_1080p_3x.mp4
|
||||
|
||||
ffmpeg -i /Users/yuli/Desktop/remecli_zh.mov \
|
||||
-vf "scale=-2:1080,setpts=0.333*PTS" \
|
||||
-c:v libx264 \
|
||||
-crf 28 \
|
||||
-preset fast \
|
||||
-c:a aac \
|
||||
-b:a 96k \
|
||||
/Users/yuli/Desktop/remecli_zh_1080p_3x.mp4
|
||||
```
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
"""FsCli system prompt"""
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ from loguru import logger
|
|||
from ...core.enumeration import Role, ChunkEnum
|
||||
from ...core.op import BaseReactStream
|
||||
from ...core.schema import Message, StreamChunk
|
||||
from ...core.utils import format_messages
|
||||
from ...tool.fs import BashTool, LsTool, ReadTool, WriteTool, EditTool
|
||||
|
||||
|
||||
|
|
@ -31,18 +33,23 @@ class FsCli(BaseReactStream):
|
|||
|
||||
self.messages: list[Message] = []
|
||||
self.previous_summary: str = ""
|
||||
self.summary_tasks: list[asyncio.Task] = []
|
||||
|
||||
async def reset(self) -> str:
|
||||
"""Reset conversation history using summary.
|
||||
def add_summary_task(self, messages: list[Message]):
|
||||
"""Add summary task to queue."""
|
||||
remaining_tasks = []
|
||||
for task in self.summary_tasks:
|
||||
if task.done():
|
||||
exc = task.exception()
|
||||
if exc is not None:
|
||||
logger.exception(f"Summary task failed: {exc}")
|
||||
else:
|
||||
result = task.result()
|
||||
logger.info(f"Summary task completed: {result}")
|
||||
else:
|
||||
remaining_tasks.append(task)
|
||||
self.summary_tasks = remaining_tasks
|
||||
|
||||
Summarizes current messages to memory files and clears history.
|
||||
"""
|
||||
if not self.messages:
|
||||
self.messages.clear()
|
||||
self.previous_summary = ""
|
||||
return "No history to reset."
|
||||
|
||||
# Import required modules
|
||||
from ..fs import FsSummarizer
|
||||
|
||||
# Summarize current conversation and save to memory files
|
||||
|
|
@ -59,14 +66,30 @@ class FsCli(BaseReactStream):
|
|||
language=self.language,
|
||||
)
|
||||
|
||||
result = await summarizer.call(
|
||||
messages=self.messages,
|
||||
date=current_date,
|
||||
service_context=self.service_context,
|
||||
summary_task = asyncio.create_task(
|
||||
summarizer.call(
|
||||
messages=messages,
|
||||
date=current_date,
|
||||
service_context=self.service_context,
|
||||
),
|
||||
)
|
||||
self.summary_tasks.append(summary_task)
|
||||
|
||||
async def new(self) -> str:
|
||||
"""Reset conversation history using summary.
|
||||
|
||||
Summarizes current messages to memory files and clears history.
|
||||
"""
|
||||
if not self.messages:
|
||||
self.messages.clear()
|
||||
self.previous_summary = ""
|
||||
return "No history to reset."
|
||||
|
||||
self.add_summary_task(self.messages)
|
||||
|
||||
self.messages.clear()
|
||||
self.previous_summary = ""
|
||||
return f"History saved to memory files and reset. Result: {result.get('answer', 'Done')}"
|
||||
return "History saved to memory files and reset."
|
||||
|
||||
async def context_check(self) -> dict:
|
||||
"""Check if messages exceed token limits."""
|
||||
|
|
@ -104,20 +127,16 @@ class FsCli(BaseReactStream):
|
|||
tokens_before = cut_result.get("token_count", 0)
|
||||
|
||||
if force_compact:
|
||||
# Force compact: summarize all messages, leave only summary
|
||||
messages_to_summarize = self.messages
|
||||
turn_prefix_messages = []
|
||||
left_messages = []
|
||||
elif not cut_result.get("needs_compaction", False):
|
||||
# No compaction needed
|
||||
return "History is within token limits, no compaction needed."
|
||||
else:
|
||||
# Normal compaction: use cut point result
|
||||
messages_to_summarize = cut_result.get("messages_to_summarize", [])
|
||||
turn_prefix_messages = cut_result.get("turn_prefix_messages", [])
|
||||
left_messages = cut_result.get("left_messages", [])
|
||||
|
||||
# Step 2: Generate summary via Compactor
|
||||
compactor = FsCompactor(language=self.language)
|
||||
summary_content = await compactor.call(
|
||||
messages_to_summarize=messages_to_summarize,
|
||||
|
|
@ -126,14 +145,22 @@ class FsCli(BaseReactStream):
|
|||
service_context=self.service_context,
|
||||
)
|
||||
|
||||
# Step 3: Call reset_history to save and clear
|
||||
reset_result = await self.reset()
|
||||
self.add_summary_task(messages=messages_to_summarize)
|
||||
|
||||
# Step 4: Assemble final messages
|
||||
self.messages = left_messages
|
||||
self.previous_summary = summary_content
|
||||
|
||||
return f"History compacted from {tokens_before} tokens. {reset_result}"
|
||||
return f"History compacted from {tokens_before} tokens."
|
||||
|
||||
def format_history(self) -> str:
|
||||
"""Format history messages."""
|
||||
return format_messages(
|
||||
messages=self.messages,
|
||||
add_index=False,
|
||||
add_reasoning=False,
|
||||
strip_markdown_headers=False,
|
||||
)
|
||||
|
||||
async def build_messages(self) -> list[Message]:
|
||||
"""Build system prompt message."""
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from ...core.utils import format_messages
|
|||
class FsSummarizer(BaseReact):
|
||||
"""Retrieve personal memories through vector search and history reading."""
|
||||
|
||||
def __init__(self, working_dir: str, memory_dir: str = "memory", version: str = "default", **kwargs):
|
||||
def __init__(self, working_dir: str, memory_dir: str = "memory", version: str = "v1", **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.working_dir: str = working_dir
|
||||
self.memory_dir: str = memory_dir
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ memory_stores:
|
|||
store_name: reme
|
||||
embedding_model: default
|
||||
fts_enabled: true
|
||||
vector_enabled: false
|
||||
vector_enabled: true
|
||||
|
||||
file_watchers:
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -81,4 +81,5 @@ def print_logo(service_config: "ServiceConfig"):
|
|||
expand=False,
|
||||
)
|
||||
|
||||
Console().print(Group("\n", panel, "\n"), justify="center")
|
||||
# use justify="center" to adjust position
|
||||
Console().print(Group("\n", panel, "\n"))
|
||||
|
|
|
|||
|
|
@ -39,8 +39,10 @@ class ReMeCli(ReMeFs):
|
|||
"/help": "Show help.",
|
||||
}
|
||||
|
||||
async def chat_with_remy(self, tool_result_max_size: int = 100, language: str = "zh", **kwargs):
|
||||
async def chat_with_remy(self, tool_result_max_size: int = 100, **kwargs):
|
||||
"""Interactive CLI chat with Remy using simple streaming output."""
|
||||
language = self.service_config.language
|
||||
print(f"ReMe language={language}")
|
||||
tools: list[BaseTool] = [
|
||||
FsMemorySearch(vector_weight=self.vector_weight, candidate_multiplier=self.candidate_multiplier),
|
||||
BashTool(cwd=self.working_dir),
|
||||
|
|
@ -53,10 +55,10 @@ class ReMeCli(ReMeFs):
|
|||
tavily_api_key: str = os.getenv("TAVILY_API_KEY", "")
|
||||
dashscope_api_key: str = os.getenv("DASHSCOPE_API_KEY", "")
|
||||
if tavily_api_key:
|
||||
tools.append(TavilySearch(name="web_search"))
|
||||
tools.append(TavilySearch(name="web_search", language=language))
|
||||
print("find tavily_api_key, append Tavily search tool")
|
||||
elif dashscope_api_key:
|
||||
tools.append(DashscopeSearch(name="web_search"))
|
||||
tools.append(DashscopeSearch(name="web_search", language=language))
|
||||
print("find dashscope_api_key, append Dashscope search tool")
|
||||
else:
|
||||
print("No Tavily or Dashscope API key found, skip Tavily and Dashscope search tool")
|
||||
|
|
@ -108,7 +110,7 @@ class ReMeCli(ReMeFs):
|
|||
break
|
||||
|
||||
if user_input == "/new":
|
||||
result = await fs_cli.reset()
|
||||
result = await fs_cli.new()
|
||||
print(f"{result}\nConversation reset\n")
|
||||
continue
|
||||
|
||||
|
|
@ -117,6 +119,11 @@ class ReMeCli(ReMeFs):
|
|||
print(f"{result}\nHistory compacted.\n")
|
||||
continue
|
||||
|
||||
if user_input == "/history":
|
||||
result = fs_cli.format_history()
|
||||
print(f"Formated History:\n{result}\n")
|
||||
continue
|
||||
|
||||
if user_input == "/clear":
|
||||
fs_cli.messages.clear()
|
||||
print("History cleared.\n")
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ role_prompt: |
|
|||
{query}
|
||||
|
||||
# task
|
||||
Extract the original content related to the user's query directly from the context, maintain accuracy, and avoid excessive processing.
|
||||
Return all the original search results directly without processing.
|
||||
|
||||
role_prompt_zh: |
|
||||
# 用户问题
|
||||
{query}
|
||||
|
||||
# task
|
||||
直接从上下文中提取与用户问题相关的原始内容,保持准确性,避免过度处理。
|
||||
直接返回所有的原始搜索结果,不要处理
|
||||
Loading…
Add table
Reference in a new issue