diff --git a/apps/admin_console/routers/sessions.py b/apps/admin_console/routers/sessions.py
index d53e4be..b4c4a3e 100644
--- a/apps/admin_console/routers/sessions.py
+++ b/apps/admin_console/routers/sessions.py
@@ -283,9 +283,18 @@ async def cleanup_history_endpoint():
@router.post("/api/sessions/{session_id}/delete")
async def delete_session_endpoint(session_id: str):
+ from artemis.exploration.store import ExplorationConflict, explorations
+
try:
from artemis.data_engine.storage import StorageManager
+ session_id = str(UUID(session_id))
+ run = explorations.run(session_id)
+ if run and run["kind"] == "exploration":
+ from apps.admin_console.services.exploration_deletion import delete_exploration
+
+ deleted = delete_exploration(explorations, run["exploration_id"])
+ return {"status": "success", "deleted_session_ids": deleted}
storage = StorageManager(DB_PATH, TRACES_PATH)
storage.delete_session(UUID(session_id))
from apps.admin_console.services.automation_store import store
@@ -294,6 +303,11 @@ async def delete_session_endpoint(session_id: str):
return {
"status": "success",
"message": f"Session {session_id} deleted successfully",
+ "deleted_session_ids": [session_id],
}
+ except ExplorationConflict as e:
+ raise HTTPException(status_code=409, detail=str(e)) from e
+ except (ValueError, KeyError) as e:
+ raise HTTPException(status_code=400, detail=str(e)) from e
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
diff --git a/apps/admin_console/services/exploration_deletion.py b/apps/admin_console/services/exploration_deletion.py
new file mode 100644
index 0000000..e8c74fc
--- /dev/null
+++ b/apps/admin_console/services/exploration_deletion.py
@@ -0,0 +1,48 @@
+"""Delete an inactive conversation while keeping independently executed reruns."""
+
+import shutil
+from uuid import UUID
+
+from apps.admin_console.core.state import state
+from apps.admin_console.services import report_export
+from artemis.data_engine.storage import StorageManager
+from artemis.exploration.store import ExplorationConflict, ExplorationStore
+from artemis.runtime.process_probe import pid_is_alive
+from artemis.runtime.task_control import read_state
+
+
+def _check_runs(runs: list[dict]) -> None:
+ queued = {
+ item.get("session_id")
+ for item in state.queue_items
+ if item.get("status") in {"pending", "queued", "running"}
+ }
+ for run in runs:
+ run_id = run["id"]
+ if (
+ run_id in state.active_runs
+ or run_id in queued
+ or pid_is_alive(read_state(run_id).get("pid"))
+ ):
+ raise ExplorationConflict("探索工作进程尚未结束,请停止任务并稍后重试删除")
+
+
+def delete_exploration(repository: ExplorationStore, exploration_id: str) -> list[str]:
+ runs = repository.begin_delete(exploration_id, _check_runs)
+ # Validation sessions and batch copies remain ordinary Flash/Pro history.
+ deleted = [run["id"] for run in runs if run["kind"] == "exploration"]
+ storage = StorageManager(repository.database.path, report_export.TRACES_PATH)
+ with report_export.EXPORT_LOCK:
+ for run_id in deleted:
+ safe_id = str(UUID(run_id))
+ storage.delete_session(UUID(safe_id))
+ repository.database.delete_history(safe_id)
+ for root in (
+ report_export.EXPORT_ROOT,
+ report_export.EXPORT_ROOT.parent / "mcp_exports",
+ ):
+ folder = (root / "sessions" / safe_id).resolve()
+ if folder.is_relative_to(root.resolve()) and folder.is_dir():
+ shutil.rmtree(folder)
+ repository.finish_delete(exploration_id)
+ return deleted
diff --git a/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html b/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html
index 48f4528..6e0a486 100644
--- a/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html
+++ b/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html
@@ -62,6 +62,7 @@ limitations under the License.
任务队列
{{ deleteError() }}
}