diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs index 4c791e640..00940673a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs @@ -2900,12 +2900,16 @@ fn generate_image_grid_axis( fn bridge_image_generation_kind( arguments: &Value, ) -> Result { - let kind = arguments - .get("kind") - .and_then(Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .unwrap_or("image"); + // 缺省与显式 null 用 schema 声明的默认值;给了别的类型不许静默当 image。 + let kind = match arguments.get("kind") { + None | Some(Value::Null) => "image", + Some(Value::String(value)) => value.trim(), + Some(value) => { + return Err(GenerateImageError::KindNotText { + got: value.to_string(), + }) + } + }; normalize_platform_art_asset_generation_kind(kind).ok_or_else(|| { GenerateImageError::KindUnsupported { got: kind.to_string(), @@ -4860,6 +4864,40 @@ mod tests { #[test] fn non_text_field_values_report_a_type_error_instead_of_an_empty_value() { + let kind_not_text = match generate_image_input(&json!({ + "prompt": "像素风主角", + "kind": true + })) { + Ok(_) => panic!("kind 不是字符串时必须被拒绝"), + Err(error) => error.to_user_msg(), + }; + assert!( + kind_not_text.contains("kind 必须是字符串"), + "{kind_not_text}" + ); + + let kind_empty = match generate_image_input(&json!({ + "prompt": "像素风主角", + "kind": "" + })) { + Ok(_) => panic!("空 kind 必须被拒绝,不能再静默当 image"), + Err(error) => error.to_user_msg(), + }; + assert!(kind_empty.contains("不是受支持的素材类型"), "{kind_empty}"); + + assert_eq!( + generate_image_input(&json!({ "prompt": "像素风主角" })) + .map(|input| input.kind) + .expect("缺省 kind 仍默认 image"), + GameCreationAppAssetKind::Image + ); + assert_eq!( + generate_image_input(&json!({ "prompt": "像素风主角", "kind": null })) + .map(|input| input.kind) + .expect("显式 null 仍按默认 image"), + GameCreationAppAssetKind::Image + ); + let trailing_newline = match resource_generation_input(&json!({ "kind": "video", "mode": "create", diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/tool/generate_image/error.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/tool/generate_image/error.rs index 847c35299..2bf337653 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/tool/generate_image/error.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/tool/generate_image/error.rs @@ -20,6 +20,7 @@ pub(crate) enum GenerateImageError { PromptTooLong { got_chars: usize, max_chars: usize }, PromptHasControlCharacters, PromptNotText { got: String }, + KindNotText { got: String }, KindUnsupported { got: String }, AspectRatioEmpty, AspectRatioTooLong { got_chars: usize, max_chars: usize }, @@ -83,6 +84,9 @@ impl ToolFailure for GenerateImageError { Self::PromptNotText { got } => format!( "生成图片失败:prompt 必须是字符串,当前是「{got}」。" ), + Self::KindNotText { got } => { + format!("生成图片失败:kind 必须是字符串,当前是「{got}」。") + } Self::KindUnsupported { got } => format!( "生成图片失败:kind「{got}」不是受支持的素材类型,只允许 {}。", platform_art_asset_generation_kind_list()