merge: merge origin/gamma/refactor and origin/feature/teamhoa/r05-r06 into feature/delta-team/epic-R04

This commit is contained in:
2026-08-27 12:23:43 +09:00
57 changed files with 3003 additions and 512 deletions
+13 -6
View File
@@ -16,8 +16,6 @@ from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List
from ..config import HISTORY_DIR
def new_session_id() -> str:
return datetime.now().strftime("%Y%m%d-%H%M%S-%f")[:-3]
@@ -66,7 +64,9 @@ def save_conversation(
"outputs": list(outputs or []),
"messages": messages,
}
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
# R06-T02: atomic write - see infrastructure/persistence/json/atomic_write.py.
from ..infrastructure.persistence.json.atomic_write import write_json
write_json(path, payload)
return path
@@ -78,15 +78,19 @@ def delete_conversation(path) -> None:
def rename_conversation(path, new_title: str) -> None:
from ..infrastructure.persistence.json.atomic_write import write_json
data = load_conversation(path)
data["title"] = new_title
Path(path).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
write_json(Path(path), data)
def set_pinned(path, pinned: bool) -> None:
from ..infrastructure.persistence.json.atomic_write import write_json
data = load_conversation(path)
data["pinned"] = bool(pinned)
Path(path).write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
write_json(Path(path), data)
def load_conversation(path: Path) -> Dict[str, Any]:
@@ -111,13 +115,16 @@ def _matches_query(query: str, title: str, messages: List[Dict[str, Any]]) -> bo
return False
def list_conversations(directory: Path = HISTORY_DIR, query: str = "") -> List[Dict[str, Any]]:
def list_conversations(directory: Optional[Path] = None, query: str = "") -> List[Dict[str, Any]]:
"""List saved conversations, most recent first (pinned always on top).
``query`` (from the sidebar's search box), when non-empty, keeps only
conversations whose title OR any message's content contains it
(case-insensitive) — since every file is already parsed to build the
metadata below, this search costs no extra I/O over listing alone."""
if directory is None:
from ..config import HISTORY_DIR
directory = HISTORY_DIR
if not directory or not directory.exists():
return []
q = (query or "").strip().lower()