♻️ 大幅重构,拆分模块,增加一些MCP相关限制
Some checks failed
Pyright Lint / Pyright Lint (push) Has been cancelled
Ruff Lint / Ruff Lint (push) Has been cancelled

This commit is contained in:
FuQuan233 2026-07-29 17:00:22 +08:00
parent 41e6aeacb9
commit 0d6771eca6
17 changed files with 1142 additions and 912 deletions

View file

@ -0,0 +1,88 @@
import asyncio
from collections import deque
import json
import os
from pathlib import Path
import aiofiles
from nonebot import logger
from .config import ScopedConfig
from .state import ChatState, StateStore
class StatePersistence:
def __init__(self, config: ScopedConfig, states: StateStore, group_file: Path, private_file: Path):
self.config = config
self.states = states
self.group_file = group_file
self.private_file = private_file
self._lock = asyncio.Lock()
@staticmethod
def _serialize(state: ChatState, include_probability: bool) -> dict:
data = {
"preset": state.preset_name,
"history": list(state.history),
"last_active": state.last_active,
"group_prompt": state.prompt,
"output_reasoning_content": state.output_reasoning_content,
}
if include_probability:
data["random_trigger_prob"] = state.random_trigger_prob
return data
async def _write_json(self, path: Path, data: dict) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(path.suffix + ".tmp")
async with aiofiles.open(temporary, "w", encoding="utf8") as file:
await file.write(json.dumps(data, ensure_ascii=False))
os.replace(temporary, path)
async def save(self) -> None:
async with self._lock:
await self._write_json(
self.group_file,
{key: self._serialize(state, True) for key, state in self.states.group_states.items()},
)
if self.config.enable_private_chat:
await self._write_json(
self.private_file,
{key: self._serialize(state, False) for key, state in self.states.private_states.items()},
)
async def _read_json(self, path: Path) -> dict:
if not path.exists():
return {}
try:
async with aiofiles.open(path, encoding="utf8") as file:
value = json.loads(await file.read())
return value if isinstance(value, dict) else {}
except (OSError, json.JSONDecodeError):
logger.exception(f"读取llmchat状态失败: {path}")
return {}
def _restore(self, raw: dict, *, is_group: bool) -> ChatState:
state = ChatState(
preset_name=raw.get(
"preset",
self.config.default_preset if is_group else self.config.private_chat_preset,
),
history_size=self.config.history_size,
past_events_size=self.config.past_events_size,
random_trigger_prob=raw.get("random_trigger_prob", self.config.random_trigger_prob) if is_group else 0.0,
)
state.history = deque(raw.get("history", []), maxlen=self.config.history_size * 2)
state.last_active = raw.get("last_active", state.last_active)
state.prompt = raw.get("group_prompt", raw.get("prompt"))
state.output_reasoning_content = raw.get("output_reasoning_content", False)
return state
async def load(self) -> None:
groups = await self._read_json(self.group_file)
for context_id, raw in groups.items():
self.states.group_states[int(context_id)] = self._restore(raw, is_group=True)
if self.config.enable_private_chat:
private = await self._read_json(self.private_file)
for context_id, raw in private.items():
self.states.private_states[int(context_id)] = self._restore(raw, is_group=False)