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 6b148deed..6923b0761 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 @@ -1161,6 +1161,8 @@ fn bridge_registered_resource( "localPath": asset.local_path, "kind": asset.kind, "mediaType": asset.media_type, + "category": asset.category, + "tags": asset.tags, "canvasProjectId": asset.source.canvas_project_id, "resourceId": asset.source.resource_id, "assetObjectId": asset.source.asset_object_id, @@ -2867,6 +2869,8 @@ mod tests { projection["imageSequenceFrames"][0]["objectKey"], "animations/frame-01.png" ); + assert_eq!(projection["category"], "character"); + assert_eq!(projection["tags"], json!([])); let serialized = projection.to_string(); assert!(!serialized.contains("signed.invalid")); assert!(!serialized.contains("private prompt")); @@ -2874,6 +2878,42 @@ mod tests { assert!(!serialized.contains("private.invalid")); } + #[test] + fn bridge_registered_resource_projects_manifest_classification_verbatim() { + let asset = GameCreationAppAssetManifestEntry { + id: "spec-1".to_string(), + kind: "spec".to_string(), + media_type: "application/json".to_string(), + local_path: "assets/specs/hero.json".to_string(), + image_sequence_frames: None, + image_sequence_duration_ms: None, + category: + shared_contracts::game_creation_app::GameCreationAppAssetCategory::UiInteraction, + tags: vec!["主角".to_string(), "第一版".to_string()], + source: GameCreationAppAssetSource { + kind: GameCreationAppAssetSourceKind::Generated, + canvas_project_id: None, + resource_id: None, + asset_object_id: None, + task_id: None, + prompt: Some("private prompt".to_string()), + model: Some("private model".to_string()), + generation_route: None, + generation_kind: None, + reference_resource_ids: Vec::new(), + }, + }; + + let projection = bridge_registered_resource(&asset, false); + assert_eq!(projection["kind"], "spec"); + assert_eq!(projection["category"], "ui-interaction"); + assert_eq!(projection["tags"], json!(["主角", "第一版"])); + assert_eq!(projection["imageSequenceFrames"], Value::Null); + let serialized = projection.to_string(); + assert!(!serialized.contains("private prompt")); + assert!(!serialized.contains("private model")); + } + #[test] fn bridge_success_warnings_are_redacted_before_serialization() { let root = tempfile::tempdir().expect("warning redaction root"); diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs index 3dde7a64a..11e028cb4 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tools_mcp.rs @@ -256,7 +256,7 @@ fn direct_tools_mcp_specs_for(controlled_web_search: bool) -> Value { }), json!({ "name": "agc_list_registered_assets", - "description": "查询当前项目由客户端权威 manifest 登记的资源与未完成资源 operation。结果有界且只包含项目相对路径、稳定资源身份、序列帧身份和恢复状态,不返回 prompt、模型、签名 URL、宿主路径或凭据。", + "description": "查询当前项目由客户端权威 manifest 登记的资源与未完成资源 operation。结果有界且只包含项目相对路径、稳定资源身份、功能分类与自定义标签、序列帧身份和恢复状态,不返回 prompt、模型、签名 URL、宿主路径或凭据。", "inputSchema": { "type": "object", "properties": {