From 5bc734030493aeadeb36392d16ab91eca641cd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 15 Sep 2026 15:22:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BD=E7=A6=BB=20DirectProject=20=E8=BA=AB?= =?UTF-8?q?=E4=BB=BD=E8=A7=A3=E6=9E=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将项目 canonical identity 与 digest 放入独立文件 保持 Codex app-server 线程池调用接口不变 --- .../direct_project_identity.rs | 50 +++++++++++++++++++ .../src/agent/codex_app_server/mod.rs | 48 +----------------- 2 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/direct_project_identity.rs diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/direct_project_identity.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/direct_project_identity.rs new file mode 100644 index 000000000..4454a2a48 --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/direct_project_identity.rs @@ -0,0 +1,50 @@ +//! DirectProject 线程池身份的 canonical 解析与摘要。 + +use super::super::*; +use sha2::{Digest, Sha256}; + +pub(super) fn direct_codex_canonical_project_identity( + root: &std::path::Path, +) -> Result<(std::path::PathBuf, String), String> { + let (canonical_root, _) = resolve_direct_codex_project_authority(root)?; + let manifest = read_manifest(&canonical_root.join(".agent/manifest.json")) + .map_err(|error| format!("读取 DirectProject 权威项目身份失败:{error}"))?; + let manifest_project_id = manifest.project_id.trim(); + if manifest_project_id.is_empty() || manifest_project_id.chars().count() > 256 { + return Err("DirectProject manifest.projectId 不满足身份边界".to_string()); + } + let path_identity = direct_codex_os_path_identity_bytes(&canonical_root); + Ok(( + canonical_root, + direct_codex_project_identity_digest(&path_identity, manifest_project_id.as_bytes()), + )) +} + +fn direct_codex_os_path_identity_bytes(path: &std::path::Path) -> Vec { + #[cfg(unix)] + { + use std::os::unix::ffi::OsStrExt; + return path.as_os_str().as_bytes().to_vec(); + } + #[cfg(windows)] + { + use std::os::windows::ffi::OsStrExt; + let mut bytes = Vec::new(); + for unit in path.as_os_str().encode_wide() { + bytes.extend_from_slice(&unit.to_le_bytes()); + } + return bytes; + } + #[cfg(not(any(unix, windows)))] + path.as_os_str().to_string_lossy().as_bytes().to_vec() +} + +fn direct_codex_project_identity_digest(path_identity: &[u8], project_id: &[u8]) -> String { + let mut digest = Sha256::new(); + digest.update(b"genarrative-direct-project-identity.v1\0"); + digest.update((path_identity.len() as u64).to_le_bytes()); + digest.update(path_identity); + digest.update((project_id.len() as u64).to_le_bytes()); + digest.update(project_id); + format!("{:x}", digest.finalize()) +} diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs index 506b038f4..d6174b5d8 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs @@ -12,6 +12,8 @@ use uuid::Uuid; mod direct_project_history_wire; use direct_project_history_wire::build_direct_project_history_injection_params; +mod direct_project_identity; +use direct_project_identity::*; const GAME_CREATOR_CODEX_APP_SERVER_PROVIDER_ID: &str = "genarrative_agc"; const GAME_CREATOR_CODEX_APP_SERVER_API_KEY_ENV: &str = "GENARRATIVE_AGC_CODEX_API_KEY"; @@ -3778,52 +3780,6 @@ pub(crate) async fn direct_game_creator_codex_chat_at_with_observer( .await } -fn direct_codex_canonical_project_identity( - root: &std::path::Path, -) -> Result<(std::path::PathBuf, String), String> { - let (canonical_root, _) = resolve_direct_codex_project_authority(root)?; - let manifest = read_manifest(&canonical_root.join(".agent/manifest.json")) - .map_err(|error| format!("读取 DirectProject 权威项目身份失败:{error}"))?; - let manifest_project_id = manifest.project_id.trim(); - if manifest_project_id.is_empty() || manifest_project_id.chars().count() > 256 { - return Err("DirectProject manifest.projectId 不满足身份边界".to_string()); - } - let path_identity = direct_codex_os_path_identity_bytes(&canonical_root); - Ok(( - canonical_root, - direct_codex_project_identity_digest(&path_identity, manifest_project_id.as_bytes()), - )) -} - -fn direct_codex_os_path_identity_bytes(path: &std::path::Path) -> Vec { - #[cfg(unix)] - { - use std::os::unix::ffi::OsStrExt; - return path.as_os_str().as_bytes().to_vec(); - } - #[cfg(windows)] - { - use std::os::windows::ffi::OsStrExt; - let mut bytes = Vec::new(); - for unit in path.as_os_str().encode_wide() { - bytes.extend_from_slice(&unit.to_le_bytes()); - } - return bytes; - } - #[cfg(not(any(unix, windows)))] - path.as_os_str().to_string_lossy().as_bytes().to_vec() -} - -fn direct_codex_project_identity_digest(path_identity: &[u8], project_id: &[u8]) -> String { - let mut digest = Sha256::new(); - digest.update(b"genarrative-direct-project-identity.v1\0"); - digest.update((path_identity.len() as u64).to_le_bytes()); - digest.update(path_identity); - digest.update((project_id.len() as u64).to_le_bytes()); - digest.update(project_id); - format!("{:x}", digest.finalize()) -} - pub(crate) async fn direct_game_creator_codex_chat_at_with_optional_observer( root: &std::path::Path, system_prompt: String,