diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs index 11e028cb4..a456b7596 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs @@ -1247,8 +1247,6 @@ fn external_mcp_record_response(root: &Path, arguments: &Value) -> Value { Err(error) => return mcp_tool_result(error, Vec::new(), true), }; let redacted = redact_external_mcp_response(&content); - let key = format!("{request_id}\u{0}{sequence}"); - let message_id = format!("external-codex-{:x}", Sha256::digest(key.as_bytes())); let guard = EXTERNAL_MCP_JOURNAL_LOCK .get_or_init(|| Mutex::new(())) .lock(); @@ -1358,29 +1356,6 @@ fn external_mcp_record_response(root: &Path, arguments: &Value) -> Value { true, ); } - // Reuse the existing conversation projection so the current UI can read - // the explicit external response without treating it as business truth. - if let Err(error) = append_local_conversation_message_for_session_idempotent_at( - root, - None, - None, - LocalConversationMessage { - role: "assistant".to_string(), - content: record - .get("content") - .and_then(Value::as_str) - .unwrap_or_default() - .to_string(), - agent_id: None, - }, - &message_id, - ) { - return mcp_tool_result( - format!("Codex 返回已写入但对话投影失败:{error}"), - Vec::new(), - true, - ); - } records.push(record.clone()); mcp_tool_result(record.to_string(), Vec::new(), false) } @@ -2280,4 +2255,33 @@ mod tests { })) .is_err()); } + + #[test] + fn recorded_codex_response_only_writes_its_own_journal() { + let temporary = crate::tests::canonical_test_tempdir("direct-tools-record-response-"); + let root = temporary.path(); + init_local_game_project_at(root, "direct-tools-record", "Codex 返回记录测试") + .expect("init project"); + + let result = external_mcp_record_response( + root, + &json!({ + "requestId": "req-1", + "sequence": 0, + "content": "已完成的返回正文" + }), + ); + assert_eq!(result.get("isError"), Some(&json!(false)), "{result}"); + + let journal = root.join(".agent/conversations/codex-responses.jsonl"); + let journal_text = std::fs::read_to_string(&journal).expect("read codex responses journal"); + assert!(journal_text.contains("已完成的返回正文"), "{journal_text}"); + + let project_history = root.join(".agent/conversations/project.jsonl"); + let project_history_text = std::fs::read_to_string(&project_history).unwrap_or_default(); + assert_eq!( + project_history_text, "", + "显式 Codex 返回不能再往项目主对话写 legacy 行" + ); + } }