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 99d4262c4..2ab90cc62 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 @@ -20,9 +20,7 @@ pub(crate) fn direct_codex_user_item_to_response_item( } let canonical: DirectCodexUserItem = serde_json::from_value(item.clone()) .map_err(|error| format!("DirectProject user item 无法转换为 Codex item:{error}"))?; - let Value::Array(content) = direct_codex_user_item_to_wire_input(root, &canonical)? else { - return Err("DirectProject user item wire content 不是数组".to_string()); - }; + let content = direct_codex_user_item_to_response_content(root, &canonical)?; let mut projected = serde_json::json!({ "type": "message", "role": "user", @@ -34,6 +32,25 @@ pub(crate) fn direct_codex_user_item_to_response_item( Ok(projected) } +fn direct_codex_user_item_to_response_content( + root: &Path, + item: &DirectCodexUserItem, +) -> Result, String> { + let Value::Array(input) = direct_codex_user_item_to_wire_input(root, item)? else { + return Err("DirectProject user item wire content 不是数组".to_string()); + }; + input + .into_iter() + .map(|part| { + let text = part + .get("text") + .and_then(Value::as_str) + .ok_or_else(|| "DirectProject user item wire part 缺少 text".to_string())?; + Ok(serde_json::json!({ "type": "input_text", "text": text })) + }) + .collect() +} + /// 将 canonical user item 转为 app-server `turn/start.input` 可接受的文本数组。 /// AGC 私有 part 只在这里投影为安全摘要,canonical item 本身不被修改。 pub(crate) fn direct_codex_user_item_to_wire_input( @@ -131,6 +148,23 @@ mod tests { ); } + #[test] + fn response_item_projection_uses_input_text_not_turn_input_text() { + 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": "input_text", "text": "你好"}] + }); + let projected = direct_codex_user_item_to_response_item(root.path(), &item) + .expect("user response item should project"); + assert_eq!(projected["content"][0]["type"], "input_text"); + assert_ne!(projected["content"][0]["type"], "text"); + } + #[test] fn history_item_without_type_fails_closed() { let error = direct_codex_user_item_to_response_item(