对话会话 —— 包含一整段对话的所有消息。 注意这里没有 frozen=True,因为我们需要往里面添加消息。 对应源码: session.rs:42-46
| 221 | |
| 222 | @dataclass |
| 223 | class Session: |
| 224 | """ |
| 225 | 对话会话 —— 包含一整段对话的所有消息。 |
| 226 | |
| 227 | 注意这里没有 frozen=True,因为我们需要往里面添加消息。 |
| 228 | 对应源码: session.rs:42-46 |
| 229 | """ |
| 230 | version: int = 1 |
| 231 | messages: list[ConversationMessage] = field(default_factory=list) |
| 232 | |
| 233 | # ---- 序列化(保存到文件)---- |
| 234 | # 序列化是什么?就是把 Python 对象变成可以写入文件的格式(比如 JSON)。 |
| 235 | # 反序列化就是反过来,从文件读取并还原成 Python 对象。 |
| 236 | |
| 237 | def to_dict(self) -> dict: |
| 238 | """把 Session 变成字典(方便转 JSON)""" |
| 239 | return { |
| 240 | "version": self.version, |
| 241 | "messages": [self._message_to_dict(msg) for msg in self.messages], |
| 242 | } |
| 243 | |
| 244 | def save_to_file(self, path: str) -> None: |
| 245 | """保存到 JSON 文件(存档)""" |
| 246 | with open(path, "w", encoding="utf-8") as f: |
| 247 | json.dump(self.to_dict(), f, ensure_ascii=False, indent=2) |
| 248 | |
| 249 | @classmethod |
| 250 | def load_from_file(cls, path: str) -> "Session": |
| 251 | """从 JSON 文件加载(读档)""" |
| 252 | with open(path, "r", encoding="utf-8") as f: |
| 253 | data = json.load(f) |
| 254 | session = cls(version=data["version"]) |
| 255 | for msg_data in data["messages"]: |
| 256 | session.messages.append(cls._dict_to_message(msg_data)) |
| 257 | return session |
| 258 | |
| 259 | @staticmethod |
| 260 | def _message_to_dict(msg: ConversationMessage) -> dict: |
| 261 | result = {"role": msg.role, "blocks": []} |
| 262 | for block in msg.blocks: |
| 263 | if isinstance(block, TextBlock): |
| 264 | result["blocks"].append({"type": "text", "text": block.text}) |
| 265 | elif isinstance(block, ToolUseBlock): |
| 266 | result["blocks"].append({ |
| 267 | "type": "tool_use", "id": block.id, |
| 268 | "name": block.name, "input": block.input, |
| 269 | }) |
| 270 | elif isinstance(block, ToolResultBlock): |
| 271 | result["blocks"].append({ |
| 272 | "type": "tool_result", "tool_use_id": block.tool_use_id, |
| 273 | "tool_name": block.tool_name, "output": block.output, |
| 274 | "is_error": block.is_error, |
| 275 | }) |
| 276 | if msg.usage is not None: |
| 277 | result["usage"] = { |
| 278 | "input_tokens": msg.usage.input_tokens, |
| 279 | "output_tokens": msg.usage.output_tokens, |
| 280 | } |