清洗附件摘要元数据
wire 投影复用附件名称与媒体类型的安全清洗。 附件项目路径输出归一化结果,避免原始控制字符进入模型提示。
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
use super::model::{DirectCodexUserContentPart, DirectCodexUserItem};
|
||||
use super::validation::validate_direct_codex_user_item;
|
||||
use crate::agent::{read_manifest_for_project, sanitize_attachment_local_path};
|
||||
use crate::agent::{
|
||||
read_manifest_for_project, sanitize_attachment_local_path, sanitize_attachment_media_type,
|
||||
sanitize_attachment_name,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -101,14 +104,15 @@ pub(crate) fn direct_codex_user_item_to_wire_input(
|
||||
summary
|
||||
}
|
||||
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!(
|
||||
"[附件:名称={};类型={};大小={} 字节",
|
||||
reference.name.trim(),
|
||||
reference.media_type.trim(),
|
||||
reference.size
|
||||
name, media_type, reference.size
|
||||
);
|
||||
if !reference.local_path.trim().is_empty() {
|
||||
summary.push_str(&format!(";项目路径={}", reference.local_path.trim()));
|
||||
if let Some(local_path) = local_path {
|
||||
summary.push_str(&format!(";项目路径={local_path}"));
|
||||
}
|
||||
summary.push_str(&format!(";状态={}", reference.status.trim()));
|
||||
summary.push(']');
|
||||
@@ -212,6 +216,36 @@ mod tests {
|
||||
assert!(content[1]["text"].as_str().unwrap().contains("notes.txt"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn attachment_metadata_is_sanitized_before_prompt_projection() {
|
||||
let root = tempfile::tempdir().expect("temp project");
|
||||
crate::init_local_game_project_at(root.path(), "wire-test", "wire 投影测试")
|
||||
.expect("init project");
|
||||
let item = json!({
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"id": "turn-1:user",
|
||||
"content": [{
|
||||
"type": "agc_attachment_reference",
|
||||
"name": "C:\\tmp\\notes\nsecret.md",
|
||||
"mediaType": "text/plain\nBearer secret",
|
||||
"size": 4,
|
||||
"localPath": "assets\\.\\notes.txt",
|
||||
"status": "imported"
|
||||
}]
|
||||
});
|
||||
let wire = super::direct_codex_user_item_to_wire_input(
|
||||
root.path(),
|
||||
&serde_json::from_value(item).expect("deserialize user item"),
|
||||
)
|
||||
.expect("attachment metadata should project");
|
||||
let text = wire[0]["text"].as_str().expect("wire text");
|
||||
assert!(text.contains("名称=notessecret.md"), "{text}");
|
||||
assert!(text.contains("类型=application/octet-stream"), "{text}");
|
||||
assert!(text.contains("项目路径=assets/notes.txt"), "{text}");
|
||||
assert!(!text.contains("Bearer secret"), "{text}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whitespace_only_text_parts_survive_validation() {
|
||||
let root = tempfile::tempdir().expect("temp project");
|
||||
|
||||
Reference in New Issue
Block a user