fix(versioning): 压缩继承版本控制并忽略系统目录
This commit is contained in:
parent
0ba2763696
commit
eba36c46da
@ -27,6 +27,7 @@ class VersioningPaths:
|
|||||||
|
|
||||||
class ConversationVersioningManager:
|
class ConversationVersioningManager:
|
||||||
"""Manage hidden git snapshots bound to a conversation."""
|
"""Manage hidden git snapshots bound to a conversation."""
|
||||||
|
SYSTEM_AUTO_DIRS = ("compact_result", "skills", "user_upload")
|
||||||
|
|
||||||
def __init__(self, project_path: Path | str, data_dir: Path | str, conversation_id: str):
|
def __init__(self, project_path: Path | str, data_dir: Path | str, conversation_id: str):
|
||||||
self.project_path = Path(project_path).expanduser().resolve()
|
self.project_path = Path(project_path).expanduser().resolve()
|
||||||
@ -81,10 +82,6 @@ class ConversationVersioningManager:
|
|||||||
|
|
||||||
def _ensure_exclude_paths(self) -> None:
|
def _ensure_exclude_paths(self) -> None:
|
||||||
"""Avoid recursive tracking if save root is inside work tree."""
|
"""Avoid recursive tracking if save root is inside work tree."""
|
||||||
try:
|
|
||||||
rel_save = self.paths.save_root.relative_to(self.project_path)
|
|
||||||
except ValueError:
|
|
||||||
return
|
|
||||||
info_exclude = self.paths.git_dir / "info" / "exclude"
|
info_exclude = self.paths.git_dir / "info" / "exclude"
|
||||||
info_exclude.parent.mkdir(parents=True, exist_ok=True)
|
info_exclude.parent.mkdir(parents=True, exist_ok=True)
|
||||||
existing = ""
|
existing = ""
|
||||||
@ -93,18 +90,46 @@ class ConversationVersioningManager:
|
|||||||
existing = info_exclude.read_text(encoding="utf-8", errors="ignore")
|
existing = info_exclude.read_text(encoding="utf-8", errors="ignore")
|
||||||
except OSError:
|
except OSError:
|
||||||
existing = ""
|
existing = ""
|
||||||
marker = str(rel_save).replace("\\", "/").rstrip("/")
|
existing_lines = set(existing.splitlines())
|
||||||
if not marker:
|
lines_to_add: List[str] = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
rel_save = self.paths.save_root.relative_to(self.project_path)
|
||||||
|
marker = str(rel_save).replace("\\", "/").rstrip("/")
|
||||||
|
if marker:
|
||||||
|
lines_to_add.append(f"{marker}/")
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for dirname in self.SYSTEM_AUTO_DIRS:
|
||||||
|
clean = str(dirname or "").strip().strip("/").replace("\\", "/")
|
||||||
|
if not clean:
|
||||||
|
continue
|
||||||
|
# 同时忽略根目录与任意层级同名目录
|
||||||
|
lines_to_add.append(f"/{clean}/")
|
||||||
|
lines_to_add.append(f"{clean}/")
|
||||||
|
|
||||||
|
pending = [line for line in lines_to_add if line not in existing_lines]
|
||||||
|
if not pending:
|
||||||
return
|
return
|
||||||
line = f"{marker}/"
|
if existing and not existing.endswith("\n"):
|
||||||
if line not in existing.splitlines():
|
pending.insert(0, "")
|
||||||
with info_exclude.open("a", encoding="utf-8") as fh:
|
with info_exclude.open("a", encoding="utf-8") as fh:
|
||||||
if existing and not existing.endswith("\n"):
|
fh.write("\n".join(pending) + "\n")
|
||||||
fh.write("\n")
|
|
||||||
fh.write(line + "\n")
|
def _drop_ignored_from_index(self) -> None:
|
||||||
|
"""
|
||||||
|
Ensure ignored system directories are not kept as tracked files in hidden git index.
|
||||||
|
"""
|
||||||
|
for dirname in self.SYSTEM_AUTO_DIRS:
|
||||||
|
clean = str(dirname or "").strip().strip("/").replace("\\", "/")
|
||||||
|
if not clean:
|
||||||
|
continue
|
||||||
|
self._run_git(["rm", "-r", "--cached", "--ignore-unmatch", "--", clean], check=False)
|
||||||
|
|
||||||
def _stage_all(self) -> None:
|
def _stage_all(self) -> None:
|
||||||
self._ensure_exclude_paths()
|
self._ensure_exclude_paths()
|
||||||
|
self._drop_ignored_from_index()
|
||||||
# Stage everything under work tree; exclusions are handled via info/exclude.
|
# Stage everything under work tree; exclusions are handled via info/exclude.
|
||||||
self._run_git(["add", "-A", "--", "."])
|
self._run_git(["add", "-A", "--", "."])
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ from datetime import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
from modules.versioning_manager import ConversationVersioningManager
|
||||||
|
|
||||||
|
|
||||||
SUMMARY_PROMPT = (
|
SUMMARY_PROMPT = (
|
||||||
"由于当前对话过长,系统正在自动压缩。请你基于已有上下文输出一份可继续执行的工作总结,要求:\n"
|
"由于当前对话过长,系统正在自动压缩。请你基于已有上下文输出一份可继续执行的工作总结,要求:\n"
|
||||||
@ -249,6 +251,8 @@ async def run_deep_compression(
|
|||||||
return {"success": False, "error": "对话正在压缩中", "in_progress": True}
|
return {"success": False, "error": "对话正在压缩中", "in_progress": True}
|
||||||
|
|
||||||
old_title = conv_data.get("title") or "未命名"
|
old_title = conv_data.get("title") or "未命名"
|
||||||
|
source_versioning = metadata.get("versioning") if isinstance(metadata.get("versioning"), dict) else {}
|
||||||
|
source_versioning_enabled = bool(source_versioning.get("enabled"))
|
||||||
compression_count = int(metadata.get("compression_count", 0) or 0)
|
compression_count = int(metadata.get("compression_count", 0) or 0)
|
||||||
previous_records = _normalize_deep_compression_records(metadata)
|
previous_records = _normalize_deep_compression_records(metadata)
|
||||||
previous_max_count = max([int(item.get("count") or 0) for item in previous_records], default=0)
|
previous_max_count = max([int(item.get("count") or 0) for item in previous_records], default=0)
|
||||||
@ -337,6 +341,45 @@ async def run_deep_compression(
|
|||||||
"last_deep_compression_record": current_record,
|
"last_deep_compression_record": current_record,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if source_versioning_enabled:
|
||||||
|
try:
|
||||||
|
vm = ConversationVersioningManager(
|
||||||
|
project_path=workspace.project_path,
|
||||||
|
data_dir=workspace.data_dir,
|
||||||
|
conversation_id=new_conv_id,
|
||||||
|
)
|
||||||
|
vm_meta = vm.set_enabled(enabled=True, mode="overwrite")
|
||||||
|
new_conv_data = cm.conversation_manager.load_conversation(new_conv_id) or {}
|
||||||
|
snapshot_payload = {
|
||||||
|
"conversation_id": new_conv_id,
|
||||||
|
"title": new_conv_data.get("title"),
|
||||||
|
"metadata": new_conv_data.get("metadata") or {},
|
||||||
|
"messages": new_conv_data.get("messages") or [],
|
||||||
|
"message_index": -1,
|
||||||
|
"run_status": "initial",
|
||||||
|
}
|
||||||
|
init_result = vm.ensure_initial_checkpoint(
|
||||||
|
workspace_path=str(workspace.project_path),
|
||||||
|
conversation_snapshot=snapshot_payload,
|
||||||
|
)
|
||||||
|
init_row = init_result.get("row") or {}
|
||||||
|
last_commit = init_row.get("commit") or vm_meta.get("last_commit")
|
||||||
|
cm.conversation_manager.update_conversation_metadata(
|
||||||
|
new_conv_id,
|
||||||
|
{
|
||||||
|
"versioning": {
|
||||||
|
"enabled": True,
|
||||||
|
"mode": "overwrite",
|
||||||
|
"updated_at": datetime.now().isoformat(),
|
||||||
|
"last_commit": last_commit,
|
||||||
|
"last_input_seq": int(vm_meta.get("last_input_seq") or 0),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
cm.conversation_manager.update_conversation_title(new_conv_id, f"{old_title}对话 压缩后")
|
cm.conversation_manager.update_conversation_title(new_conv_id, f"{old_title}对话 压缩后")
|
||||||
web_terminal.load_conversation(new_conv_id)
|
web_terminal.load_conversation(new_conv_id)
|
||||||
guide_message = _build_guide_message(
|
guide_message = _build_guide_message(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user