agent-Specialization/.agents/memory/conversation_model_persistence.md
JOJO f661dc6456 refactor(server,modules,utils,frontend): split oversized modules into packages and fix regressions
- Split server/chat.py, server/status.py, server/tasks.py into sub-packages
- Split utils/context_manager.py, utils/conversation_manager.py into mixin packages
- Split modules/file_manager.py, persistent_terminal.py, terminal_ops.py, mcp_client_manager.py into packages
- Split core/main_terminal_parts/context.py into base + mixins
- Split static/src/app/methods/{ui,message,upload,taskPolling,conversation} into sub-modules
- Fix flattened method exports, dynamic import paths, missing cross-module imports
- Add missing permission/network/execution mode constants and _PERMISSION_MODE_LABEL
- Update AGENTS.md, CLAUDE.md and project memories to reflect new structure
2026-06-20 15:54:48 +08:00

67 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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`(旧数据或新建对话),保持当前模型即可。