Co-authored-by: Alexis Tacnet <alexis@mistral.ai> Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com> Co-authored-by: Lucas Marandat <31749711+lucasmrdt@users.noreply.github.com> Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Val <102326092+vdeva@users.noreply.github.com> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: p.vezia <166131032+le-codeur-rapide@users.noreply.github.com> Co-authored-by: Hiba Chaabnia <Hiba-Chaabnia@users.noreply.github.com> Co-authored-by: Nikhil Bhima <nikhilbhima@users.noreply.github.com> Co-authored-by: Nkipohcs <Nkipohcs@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
87 lines
2.7 KiB
Python
87 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import json
|
|
from pathlib import Path
|
|
import shutil
|
|
from typing import Any
|
|
|
|
from vibe.core.config import SessionLoggingConfig
|
|
from vibe.core.session import last_session_pointer
|
|
from vibe.core.session.session_loader import METADATA_FILENAME, SessionLoader
|
|
from vibe.core.session.session_logger import SessionLogger
|
|
from vibe.core.utils.io import read_safe
|
|
|
|
|
|
def _normalize_session_title(title: str) -> str:
|
|
normalized_title = title.strip()
|
|
if not normalized_title:
|
|
raise ValueError("Session title cannot be empty.")
|
|
|
|
return normalized_title
|
|
|
|
|
|
def _resolve_saved_session_dir(
|
|
session_id: str, session_config: SessionLoggingConfig
|
|
) -> Path:
|
|
session_dir = _find_saved_session_dir(session_id, session_config)
|
|
if session_dir is None:
|
|
raise ValueError(f"Session not found: {session_id}")
|
|
|
|
return session_dir
|
|
|
|
|
|
def _find_saved_session_dir(
|
|
session_id: str, session_config: SessionLoggingConfig
|
|
) -> Path | None:
|
|
for session_dir in SessionLoader._find_session_dirs_by_short_id(
|
|
session_id, session_config
|
|
):
|
|
try:
|
|
metadata = _load_raw_metadata(session_dir)
|
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
continue
|
|
|
|
if metadata.get("session_id") == session_id:
|
|
return session_dir
|
|
|
|
return None
|
|
|
|
|
|
def _load_raw_metadata(session_dir: Path) -> dict[str, Any]:
|
|
metadata_path = session_dir / METADATA_FILENAME
|
|
metadata = json.loads(read_safe(metadata_path).text)
|
|
if not isinstance(metadata, dict):
|
|
raise ValueError(f"Session metadata must be an object: {metadata_path}")
|
|
|
|
return metadata
|
|
|
|
|
|
async def update_saved_session_title_at_path(
|
|
session_dir: Path, title: str
|
|
) -> dict[str, Any]:
|
|
normalized_title = _normalize_session_title(title)
|
|
metadata = _load_raw_metadata(session_dir)
|
|
|
|
updated_metadata = {**metadata, "title": normalized_title, "title_source": "manual"}
|
|
await SessionLogger.persist_metadata(updated_metadata, session_dir)
|
|
return updated_metadata
|
|
|
|
|
|
async def update_saved_session_title(
|
|
session_id: str, title: str, session_config: SessionLoggingConfig
|
|
) -> dict[str, Any]:
|
|
session_dir = _resolve_saved_session_dir(session_id, session_config)
|
|
return await update_saved_session_title_at_path(session_dir, title)
|
|
|
|
|
|
async def delete_saved_session(
|
|
session_id: str, session_config: SessionLoggingConfig
|
|
) -> None:
|
|
session_dir = _find_saved_session_dir(session_id, session_config)
|
|
if session_dir is None:
|
|
last_session_pointer.clear_matching(session_config, session_id)
|
|
return
|
|
|
|
await asyncio.to_thread(shutil.rmtree, session_dir)
|
|
last_session_pointer.clear_matching(session_config, session_id)
|