fix: sync rust api-server runtime and bindings
This commit is contained in:
@@ -995,15 +995,14 @@ fn upsert_custom_world_profile_record(
|
||||
.find(&input.profile_id)
|
||||
.filter(|row| row.owner_user_id == input.owner_user_id)
|
||||
.or_else(|| {
|
||||
input.source_agent_session_id.as_ref().and_then(|session_id| {
|
||||
ctx.db.custom_world_profile().iter().find(|row| {
|
||||
is_same_agent_draft_profile_candidate(
|
||||
row,
|
||||
&input.owner_user_id,
|
||||
session_id,
|
||||
)
|
||||
input
|
||||
.source_agent_session_id
|
||||
.as_ref()
|
||||
.and_then(|session_id| {
|
||||
ctx.db.custom_world_profile().iter().find(|row| {
|
||||
is_same_agent_draft_profile_candidate(row, &input.owner_user_id, session_id)
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
let next_row = match current {
|
||||
@@ -1432,18 +1431,16 @@ fn list_custom_world_work_snapshots(
|
||||
|
||||
let mut items = Vec::new();
|
||||
|
||||
for session in ctx
|
||||
.db
|
||||
.custom_world_agent_session()
|
||||
.iter()
|
||||
.filter(|row| row.owner_user_id == input.owner_user_id && row.stage != RpgAgentStage::Published)
|
||||
{
|
||||
for session in ctx.db.custom_world_agent_session().iter().filter(|row| {
|
||||
row.owner_user_id == input.owner_user_id && row.stage != RpgAgentStage::Published
|
||||
}) {
|
||||
let gate = build_custom_world_publish_gate_from_session(&session);
|
||||
let draft_profile = parse_optional_session_object(session.draft_profile_json.as_deref());
|
||||
let title = resolve_session_work_title(&session, draft_profile.as_ref());
|
||||
let summary = resolve_session_work_summary(&session, draft_profile.as_ref());
|
||||
let stage_label = Some(resolve_rpg_agent_stage_label(session.stage).to_string());
|
||||
let subtitle = resolve_session_work_subtitle(draft_profile.as_ref(), stage_label.as_deref());
|
||||
let subtitle =
|
||||
resolve_session_work_subtitle(draft_profile.as_ref(), stage_label.as_deref());
|
||||
let (playable_npc_count, landmark_count) =
|
||||
resolve_session_work_counts(ctx, &session, draft_profile.as_ref());
|
||||
|
||||
@@ -1516,8 +1513,16 @@ fn list_custom_world_work_snapshots(
|
||||
.updated_at_micros
|
||||
.cmp(&left.updated_at_micros)
|
||||
.then_with(|| {
|
||||
let left_rank = if left.source_type == "agent_session" { 0 } else { 1 };
|
||||
let right_rank = if right.source_type == "agent_session" { 0 } else { 1 };
|
||||
let left_rank = if left.source_type == "agent_session" {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let right_rank = if right.source_type == "agent_session" {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
left_rank.cmp(&right_rank)
|
||||
})
|
||||
.then(left.work_id.cmp(&right.work_id))
|
||||
@@ -1578,7 +1583,9 @@ fn execute_custom_world_agent_action_tx(
|
||||
match input.action.trim() {
|
||||
"draft_foundation" => execute_draft_foundation_action(ctx, &session, &input, &payload),
|
||||
"update_draft_card" => execute_update_draft_card_action(ctx, &session, &input, &payload),
|
||||
"sync_result_profile" => execute_sync_result_profile_action(ctx, &session, &input, &payload),
|
||||
"sync_result_profile" => {
|
||||
execute_sync_result_profile_action(ctx, &session, &input, &payload)
|
||||
}
|
||||
"publish_world" => execute_publish_world_action(ctx, &session, &input, &payload),
|
||||
"revert_checkpoint" => execute_revert_checkpoint_action(ctx, &session, &input, &payload),
|
||||
"generate_characters"
|
||||
@@ -1603,18 +1610,16 @@ fn execute_draft_foundation_action(
|
||||
}
|
||||
|
||||
let updated_at = input.submitted_at_micros;
|
||||
let draft_profile = if let Some(profile) = payload.get("draftProfile").and_then(JsonValue::as_object) {
|
||||
profile.clone()
|
||||
} else if let Some(existing) = parse_optional_session_object(session.draft_profile_json.as_deref()) {
|
||||
ensure_minimal_draft_profile(existing, &session.seed_text)
|
||||
} else {
|
||||
build_minimal_draft_profile_from_seed(&session.seed_text)
|
||||
};
|
||||
|
||||
let draft_profile_json =
|
||||
serde_json::to_string(&JsonValue::Object(draft_profile.clone())).map_err(|error| {
|
||||
format!("draft_foundation 无法序列化 draft_profile_json: {error}")
|
||||
let draft_profile = payload
|
||||
.get("draftProfile")
|
||||
.and_then(JsonValue::as_object)
|
||||
.cloned()
|
||||
.ok_or_else(|| {
|
||||
"draft_foundation requires externally generated payload.draftProfile".to_string()
|
||||
})?;
|
||||
|
||||
let draft_profile_json = serde_json::to_string(&JsonValue::Object(draft_profile.clone()))
|
||||
.map_err(|error| format!("draft_foundation 无法序列化 draft_profile_json: {error}"))?;
|
||||
let gate = summarize_publish_gate_from_json(
|
||||
&input.session_id,
|
||||
RpgAgentStage::ObjectRefining,
|
||||
@@ -1627,8 +1632,12 @@ fn execute_draft_foundation_action(
|
||||
progress_percent: Some(100),
|
||||
stage: Some(RpgAgentStage::ObjectRefining),
|
||||
draft_profile_json: Some(Some(draft_profile_json.clone())),
|
||||
last_assistant_reply: Some(Some("世界底稿已整理完成,接下来可以继续细化卡片和发布预览。".to_string())),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(&gate))?)),
|
||||
last_assistant_reply: Some(Some(
|
||||
"世界底稿已整理完成,接下来可以继续细化卡片和发布预览。".to_string(),
|
||||
)),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(
|
||||
&gate,
|
||||
))?)),
|
||||
result_preview_json: Some(build_result_preview_json(
|
||||
Some(&draft_profile),
|
||||
&gate,
|
||||
@@ -1675,7 +1684,8 @@ fn execute_update_draft_card_action(
|
||||
) -> Result<CustomWorldAgentOperationSnapshot, String> {
|
||||
ensure_refining_stage(session.stage, "update_draft_card")?;
|
||||
|
||||
let card_id = read_required_payload_text(payload, "cardId", "update_draft_card requires cardId")?;
|
||||
let card_id =
|
||||
read_required_payload_text(payload, "cardId", "update_draft_card requires cardId")?;
|
||||
let card = ctx
|
||||
.db
|
||||
.custom_world_draft_card()
|
||||
@@ -1691,7 +1701,8 @@ fn execute_update_draft_card_action(
|
||||
return Err("update_draft_card requires sections".to_string());
|
||||
}
|
||||
|
||||
let mut detail_object = parse_optional_session_object(card.detail_payload_json.as_deref()).unwrap_or_default();
|
||||
let mut detail_object =
|
||||
parse_optional_session_object(card.detail_payload_json.as_deref()).unwrap_or_default();
|
||||
let mut detail_sections = detail_object
|
||||
.get("sections")
|
||||
.and_then(JsonValue::as_array)
|
||||
@@ -1735,27 +1746,36 @@ fn execute_update_draft_card_action(
|
||||
}
|
||||
|
||||
detail_object.insert("id".to_string(), JsonValue::String(card.card_id.clone()));
|
||||
detail_object.insert("kind".to_string(), JsonValue::String(card.kind.as_str().to_string()));
|
||||
detail_object.insert(
|
||||
"kind".to_string(),
|
||||
JsonValue::String(card.kind.as_str().to_string()),
|
||||
);
|
||||
detail_object.insert("title".to_string(), JsonValue::String(card.title.clone()));
|
||||
detail_object.insert("sections".to_string(), JsonValue::Array(detail_sections.clone()));
|
||||
detail_object.insert(
|
||||
"sections".to_string(),
|
||||
JsonValue::Array(detail_sections.clone()),
|
||||
);
|
||||
detail_object.insert(
|
||||
"linkedIds".to_string(),
|
||||
serde_json::from_str::<JsonValue>(&card.linked_ids_json).unwrap_or_else(|_| JsonValue::Array(Vec::new())),
|
||||
serde_json::from_str::<JsonValue>(&card.linked_ids_json)
|
||||
.unwrap_or_else(|_| JsonValue::Array(Vec::new())),
|
||||
);
|
||||
detail_object.insert("locked".to_string(), JsonValue::Bool(false));
|
||||
detail_object.insert("editable".to_string(), JsonValue::Bool(false));
|
||||
detail_object.insert("editableSectionIds".to_string(), JsonValue::Array(Vec::new()));
|
||||
detail_object.insert(
|
||||
"editableSectionIds".to_string(),
|
||||
JsonValue::Array(Vec::new()),
|
||||
);
|
||||
detail_object.insert("warningMessages".to_string(), JsonValue::Array(Vec::new()));
|
||||
|
||||
let updated_title = extract_detail_section_value(&detail_sections, "title").unwrap_or_else(|| card.title.clone());
|
||||
let updated_subtitle =
|
||||
extract_detail_section_value(&detail_sections, "subtitle").unwrap_or_else(|| card.subtitle.clone());
|
||||
let updated_summary =
|
||||
extract_detail_section_value(&detail_sections, "summary").unwrap_or_else(|| card.summary.clone());
|
||||
let detail_payload_json =
|
||||
serde_json::to_string(&JsonValue::Object(detail_object)).map_err(|error| {
|
||||
format!("update_draft_card 无法序列化 detail_payload_json: {error}")
|
||||
})?;
|
||||
let updated_title = extract_detail_section_value(&detail_sections, "title")
|
||||
.unwrap_or_else(|| card.title.clone());
|
||||
let updated_subtitle = extract_detail_section_value(&detail_sections, "subtitle")
|
||||
.unwrap_or_else(|| card.subtitle.clone());
|
||||
let updated_summary = extract_detail_section_value(&detail_sections, "summary")
|
||||
.unwrap_or_else(|| card.summary.clone());
|
||||
let detail_payload_json = serde_json::to_string(&JsonValue::Object(detail_object))
|
||||
.map_err(|error| format!("update_draft_card 无法序列化 detail_payload_json: {error}"))?;
|
||||
|
||||
replace_custom_world_draft_card(
|
||||
ctx,
|
||||
@@ -1778,7 +1798,14 @@ fn execute_update_draft_card_action(
|
||||
},
|
||||
);
|
||||
|
||||
let next_session = sync_session_draft_profile_from_card_update(session, &card, &updated_title, &updated_subtitle, &updated_summary, input.submitted_at_micros)?;
|
||||
let next_session = sync_session_draft_profile_from_card_update(
|
||||
session,
|
||||
&card,
|
||||
&updated_title,
|
||||
&updated_subtitle,
|
||||
&updated_summary,
|
||||
input.submitted_at_micros,
|
||||
)?;
|
||||
replace_custom_world_agent_session(ctx, session, next_session);
|
||||
|
||||
append_custom_world_action_result_message(
|
||||
@@ -1816,7 +1843,10 @@ fn execute_sync_result_profile_action(
|
||||
.ok_or_else(|| "sync_result_profile requires profile".to_string())?;
|
||||
if let Some(stable_profile_id) = resolve_stable_agent_draft_profile_id(session) {
|
||||
// 结果页回写时必须沿用当前草稿的稳定身份,避免把同一草稿写成新条目。
|
||||
profile.insert("id".to_string(), JsonValue::String(stable_profile_id.clone()));
|
||||
profile.insert(
|
||||
"id".to_string(),
|
||||
JsonValue::String(stable_profile_id.clone()),
|
||||
);
|
||||
upsert_nested_result_profile_id(&mut profile, &stable_profile_id);
|
||||
}
|
||||
let draft_profile = ensure_minimal_draft_profile(profile, &session.seed_text);
|
||||
@@ -1830,9 +1860,13 @@ fn execute_sync_result_profile_action(
|
||||
let next_session = rebuild_custom_world_agent_session_row(
|
||||
session,
|
||||
CustomWorldAgentSessionPatch {
|
||||
draft_profile_json: Some(Some(serialize_json_value(&JsonValue::Object(draft_profile.clone()))?)),
|
||||
draft_profile_json: Some(Some(serialize_json_value(&JsonValue::Object(
|
||||
draft_profile.clone(),
|
||||
))?)),
|
||||
last_assistant_reply: Some(Some("结果页草稿已同步回当前会话。".to_string())),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(&gate))?)),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(
|
||||
&gate,
|
||||
))?)),
|
||||
result_preview_json: Some(build_result_preview_json(
|
||||
Some(&draft_profile),
|
||||
&gate,
|
||||
@@ -1871,12 +1905,14 @@ fn execute_sync_result_profile_action(
|
||||
}
|
||||
|
||||
fn resolve_stable_agent_draft_profile_id(session: &CustomWorldAgentSession) -> Option<String> {
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref()).and_then(|profile| {
|
||||
read_optional_text_field(&profile, &["legacyResultProfile.id", "id"])
|
||||
})
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.and_then(|profile| read_optional_text_field(&profile, &["legacyResultProfile.id", "id"]))
|
||||
}
|
||||
|
||||
fn upsert_nested_result_profile_id(profile: &mut JsonMap<String, JsonValue>, stable_profile_id: &str) {
|
||||
fn upsert_nested_result_profile_id(
|
||||
profile: &mut JsonMap<String, JsonValue>,
|
||||
stable_profile_id: &str,
|
||||
) {
|
||||
let legacy_result_profile = profile
|
||||
.entry("legacyResultProfile".to_string())
|
||||
.or_insert_with(|| JsonValue::Object(JsonMap::new()));
|
||||
@@ -1907,12 +1943,13 @@ fn execute_publish_world_action(
|
||||
) -> Result<CustomWorldAgentOperationSnapshot, String> {
|
||||
ensure_publishable_stage(session.stage, "publish_world")?;
|
||||
|
||||
let draft_profile = if let Some(explicit) = payload.get("draftProfile").and_then(JsonValue::as_object) {
|
||||
explicit.clone()
|
||||
} else {
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.ok_or_else(|| "publish_world requires draft_profile_json".to_string())?
|
||||
};
|
||||
let draft_profile =
|
||||
if let Some(explicit) = payload.get("draftProfile").and_then(JsonValue::as_object) {
|
||||
explicit.clone()
|
||||
} else {
|
||||
parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.ok_or_else(|| "publish_world requires draft_profile_json".to_string())?
|
||||
};
|
||||
let gate = summarize_publish_gate_from_json(
|
||||
&session.session_id,
|
||||
session.stage,
|
||||
@@ -1972,7 +2009,10 @@ fn execute_publish_world_action(
|
||||
&session.session_id,
|
||||
RpgAgentOperationType::PublishWorld,
|
||||
"世界已发布",
|
||||
&format!("正式世界档案已写入作品库:{}。", publish_result.1.profile_id),
|
||||
&format!(
|
||||
"正式世界档案已写入作品库:{}。",
|
||||
publish_result.1.profile_id
|
||||
),
|
||||
input.submitted_at_micros,
|
||||
);
|
||||
|
||||
@@ -2046,9 +2086,15 @@ fn execute_revert_checkpoint_action(
|
||||
.map(|value| serialize_json_value(&JsonValue::Object(value.clone())))
|
||||
.transpose()?,
|
||||
),
|
||||
last_assistant_reply: Some(Some("已恢复到所选 checkpoint 的世界草稿状态。".to_string())),
|
||||
quality_findings_json: Some(serialize_json_value(&JsonValue::Array(restored_quality_findings))?),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(&gate))?)),
|
||||
last_assistant_reply: Some(Some(
|
||||
"已恢复到所选 checkpoint 的世界草稿状态。".to_string(),
|
||||
)),
|
||||
quality_findings_json: Some(serialize_json_value(&JsonValue::Array(
|
||||
restored_quality_findings,
|
||||
))?),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(
|
||||
&gate,
|
||||
))?)),
|
||||
result_preview_json: Some(build_result_preview_json(
|
||||
restored_draft_profile.as_ref(),
|
||||
&gate,
|
||||
@@ -2099,7 +2145,10 @@ fn execute_placeholder_custom_world_action(
|
||||
ctx,
|
||||
&session.session_id,
|
||||
&input.operation_id,
|
||||
&format!("动作 {} 已接入最小兼容占位,后续会继续补真实编排。", input.action),
|
||||
&format!(
|
||||
"动作 {} 已接入最小兼容占位,后续会继续补真实编排。",
|
||||
input.action
|
||||
),
|
||||
input.submitted_at_micros,
|
||||
);
|
||||
let operation = build_and_insert_custom_world_operation(
|
||||
@@ -2201,7 +2250,8 @@ fn summarize_publish_gate_from_json(
|
||||
blockers.push(CustomWorldPublishBlockerSnapshot {
|
||||
blocker_id: "publish_missing_player_premise".to_string(),
|
||||
code: "publish_missing_player_premise".to_string(),
|
||||
message: "当前世界缺少玩家身份与切入前提,发布前需要先补齐玩家 premise。".to_string(),
|
||||
message: "当前世界缺少玩家身份与切入前提,发布前需要先补齐玩家 premise。"
|
||||
.to_string(),
|
||||
});
|
||||
}
|
||||
if !json_array_has_non_empty_text(profile.get("coreConflicts")) {
|
||||
@@ -2342,8 +2392,10 @@ fn build_supported_actions_json(
|
||||
let has_checkpoint = checkpoints
|
||||
.iter()
|
||||
.any(|entry| entry.get("snapshot").is_some());
|
||||
let draft_refining_enabled =
|
||||
matches!(stage, RpgAgentStage::ObjectRefining | RpgAgentStage::VisualRefining);
|
||||
let draft_refining_enabled = matches!(
|
||||
stage,
|
||||
RpgAgentStage::ObjectRefining | RpgAgentStage::VisualRefining
|
||||
);
|
||||
let long_tail_enabled = matches!(
|
||||
stage,
|
||||
RpgAgentStage::ObjectRefining
|
||||
@@ -2462,8 +2514,10 @@ fn build_custom_world_draft_card_detail_snapshot(
|
||||
card: &CustomWorldDraftCard,
|
||||
) -> Result<CustomWorldDraftCardDetailSnapshot, String> {
|
||||
if let Some(detail_payload_json) = card.detail_payload_json.as_deref() {
|
||||
let detail_value = serde_json::from_str::<JsonValue>(detail_payload_json)
|
||||
.map_err(|error| format!("custom_world_draft_card.detail_payload_json 非法: {error}"))?;
|
||||
let detail_value =
|
||||
serde_json::from_str::<JsonValue>(detail_payload_json).map_err(|error| {
|
||||
format!("custom_world_draft_card.detail_payload_json 非法: {error}")
|
||||
})?;
|
||||
if let Some(object) = detail_value.as_object() {
|
||||
let sections = object
|
||||
.get("sections")
|
||||
@@ -2501,8 +2555,14 @@ fn build_custom_world_draft_card_detail_snapshot(
|
||||
.to_string(),
|
||||
sections,
|
||||
linked_ids_json: card.linked_ids_json.clone(),
|
||||
locked: object.get("locked").and_then(JsonValue::as_bool).unwrap_or(false),
|
||||
editable: object.get("editable").and_then(JsonValue::as_bool).unwrap_or(false),
|
||||
locked: object
|
||||
.get("locked")
|
||||
.and_then(JsonValue::as_bool)
|
||||
.unwrap_or(false),
|
||||
editable: object
|
||||
.get("editable")
|
||||
.and_then(JsonValue::as_bool)
|
||||
.unwrap_or(false),
|
||||
editable_section_ids_json: serialize_json_value(
|
||||
object
|
||||
.get("editableSectionIds")
|
||||
@@ -2534,7 +2594,9 @@ fn build_custom_world_draft_card_detail_snapshot(
|
||||
})
|
||||
}
|
||||
|
||||
fn build_fallback_card_sections(card: &CustomWorldDraftCard) -> Vec<CustomWorldDraftCardDetailSectionSnapshot> {
|
||||
fn build_fallback_card_sections(
|
||||
card: &CustomWorldDraftCard,
|
||||
) -> Vec<CustomWorldDraftCardDetailSectionSnapshot> {
|
||||
vec![
|
||||
CustomWorldDraftCardDetailSectionSnapshot {
|
||||
section_id: "title".to_string(),
|
||||
@@ -2578,7 +2640,9 @@ fn rebuild_custom_world_agent_session_row(
|
||||
current_turn: current.current_turn,
|
||||
progress_percent: patch.progress_percent.unwrap_or(current.progress_percent),
|
||||
stage: patch.stage.unwrap_or(current.stage),
|
||||
focus_card_id: patch.focus_card_id.unwrap_or_else(|| current.focus_card_id.clone()),
|
||||
focus_card_id: patch
|
||||
.focus_card_id
|
||||
.unwrap_or_else(|| current.focus_card_id.clone()),
|
||||
anchor_content_json: patch
|
||||
.anchor_content_json
|
||||
.unwrap_or_else(|| current.anchor_content_json.clone()),
|
||||
@@ -2588,8 +2652,12 @@ fn rebuild_custom_world_agent_session_row(
|
||||
creator_intent_readiness_json: patch
|
||||
.creator_intent_readiness_json
|
||||
.unwrap_or_else(|| current.creator_intent_readiness_json.clone()),
|
||||
anchor_pack_json: patch.anchor_pack_json.unwrap_or_else(|| current.anchor_pack_json.clone()),
|
||||
lock_state_json: patch.lock_state_json.unwrap_or_else(|| current.lock_state_json.clone()),
|
||||
anchor_pack_json: patch
|
||||
.anchor_pack_json
|
||||
.unwrap_or_else(|| current.anchor_pack_json.clone()),
|
||||
lock_state_json: patch
|
||||
.lock_state_json
|
||||
.unwrap_or_else(|| current.lock_state_json.clone()),
|
||||
draft_profile_json: patch
|
||||
.draft_profile_json
|
||||
.unwrap_or_else(|| current.draft_profile_json.clone()),
|
||||
@@ -2741,7 +2809,8 @@ fn upsert_world_foundation_card(
|
||||
status: RpgAgentDraftCardStatus::Confirmed,
|
||||
title: read_optional_text_field(draft_profile, &["name", "title"])
|
||||
.unwrap_or_else(|| "世界底稿".to_string()),
|
||||
subtitle: read_optional_text_field(draft_profile, &["subtitle"]).unwrap_or_default(),
|
||||
subtitle: read_optional_text_field(draft_profile, &["subtitle"])
|
||||
.unwrap_or_default(),
|
||||
summary: read_optional_text_field(draft_profile, &["summary"])
|
||||
.unwrap_or_else(|| "第一版世界底稿已生成。".to_string()),
|
||||
linked_ids_json: "[]".to_string(),
|
||||
@@ -2754,24 +2823,27 @@ fn upsert_world_foundation_card(
|
||||
},
|
||||
);
|
||||
} else {
|
||||
ctx.db.custom_world_draft_card().insert(CustomWorldDraftCard {
|
||||
card_id,
|
||||
session_id: session_id.to_string(),
|
||||
kind: RpgAgentDraftCardKind::World,
|
||||
status: RpgAgentDraftCardStatus::Confirmed,
|
||||
title: read_optional_text_field(draft_profile, &["name", "title"])
|
||||
.unwrap_or_else(|| "世界底稿".to_string()),
|
||||
subtitle: read_optional_text_field(draft_profile, &["subtitle"]).unwrap_or_default(),
|
||||
summary: read_optional_text_field(draft_profile, &["summary"])
|
||||
.unwrap_or_else(|| "第一版世界底稿已生成。".to_string()),
|
||||
linked_ids_json: "[]".to_string(),
|
||||
warning_count: 0,
|
||||
asset_status: None,
|
||||
asset_status_label: None,
|
||||
detail_payload_json: Some(detail_payload_json),
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
});
|
||||
ctx.db
|
||||
.custom_world_draft_card()
|
||||
.insert(CustomWorldDraftCard {
|
||||
card_id,
|
||||
session_id: session_id.to_string(),
|
||||
kind: RpgAgentDraftCardKind::World,
|
||||
status: RpgAgentDraftCardStatus::Confirmed,
|
||||
title: read_optional_text_field(draft_profile, &["name", "title"])
|
||||
.unwrap_or_else(|| "世界底稿".to_string()),
|
||||
subtitle: read_optional_text_field(draft_profile, &["subtitle"])
|
||||
.unwrap_or_default(),
|
||||
summary: read_optional_text_field(draft_profile, &["summary"])
|
||||
.unwrap_or_else(|| "第一版世界底稿已生成。".to_string()),
|
||||
linked_ids_json: "[]".to_string(),
|
||||
warning_count: 0,
|
||||
asset_status: None,
|
||||
asset_status_label: None,
|
||||
detail_payload_json: Some(detail_payload_json),
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(updated_at_micros),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -2788,7 +2860,10 @@ fn sync_session_draft_profile_from_card_update(
|
||||
let mut draft_profile = parse_optional_session_object(session.draft_profile_json.as_deref())
|
||||
.unwrap_or_else(|| build_minimal_draft_profile_from_seed(&session.seed_text));
|
||||
if card.kind == RpgAgentDraftCardKind::World {
|
||||
draft_profile.insert("name".to_string(), JsonValue::String(updated_title.to_string()));
|
||||
draft_profile.insert(
|
||||
"name".to_string(),
|
||||
JsonValue::String(updated_title.to_string()),
|
||||
);
|
||||
draft_profile.insert(
|
||||
"subtitle".to_string(),
|
||||
JsonValue::String(updated_subtitle.to_string()),
|
||||
@@ -2808,8 +2883,12 @@ fn sync_session_draft_profile_from_card_update(
|
||||
rebuild_custom_world_agent_session_row(
|
||||
session,
|
||||
CustomWorldAgentSessionPatch {
|
||||
draft_profile_json: Some(Some(serialize_json_value(&JsonValue::Object(draft_profile.clone()))?)),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(&gate))?)),
|
||||
draft_profile_json: Some(Some(serialize_json_value(&JsonValue::Object(
|
||||
draft_profile.clone(),
|
||||
))?)),
|
||||
publish_gate_json: Some(Some(serialize_json_value(&publish_gate_to_json_value(
|
||||
&gate,
|
||||
))?)),
|
||||
result_preview_json: Some(build_result_preview_json(
|
||||
Some(&draft_profile),
|
||||
&gate,
|
||||
@@ -2824,7 +2903,10 @@ fn sync_session_draft_profile_from_card_update(
|
||||
}
|
||||
|
||||
fn ensure_refining_stage(stage: RpgAgentStage, action: &str) -> Result<(), String> {
|
||||
if matches!(stage, RpgAgentStage::ObjectRefining | RpgAgentStage::VisualRefining) {
|
||||
if matches!(
|
||||
stage,
|
||||
RpgAgentStage::ObjectRefining | RpgAgentStage::VisualRefining
|
||||
) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
@@ -2933,10 +3015,7 @@ fn read_required_payload_text(
|
||||
.ok_or_else(|| error_message.to_string())
|
||||
}
|
||||
|
||||
fn read_optional_text_field(
|
||||
object: &JsonMap<String, JsonValue>,
|
||||
keys: &[&str],
|
||||
) -> Option<String> {
|
||||
fn read_optional_text_field(object: &JsonMap<String, JsonValue>, keys: &[&str]) -> Option<String> {
|
||||
for key in keys {
|
||||
let mut current = JsonValue::Object(object.clone());
|
||||
let mut found = true;
|
||||
@@ -2949,7 +3028,11 @@ fn read_optional_text_field(
|
||||
}
|
||||
}
|
||||
if found {
|
||||
if let Some(value) = current.as_str().map(str::trim).filter(|value| !value.is_empty()) {
|
||||
if let Some(value) = current
|
||||
.as_str()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
return Some(value.to_string());
|
||||
}
|
||||
}
|
||||
@@ -3144,21 +3227,28 @@ fn append_checkpoint_json(current: &str, checkpoint: &JsonValue) -> Result<Strin
|
||||
fn extract_detail_section_value(sections: &[JsonValue], target_id: &str) -> Option<String> {
|
||||
sections.iter().find_map(|entry| {
|
||||
let object = entry.as_object()?;
|
||||
(object.get("id").and_then(JsonValue::as_str) == Some(target_id))
|
||||
.then(|| {
|
||||
object
|
||||
.get("value")
|
||||
.and_then(JsonValue::as_str)
|
||||
.unwrap_or_default()
|
||||
.to_string()
|
||||
})
|
||||
(object.get("id").and_then(JsonValue::as_str) == Some(target_id)).then(|| {
|
||||
object
|
||||
.get("value")
|
||||
.and_then(JsonValue::as_str)
|
||||
.unwrap_or_default()
|
||||
.to_string()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn json_array_has_non_empty_text(value: Option<&JsonValue>) -> bool {
|
||||
value
|
||||
.and_then(JsonValue::as_array)
|
||||
.map(|entries| entries.iter().any(|entry| entry.as_str().map(str::trim).filter(|text| !text.is_empty()).is_some()))
|
||||
.map(|entries| {
|
||||
entries.iter().any(|entry| {
|
||||
entry
|
||||
.as_str()
|
||||
.map(str::trim)
|
||||
.filter(|text| !text.is_empty())
|
||||
.is_some()
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -3341,12 +3431,14 @@ fn build_custom_world_agent_session_snapshot(
|
||||
recommended_replies_json: row.recommended_replies_json.clone(),
|
||||
asset_coverage_json: row.asset_coverage_json.clone(),
|
||||
checkpoints_json: row.checkpoints_json.clone(),
|
||||
supported_actions_json: serialize_json_value(&JsonValue::Array(build_supported_actions_json(
|
||||
row.stage,
|
||||
row.progress_percent,
|
||||
&build_custom_world_publish_gate_from_session(row),
|
||||
&parse_json_array_or_empty(&row.checkpoints_json),
|
||||
)))
|
||||
supported_actions_json: serialize_json_value(&JsonValue::Array(
|
||||
build_supported_actions_json(
|
||||
row.stage,
|
||||
row.progress_percent,
|
||||
&build_custom_world_publish_gate_from_session(row),
|
||||
&parse_json_array_or_empty(&row.checkpoints_json),
|
||||
),
|
||||
))
|
||||
.unwrap_or_else(|_| "[]".to_string()),
|
||||
messages,
|
||||
draft_cards,
|
||||
|
||||
Reference in New Issue
Block a user