明确 UI 编辑器导入与识别边界

补充结构识别、语义合并和增量导入的正式行为说明

为 Rust 与前端实现添加对应内联注释

删除已撤销计划文档的技术文档引用
This commit is contained in:
2026-08-18 15:15:59 +08:00
parent 22f61654f9
commit 26db35286e
5 changed files with 21 additions and 2 deletions
@@ -1748,6 +1748,8 @@ pub(crate) fn import_ui_editor_local_files(
enforce_project_permission_policy(root, "asset.upload")?;
let _lock = acquire_project_write_lock(root, "asset.upload")?;
advance_agent_runtime_project_revision_locked(root)?;
// V1 有意采用增量导入:每个文件独立写入并登记,后续失败不回滚此前成功项。
// 调用方必须以返回结果和 manifest 为准重建已提交集合;整批原子语义需另行定义 transaction/reconciliation 合同。
let mut inputs = Vec::new();
for source in source_paths {
let path = Path::new(source.trim());
@@ -1947,6 +1949,7 @@ pub(crate) fn import_ui_editor_local_fonts(
let font_root = root.join("assets/fonts");
fs::create_dir_all(&font_root).map_err(|_| "创建项目字体目录失败".to_string())?;
}
// 字体批次同样是增量提交合同:已经复制并登记的字体在后续失败时保留。
let mut result = Vec::with_capacity(inputs.len());
for (source_file_name, bytes, validated) in inputs {
if let Some(existing) = existing_by_hash.get(&validated.content_sha256) {
@@ -2213,6 +2216,7 @@ pub(crate) fn import_ui_editor_remote_assets(
enforce_project_permission_policy(root, "canvas.asset_import")?;
let _lock = acquire_project_write_lock(root, "canvas.asset_import")?;
advance_agent_runtime_project_revision_locked(root)?;
// 远程素材导入保持与本地图片/字体相同的增量语义,不对已成功项目文件做整批回滚。
let mut downloads = Vec::new();
for asset in assets {
let asset_id = json_string_field(&asset, "assetId")
@@ -311,6 +311,8 @@ mod materialize {
collect_original_nodes(&tree.root, *priority, &tree.src_ui_design, &mut records)?;
}
let mut occupied_ids = records.keys().cloned().collect::<HashSet<_>>();
// 合并计划是语义投影,不要求覆盖全部源节点;未引用节点表示本次合并明确丢弃。
// 这里只拒绝重复/未知引用,避免把“公共结构合并”误收紧为全量复制。
let mut used_original_ids = HashSet::new();
let built = build_node(plan, &records, &mut used_original_ids, &mut occupied_ids)?;
Ok(UITree {
@@ -280,7 +280,9 @@ fn convert_node(
allow_llm_edit_component: true,
source: NodeSource::Llm,
},
// TODO: What is let llm give component structure at recognize step ????
// V1 有意把识别结果限定为“结构草稿”:组件绑定属于后续独立阶段。
// 因此空组件不是丢失数据,而是等待 visual-binding 阶段补齐 Image/Text。
// 约定见 docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md。
components: Vec::new(),
children_display_mode: ChildrenDisplayMode::Stack,
children,
@@ -1,7 +1,10 @@
import type { RecognitionDTO } from './types/RecognitionDTO';
import type { State } from './types/State';
/** 识别结果是整棵树的替换结果,不与旧树逐节点合并。 */
/**
* 识别结果是整棵结构草稿树的替换结果,不与旧树逐节点合并。
* 识别阶段有意不携带视觉组件;组件绑定由后续 visual-binding 阶段完成。
*/
export function applyRecognitionResult(
state: State,
result: RecognitionDTO,