Merge remote-tracking branch 'origin/master' into codex/yace
# Conflicts: # .hermes/shared-memory/pitfalls.md
This commit is contained in:
@@ -459,6 +459,11 @@ fn compile_match3d_draft_tx(
|
||||
config.theme_text.as_str(),
|
||||
);
|
||||
let summary_text = resolve_compile_summary_text(&input.summary_text, existing_work.as_ref());
|
||||
let compiled_at = Timestamp::from_micros_since_unix_epoch(input.compiled_at_micros);
|
||||
let generated_item_assets_json = resolve_generated_item_assets_json_for_compile(
|
||||
input.generated_item_assets_json.as_deref(),
|
||||
existing_work.as_ref(),
|
||||
)?;
|
||||
let draft = Match3DDraftSnapshot {
|
||||
profile_id: input.profile_id.clone(),
|
||||
game_name: game_name.clone(),
|
||||
@@ -467,12 +472,9 @@ fn compile_match3d_draft_tx(
|
||||
tags: tags.clone(),
|
||||
clear_count: config.clear_count,
|
||||
difficulty: config.difficulty,
|
||||
// 中文注释:草稿响应本身也携带生成素材快照,避免 HTTP facade 回读 work 详情失败时丢失背景/容器图。
|
||||
generated_item_assets_json: generated_item_assets_json.clone(),
|
||||
};
|
||||
let compiled_at = Timestamp::from_micros_since_unix_epoch(input.compiled_at_micros);
|
||||
let generated_item_assets_json = resolve_generated_item_assets_json_for_compile(
|
||||
input.generated_item_assets_json.as_deref(),
|
||||
existing_work.as_ref(),
|
||||
)?;
|
||||
let previous_publication_status = existing_work
|
||||
.as_ref()
|
||||
.map(|work| work.publication_status.clone())
|
||||
@@ -1889,6 +1891,32 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match3d_draft_snapshot_keeps_generated_item_assets_json() {
|
||||
let draft = Match3DDraftSnapshot {
|
||||
profile_id: "profile-1".to_string(),
|
||||
game_name: "水果抓大鹅".to_string(),
|
||||
theme_text: "水果".to_string(),
|
||||
summary_text: "水果主题".to_string(),
|
||||
tags: vec!["水果".to_string()],
|
||||
clear_count: 3,
|
||||
difficulty: 3,
|
||||
generated_item_assets_json: Some(
|
||||
r#"[{"itemId":"match3d-item-1","itemName":"草莓","backgroundAsset":{"prompt":"果园背景","imageSrc":"/generated-match3d-assets/session/profile/background/background.png","containerImageSrc":"/generated-match3d-assets/session/profile/ui-container/container.png","status":"image_ready"},"status":"image_ready"}]"#
|
||||
.to_string(),
|
||||
),
|
||||
};
|
||||
|
||||
let row_json = to_json_string(&draft);
|
||||
let restored =
|
||||
parse_json::<Match3DDraftSnapshot>(&row_json, "match3d draft_json").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
restored.generated_item_assets_json.as_deref(),
|
||||
draft.generated_item_assets_json.as_deref()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match3d_work_update_preserves_assets_and_allows_empty_summary() {
|
||||
let existing = Match3DWorkProfileRow {
|
||||
|
||||
@@ -256,6 +256,8 @@ pub struct Match3DDraftSnapshot {
|
||||
pub tags: Vec<String>,
|
||||
pub clear_count: u32,
|
||||
pub difficulty: u32,
|
||||
#[serde(default)]
|
||||
pub generated_item_assets_json: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
||||
@@ -899,7 +899,10 @@ fn compile_puzzle_agent_draft_tx(
|
||||
}
|
||||
let anchor_pack = infer_anchor_pack(&row.seed_text, Some(&row.seed_text));
|
||||
let messages = list_session_messages(ctx, &row.session_id);
|
||||
let draft = compile_result_draft_from_seed(&anchor_pack, &messages, Some(&row.seed_text));
|
||||
let draft = mark_puzzle_draft_generation_status(
|
||||
compile_result_draft_from_seed(&anchor_pack, &messages, Some(&row.seed_text)),
|
||||
"generating",
|
||||
);
|
||||
// 创作中心的拼图草稿卡只是 Agent session 的列表投影,
|
||||
// 每次编译结果页时同步 upsert,保证后续能按 source_session_id 恢复聊天。
|
||||
upsert_puzzle_draft_work_profile(
|
||||
@@ -2500,10 +2503,52 @@ fn profile_for_single_level(
|
||||
level: &module_puzzle::PuzzleDraftLevel,
|
||||
) -> PuzzleWorkProfile {
|
||||
let mut next_profile = profile.clone();
|
||||
let ui_background_carrier = profile.levels.iter().find(|candidate| {
|
||||
candidate
|
||||
.ui_background_image_src
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.map(|value| !value.is_empty())
|
||||
.unwrap_or(false)
|
||||
|| candidate
|
||||
.ui_background_image_object_key
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.map(|value| !value.is_empty())
|
||||
.unwrap_or(false)
|
||||
});
|
||||
let mut single_level = level.clone();
|
||||
if single_level
|
||||
.ui_background_image_src
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.unwrap_or("")
|
||||
.is_empty()
|
||||
&& single_level
|
||||
.ui_background_image_object_key
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.unwrap_or("")
|
||||
.is_empty()
|
||||
&& let Some(carrier) = ui_background_carrier
|
||||
{
|
||||
single_level.ui_background_image_src = carrier
|
||||
.ui_background_image_src
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(str::to_string);
|
||||
single_level.ui_background_image_object_key = carrier
|
||||
.ui_background_image_object_key
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(|value| value.trim_start_matches('/').to_string());
|
||||
}
|
||||
next_profile.level_name = level.level_name.clone();
|
||||
next_profile.cover_image_src = level.cover_image_src.clone();
|
||||
next_profile.cover_asset_id = level.cover_asset_id.clone();
|
||||
next_profile.levels = vec![level.clone()];
|
||||
next_profile.levels = vec![single_level];
|
||||
next_profile
|
||||
}
|
||||
|
||||
@@ -2524,6 +2569,17 @@ fn micros_to_millis(value: i64) -> u64 {
|
||||
(value as u64).saturating_div(1_000)
|
||||
}
|
||||
|
||||
fn mark_puzzle_draft_generation_status(
|
||||
mut draft: PuzzleResultDraft,
|
||||
generation_status: &str,
|
||||
) -> PuzzleResultDraft {
|
||||
draft.generation_status = generation_status.to_string();
|
||||
for level in &mut draft.levels {
|
||||
level.generation_status = generation_status.to_string();
|
||||
}
|
||||
draft
|
||||
}
|
||||
|
||||
fn upsert_puzzle_draft_work_profile(
|
||||
ctx: &TxContext,
|
||||
session_id: &str,
|
||||
@@ -3494,6 +3550,37 @@ mod tests {
|
||||
assert!(preview.publish_ready);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puzzle_draft_generation_status_updates_all_levels() {
|
||||
let anchor_pack = infer_anchor_pack("蒸汽城市雨夜猫咪", Some("蒸汽城市雨夜猫咪"));
|
||||
let mut draft = compile_result_draft(&anchor_pack, &[]);
|
||||
draft.levels.push(module_puzzle::PuzzleDraftLevel {
|
||||
level_id: "puzzle-level-2".to_string(),
|
||||
level_name: "第二关".to_string(),
|
||||
picture_description: "第二关画面".to_string(),
|
||||
picture_reference: None,
|
||||
ui_background_prompt: None,
|
||||
ui_background_image_src: None,
|
||||
ui_background_image_object_key: None,
|
||||
background_music: None,
|
||||
candidates: Vec::new(),
|
||||
selected_candidate_id: None,
|
||||
cover_image_src: None,
|
||||
cover_asset_id: None,
|
||||
generation_status: "idle".to_string(),
|
||||
});
|
||||
|
||||
let draft = mark_puzzle_draft_generation_status(draft, "generating");
|
||||
|
||||
assert_eq!(draft.generation_status, "generating");
|
||||
assert!(
|
||||
draft
|
||||
.levels
|
||||
.iter()
|
||||
.all(|level| level.generation_status == "generating")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn puzzle_generated_images_replace_existing_candidate() {
|
||||
let anchor_pack = infer_anchor_pack("蒸汽城市雨夜猫咪", Some("蒸汽城市雨夜猫咪"));
|
||||
|
||||
@@ -215,8 +215,7 @@ fn migrate_visual_novel_entry_from_old_visible_default(ctx: &ReducerContext, now
|
||||
&& row.subtitle == "分支叙事体验"
|
||||
&& row.image_src == "/creation-type-references/visual-novel.webp"
|
||||
&& row.visible
|
||||
&& ((row.badge == "可创建" && row.open)
|
||||
|| (row.badge == "敬请期待" && !row.open))
|
||||
&& ((row.badge == "可创建" && row.open) || (row.badge == "敬请期待" && !row.open))
|
||||
&& row.sort_order == 60;
|
||||
if !still_old_visible_default {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user