From c5a738646583d2cd8a766df465b994cdfc748073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Sat, 19 Sep 2026 23:32:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E9=99=84=E4=BB=B6=E6=91=98?= =?UTF-8?q?=E8=A6=81=E7=9A=84=E6=B8=85=E6=B4=97=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs 抽出 attachment_reference_summary,turn 输入与 history/prompt 投影共用同一份摘要 - 原先 direct_codex_user_item_to_codex_turn_input 自己拼摘要,跳过了 sanitize_attachment_name/media_type/local_path,模型侧可能收到 C:\tmp\notes.md 这类原始路径名,而历史投影里是清洗过的 - cargo test user_item:24 passed;cargo check 通过 --- .../src/agent/direct_codex_user_item/wire.rs | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs index 021db31f6..06a62dffa 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs @@ -1,5 +1,6 @@ use super::model::{ - DirectCodexUserContentPart, DirectCodexUserItem, DirectCodexUserRuntimeRegionPart, + DirectCodexUserAttachmentReferencePart, DirectCodexUserContentPart, DirectCodexUserItem, + DirectCodexUserRuntimeRegionPart, }; use super::validation::validate_direct_codex_user_item; use crate::agent::{ @@ -97,6 +98,25 @@ fn runtime_region_summary(reference: &DirectCodexUserRuntimeRegionPart) -> Strin summary } +/// 附件引用的安全摘要。 +/// +/// turn 输入与 history/prompt 投影共用这一份清洗:文件名取 basename 并去控制字符、 +/// media type 与项目路径同样过白名单,避免两条路径对同一个引用给出不同摘要。 +fn attachment_reference_summary(reference: &DirectCodexUserAttachmentReferencePart) -> String { + let name = sanitize_attachment_name(&reference.name); + let media_type = sanitize_attachment_media_type(&reference.media_type); + let mut summary = format!( + "[附件:名称={name};类型={media_type};大小={} 字节", + reference.size + ); + if let Some(local_path) = sanitize_attachment_local_path(&reference.local_path) { + summary.push_str(&format!(";项目路径={local_path}")); + } + summary.push_str(&format!(";状态={}", reference.status.trim())); + summary.push(']'); + summary +} + /// 将 canonical user item 转为 app-server `turn/start.input` 可接受的文本数组。 /// AGC 私有 part 只在这里投影为安全摘要,canonical item 本身不被修改。 pub(crate) fn direct_codex_user_item_to_wire_input( @@ -120,19 +140,7 @@ pub(crate) fn direct_codex_user_item_to_wire_input( runtime_region_summary(reference) } DirectCodexUserContentPart::AgcAttachmentReference(reference) => { - let name = sanitize_attachment_name(&reference.name); - let media_type = sanitize_attachment_media_type(&reference.media_type); - let local_path = sanitize_attachment_local_path(&reference.local_path); - let mut summary = format!( - "[附件:名称={};类型={};大小={} 字节", - name, media_type, reference.size - ); - if let Some(local_path) = local_path { - summary.push_str(&format!(";项目路径={local_path}")); - } - summary.push_str(&format!(";状态={}", reference.status.trim())); - summary.push(']'); - summary + attachment_reference_summary(reference) } }; input.push(serde_json::json!({ "type": "text", "text": text })); @@ -179,20 +187,9 @@ pub(crate) fn direct_codex_user_item_to_codex_turn_input( })); } DirectCodexUserContentPart::AgcAttachmentReference(reference) => { - let mut summary = format!( - "[附件:名称={};类型={};大小={} 字节", - reference.name.trim(), - reference.media_type.trim(), - reference.size - ); - if !reference.local_path.trim().is_empty() { - summary.push_str(&format!(";项目路径={}", reference.local_path.trim())); - } - summary.push_str(&format!(";状态={}", reference.status.trim())); - summary.push(']'); input.push(serde_json::json!({ "type": "text", - "text": summary, + "text": attachment_reference_summary(reference), })); } }