---
name: conversation_model_persistence
description: 当加载/恢复对话时发现模型未恢复，或新建对话后旧对话模型被覆盖时，应该索引本记忆
---

# 对话模型持久化约定

## 核心规则

- 每个对话的 `model_key` 保存在对话文件的 `metadata.model_key` 中。
- 切换模型时（`/api/model`）会立即调用 `utils/conversation_manager/ConversationManager.save_conversation(..., model_key=terminal.model_key)` 写入对话文件。
- **加载对话时必须恢复该对话保存的模型**，不能沿用终端当前的默认模型或用户个性化默认模型。
- **创建新对话时，必须先保存旧对话、再应用默认模型到新对话**，否则旧对话的 `model_key` 会被默认模型覆盖。

## 关键实现点

### 1. 手动加载对话

路径：`/api/conversations/<conversation_id>/load` → `core/web_terminal.py::WebTerminal.load_conversation()`

- 该方法会从对话元数据中恢复 `thinking_mode`、`permission_mode`、`execution_mode`、`network_permission` 等状态。
- **必须同时恢复 `model_key`**：
  ```python
  saved_model_key = meta.get("model_key")
  if saved_model_key:
      try:
          self.set_model(saved_model_key)
      except Exception as exc:
          logger.warning("加载对话模型 %s 失败: %s", saved_model_key, exc)
  ```
- 恢复后，`terminal.model_key` 即对话保存的模型，`get_status()` 和 API 返回的 `model_key` 都会正确。

### 2. 程序重启后自动恢复最近对话

路径：`core/web_terminal.py::WebTerminal._ensure_conversation()`

- Web 终端初始化时会自动加载最近的对话。
- 原来的实现只调用 `utils/context_manager/ContextManager.load_conversation_by_id()`，不会恢复 `model_key` 等运行时状态。
- 应改为调用 `self.load_conversation(conv_id)`，以复用完整的状态恢复逻辑（含模型恢复）。

### 3. 创建新对话时保护旧对话的模型

路径：`core/web_terminal.py::WebTerminal.create_new_conversation()`

- **错误顺序**：先 `set_model(默认模型)` → 再 `start_new_conversation()` → `start_new_conversation()` 内部先 `save_current_conversation()` → 旧对话被按默认模型保存，覆盖了之前的模型。
- **正确顺序**：
  1. 计算默认 `run_mode`、`permission_mode` 并应用（不改 `model_key`）。
  2. 调用 `start_new_conversation()`，此时 `terminal.model_key` 仍是旧对话的模型，旧对话被正确保存。
  3. 新对话创建完成后，再 `set_model(默认模型)`，并 `save_conversation` 更新新对话的 `model_key`。

### 4. 前端

路径：`static/src/app/methods/conversation/load.ts::loadConversation()`

- 前端在调用 `/api/conversations/<id>/load` 后，会根据返回的 `result.model_key` 更新当前模型：
  ```typescript
  if (typeof result.model_key === 'string' && result.model_key) {
    this.modelSet(result.model_key);
  }
  ```
- 后端修复后，返回的 `model_key` 即为对话保存的模型，前端会自动应用。

## 注意事项

- `set_model()` 可能因图片/视频不兼容或模型被禁用而抛异常，加载场景下应捕获并记录警告，不要让加载失败。
- 如果对话元数据中没有 `model_key`（旧数据或新建对话），保持当前模型即可。
