Fix /restore path and native log compatibility
This commit is contained in:
@@ -1,8 +1,19 @@
|
|||||||
import asyncio, glob, os, queue as Q, re, socket, sys, time
|
import ast, asyncio, glob, json, os, queue as Q, re, socket, sys, time
|
||||||
|
|
||||||
HELP_TEXT = "📖 命令列表:\n/help - 显示帮助\n/status - 查看状态\n/stop - 停止当前任务\n/new - 清空当前上下文\n/restore - 恢复上次对话历史\n/llm [n] - 查看或切换模型"
|
HELP_TEXT = "📖 命令列表:\n/help - 显示帮助\n/status - 查看状态\n/stop - 停止当前任务\n/new - 清空当前上下文\n/restore - 恢复上次对话历史\n/llm [n] - 查看或切换模型"
|
||||||
FILE_HINT = "If you need to show files to user, use [FILE:filepath] in your response."
|
FILE_HINT = "If you need to show files to user, use [FILE:filepath] in your response."
|
||||||
TAG_PATS = [r"<" + t + r">.*?</" + t + r">" for t in ("thinking", "summary", "tool_use", "file_content")]
|
TAG_PATS = [r"<" + t + r">.*?</" + t + r">" for t in ("thinking", "summary", "tool_use", "file_content")]
|
||||||
|
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
RESTORE_GLOBS = (
|
||||||
|
os.path.join(PROJECT_ROOT, "temp", "model_responses", "model_responses_*.txt"),
|
||||||
|
os.path.join(PROJECT_ROOT, "temp", "model_responses_*.txt"),
|
||||||
|
)
|
||||||
|
RESTORE_BLOCK_RE = re.compile(
|
||||||
|
r"^=== (Prompt|Response) ===.*?\n(.*?)(?=^=== (?:Prompt|Response) ===|\Z)",
|
||||||
|
re.DOTALL | re.MULTILINE,
|
||||||
|
)
|
||||||
|
HISTORY_RE = re.compile(r"<history>\s*(.*?)\s*</history>", re.DOTALL)
|
||||||
|
SUMMARY_RE = re.compile(r"<summary>\s*(.*?)\s*</summary>", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
def clean_reply(text):
|
def clean_reply(text):
|
||||||
@@ -30,13 +41,14 @@ def split_text(text, limit):
|
|||||||
return parts + ([text] if text else []) or ["..."]
|
return parts + ([text] if text else []) or ["..."]
|
||||||
|
|
||||||
|
|
||||||
def format_restore():
|
def _restore_log_files():
|
||||||
files = glob.glob("./temp/model_responses_*.txt")
|
files = []
|
||||||
if not files:
|
for pattern in RESTORE_GLOBS:
|
||||||
return None, "❌ 没有找到历史记录"
|
files.extend(glob.glob(pattern))
|
||||||
latest = max(files, key=os.path.getmtime)
|
return sorted(set(files))
|
||||||
with open(latest, "r", encoding="utf-8") as f:
|
|
||||||
content = f.read()
|
|
||||||
|
def _restore_text_pairs(content):
|
||||||
users = re.findall(r"=== USER ===\n(.+?)(?==== |$)", content, re.DOTALL)
|
users = re.findall(r"=== USER ===\n(.+?)(?==== |$)", content, re.DOTALL)
|
||||||
resps = re.findall(r"=== Response ===.*?\n(.+?)(?==== Prompt|$)", content, re.DOTALL)
|
resps = re.findall(r"=== Response ===.*?\n(.+?)(?==== Prompt|$)", content, re.DOTALL)
|
||||||
restored = []
|
restored = []
|
||||||
@@ -44,9 +56,114 @@ def format_restore():
|
|||||||
u, r = u.strip(), r.strip()[:500]
|
u, r = u.strip(), r.strip()[:500]
|
||||||
if u and r:
|
if u and r:
|
||||||
restored.extend([f"[USER]: {u}", f"[Agent] {r}"])
|
restored.extend([f"[USER]: {u}", f"[Agent] {r}"])
|
||||||
|
return restored
|
||||||
|
|
||||||
|
|
||||||
|
def _native_prompt_obj(prompt_body):
|
||||||
|
try:
|
||||||
|
prompt = json.loads(prompt_body)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
if not isinstance(prompt, dict) or prompt.get("role") != "user":
|
||||||
|
return None
|
||||||
|
if not isinstance(prompt.get("content"), list):
|
||||||
|
return None
|
||||||
|
return prompt
|
||||||
|
|
||||||
|
|
||||||
|
def _native_prompt_text(prompt):
|
||||||
|
texts = []
|
||||||
|
for block in prompt.get("content", []):
|
||||||
|
if isinstance(block, dict) and block.get("type") == "text":
|
||||||
|
text = block.get("text", "")
|
||||||
|
if isinstance(text, str) and text.strip():
|
||||||
|
texts.append(text)
|
||||||
|
return "\n".join(texts).strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _native_history_lines(prompt_text):
|
||||||
|
match = HISTORY_RE.search(prompt_text or "")
|
||||||
|
if not match:
|
||||||
|
return []
|
||||||
|
restored = []
|
||||||
|
for line in match.group(1).splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("[USER]: ") or line.startswith("[Agent] "):
|
||||||
|
restored.append(line)
|
||||||
|
return restored
|
||||||
|
|
||||||
|
|
||||||
|
def _native_first_user_line(prompt_text):
|
||||||
|
text = (prompt_text or "").strip()
|
||||||
|
if not text or "<history>" in text or text.startswith("### [WORKING MEMORY]"):
|
||||||
|
return ""
|
||||||
|
if text.startswith(FILE_HINT):
|
||||||
|
text = text[len(FILE_HINT):].lstrip()
|
||||||
|
if "### 用户当前消息" in text:
|
||||||
|
text = text.split("### 用户当前消息", 1)[-1].strip()
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _native_response_summary(response_body):
|
||||||
|
try:
|
||||||
|
blocks = ast.literal_eval((response_body or "").strip())
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
if not isinstance(blocks, list):
|
||||||
|
return ""
|
||||||
|
text_parts = []
|
||||||
|
for block in blocks:
|
||||||
|
if isinstance(block, dict) and block.get("type") == "text":
|
||||||
|
text = block.get("text", "")
|
||||||
|
if isinstance(text, str) and text:
|
||||||
|
text_parts.append(text)
|
||||||
|
match = SUMMARY_RE.search("\n".join(text_parts))
|
||||||
|
return (match.group(1).strip() if match else "")[:500]
|
||||||
|
|
||||||
|
|
||||||
|
def _restore_native_history(content):
|
||||||
|
blocks = RESTORE_BLOCK_RE.findall(content or "")
|
||||||
|
if not blocks:
|
||||||
|
return []
|
||||||
|
pairs = []
|
||||||
|
pending_prompt = None
|
||||||
|
for label, body in blocks:
|
||||||
|
if label == "Prompt":
|
||||||
|
pending_prompt = body
|
||||||
|
elif pending_prompt is not None:
|
||||||
|
pairs.append((pending_prompt, body))
|
||||||
|
pending_prompt = None
|
||||||
|
for prompt_body, response_body in reversed(pairs):
|
||||||
|
prompt = _native_prompt_obj(prompt_body)
|
||||||
|
if prompt is None:
|
||||||
|
continue
|
||||||
|
prompt_text = _native_prompt_text(prompt)
|
||||||
|
restored = list(_native_history_lines(prompt_text))
|
||||||
|
if restored:
|
||||||
|
summary = _native_response_summary(response_body)
|
||||||
|
summary_line = f"[Agent] {summary}" if summary else ""
|
||||||
|
if summary_line and (not restored or restored[-1] != summary_line):
|
||||||
|
restored.append(summary_line)
|
||||||
|
return restored
|
||||||
|
user_text = _native_first_user_line(prompt_text)
|
||||||
|
summary = _native_response_summary(response_body)
|
||||||
|
if user_text and summary:
|
||||||
|
return [f"[USER]: {user_text}", f"[Agent] {summary}"]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def format_restore():
|
||||||
|
files = _restore_log_files()
|
||||||
|
if not files:
|
||||||
|
return None, "❌ 没有找到历史记录"
|
||||||
|
latest = max(files, key=os.path.getmtime)
|
||||||
|
with open(latest, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
restored = _restore_text_pairs(content) or _restore_native_history(content)
|
||||||
if not restored:
|
if not restored:
|
||||||
return None, "❌ 历史记录里没有可恢复内容"
|
return None, "❌ 历史记录里没有可恢复内容"
|
||||||
return (restored, os.path.basename(latest), len(restored) // 2), None
|
count = sum(1 for line in restored if line.startswith("[USER]: "))
|
||||||
|
return (restored, os.path.basename(latest), count), None
|
||||||
|
|
||||||
|
|
||||||
def build_done_text(raw_text):
|
def build_done_text(raw_text):
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
sys.path.insert(0, PROJECT_ROOT)
|
sys.path.insert(0, PROJECT_ROOT)
|
||||||
os.chdir(PROJECT_ROOT)
|
os.chdir(PROJECT_ROOT)
|
||||||
from agentmain import GeneraticAgent
|
from agentmain import GeneraticAgent
|
||||||
|
from frontends.chatapp_common import format_restore
|
||||||
from llmcore import mykeys
|
from llmcore import mykeys
|
||||||
|
|
||||||
import lark_oapi as lark
|
import lark_oapi as lark
|
||||||
@@ -516,22 +517,13 @@ def handle_command(open_id, cmd, chat_id=None):
|
|||||||
_send_cmd_response(f"状态: {'空闲' if not agent.is_running else '运行中'}")
|
_send_cmd_response(f"状态: {'空闲' if not agent.is_running else '运行中'}")
|
||||||
elif cmd == "/restore":
|
elif cmd == "/restore":
|
||||||
try:
|
try:
|
||||||
files = glob.glob("./temp/model_responses_*.txt")
|
restored_info, err = format_restore()
|
||||||
if not files:
|
if err:
|
||||||
return _send_cmd_response("没有找到历史记录")
|
return _send_cmd_response(err.replace("❌ ", ""))
|
||||||
latest = max(files, key=os.path.getmtime)
|
restored, fname, count = restored_info
|
||||||
with open(latest, "r", encoding="utf-8") as f:
|
agent.history.extend(restored)
|
||||||
content = f.read()
|
|
||||||
users = re.findall(r"=== USER ===\n(.+?)(?==== |$)", content, re.DOTALL)
|
|
||||||
resps = re.findall(r"=== Response ===.*?\n(.+?)(?==== Prompt|$)", content, re.DOTALL)
|
|
||||||
count = 0
|
|
||||||
for u, r in zip(users, resps):
|
|
||||||
u, r = u.strip(), r.strip()[:500]
|
|
||||||
if u and r:
|
|
||||||
agent.history.extend([f"[USER]: {u}", f"[Agent] {r}"])
|
|
||||||
count += 1
|
|
||||||
agent.abort()
|
agent.abort()
|
||||||
_send_cmd_response(f"已恢复 {count} 轮对话\n来源: {os.path.basename(latest)}\n(仅恢复上下文,请输入新问题继续)")
|
_send_cmd_response(f"已恢复 {count} 轮对话\n来源: {fname}\n(仅恢复上下文,请输入新问题继续)")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_send_cmd_response(f"恢复失败: {e}")
|
_send_cmd_response(f"恢复失败: {e}")
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user