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 399bc45cd..b13078c13 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 @@ -1930,20 +1930,15 @@ async fn bridge_remove_background(state: &DirectToolBridgeState, arguments: &Val ); let (_operation_id, idempotency_key) = state.resource_request_ids(&fingerprint)?; let route = access.api_route("/api/external/v1/editor/images/background-removals"); - let mut request_body = json!({ - "sourceImageSrc": source_resource_id, - "projectId": manifest.project_id, - "assetKind": source_asset.kind, - "assetFolderId": context.asset_folder_id, - "assetLabel": asset_name, - "sourceResourceId": source_resource_id, - }); - if background_mode == Some("flat") { - request_body["backgroundMode"] = json!("flat"); - } - if let Some(color) = screen_color { - request_body["screenColor"] = json!(color); - } + let request_body = background_removal_request_body( + &source_resource_id, + &context.project_id, + &source_asset.kind, + &context.asset_folder_id, + &asset_name, + background_mode, + screen_color, + ); let response = crate::http_client::with_agc_main_site_marker( client .post(format!("{}{}", api_base_url, route)) @@ -1971,7 +1966,7 @@ async fn bridge_remove_background(state: &DirectToolBridgeState, arguments: &Val "status": "queued", "sourceLocalAssetId": source_asset_id, "assetName": asset_name, - "projectId": manifest.project_id, + "projectId": context.project_id, "assetFolderId": context.asset_folder_id, "queueState": bridge_safe_queue_state(queue_state), })) @@ -2001,6 +1996,32 @@ fn background_removal_request_fingerprint( } } +fn background_removal_request_body( + source_resource_id: &str, + remote_project_id: &str, + asset_kind: &str, + asset_folder_id: &str, + asset_name: &str, + background_mode: Option<&str>, + screen_color: Option<&str>, +) -> Value { + let mut body = json!({ + "sourceImageSrc": source_resource_id, + "projectId": remote_project_id, + "assetKind": asset_kind, + "assetFolderId": asset_folder_id, + "assetLabel": asset_name, + "sourceResourceId": source_resource_id, + }); + if background_mode == Some("flat") { + body["backgroundMode"] = json!("flat"); + } + if let Some(color) = screen_color { + body["screenColor"] = json!(color); + } + body +} + fn background_removal_queue_state( payload: &Value, platform_account_route: bool, @@ -3652,4 +3673,20 @@ mod tests { }) ); } + + #[test] + fn background_removal_request_uses_bound_remote_project_id() { + let body = background_removal_request_body( + "editor-resource-source", + "remote-project-1", + "character", + "remote-folder-1", + "雄狮-透明底", + Some("complex"), + None, + ); + assert_eq!(body["projectId"], "remote-project-1"); + assert_ne!(body["projectId"], "local-project-1"); + assert_eq!(body["assetFolderId"], "remote-folder-1"); + } } diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 598f4a991..2afd9c0f5 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -2,6 +2,13 @@ > 用途:记录已经确认、会影响后续开发的长期技术/产品/协作决策。短期讨论不要写在这里。 > 当前口径:历史条目的旧路径、旧版本和已退役对象只用于追溯,不构成现行实现依据;如与当前代码或 `docs/README.md` 冲突,以当前代码和最新专题文档为准。 + +## 2026-09-17 AGC 抠图提交使用远端画布项目身份 + +- 背景:AGC 已通过本地项目 ID 建立并持久化本地项目到主站远端画布项目的绑定,但 `agc_remove_background` 提交请求仍把本地 `manifest.project_id` 放入 `projectId`;`assetFolderId` 已使用远端素材目录 ID。主站因此按项目不存在或不属于当前账号返回 404,主站抠图和 BgFilter 本身均正常。 +- 决策:抠图请求及工具回执统一使用 `prepare_external_canvas_generation_context` 返回的远端 `context.project_id`;本地 manifest 项目 ID 只用于绑定键和本地状态,不得作为主站业务请求的 `projectId`。 +- 验证:客户端定向 Rust 测试、格式、编码和 diff 检查通过;未修改主站路由或 BgFilter。 + ## 2026-09-16 抠图模式与背景色契约 - External v1 抠图和 AGC `agc_remove_background` 支持 `complex`(语义分割识别前景)与 `flat`(纯色背景抠图);明确纯色背景优先 flat,模式缺省仍为 complex,主站前端保持现有行为。 diff --git a/docs/technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md b/docs/technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md index a7e9525fd..cef2b2850 100644 --- a/docs/technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md +++ b/docs/technical/【技术方案】AGC抠图模式与背景色透传-2026-09-16.md @@ -65,6 +65,8 @@ OpenAPI 与客户端工具的对外说明只描述模式用途、参数约束和 工具 schema、桥接参数校验和随包 `agc-client-projection` Skill/契约说明必须保持一致。模式与颜色属于请求意图,必须参与客户端幂等指纹;同一图片与名称的不同模式不能复用同一次请求。缺省 complex 且没有颜色时保留既有指纹。主站在默认值归一化之前计算 External 请求指纹,缺失的新字段不序列化,避免旧请求重放发生冲突。 +客户端提交前建立的本地项目绑定会返回主站远端 `projectId` 与 `assetFolderId`,抠图请求必须使用这两个远端身份;本地 manifest `projectId` 仅用于绑定和本地状态,不能直接提交给主站。 + ## 实施任务 ### 任务一:冻结 BgFilter 契约