fix: sync rust api-server runtime and bindings
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use module_puzzle::{
|
||||
PUZZLE_MAX_TAG_COUNT, PuzzleAgentMessageKind, PuzzleAgentMessageRole,
|
||||
PuzzleAgentMessageSnapshot, PuzzleAgentSessionCreateInput, PuzzleAgentSessionGetInput,
|
||||
PuzzleAgentSessionProcedureResult, PuzzleAgentSessionSnapshot, PuzzleAgentStage,
|
||||
PuzzleAnchorPack, PuzzleDraftCompileInput, PuzzleGeneratedImageCandidate,
|
||||
PUZZLE_MAX_TAG_COUNT, PuzzleAgentMessageFinalizeInput, PuzzleAgentMessageKind,
|
||||
PuzzleAgentMessageRole, PuzzleAgentMessageSnapshot, PuzzleAgentSessionCreateInput,
|
||||
PuzzleAgentSessionGetInput, PuzzleAgentSessionProcedureResult, PuzzleAgentSessionSnapshot,
|
||||
PuzzleAgentStage, PuzzleAnchorPack, PuzzleDraftCompileInput, PuzzleGeneratedImageCandidate,
|
||||
PuzzleGeneratedImagesSaveInput, PuzzlePublicationStatus, PuzzlePublishInput, PuzzleResultDraft,
|
||||
PuzzleRunDragInput, PuzzleRunGetInput, PuzzleRunNextLevelInput, PuzzleRunProcedureResult,
|
||||
PuzzleRunSnapshot, PuzzleRunStartInput, PuzzleRunSwapInput, PuzzleRuntimeLevelStatus,
|
||||
@@ -158,6 +158,25 @@ pub fn submit_puzzle_agent_message(
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn finalize_puzzle_agent_message_turn(
|
||||
ctx: &mut ProcedureContext,
|
||||
input: PuzzleAgentMessageFinalizeInput,
|
||||
) -> PuzzleAgentSessionProcedureResult {
|
||||
match ctx.try_with_tx(|tx| finalize_puzzle_agent_message_turn_tx(tx, input.clone())) {
|
||||
Ok(session) => PuzzleAgentSessionProcedureResult {
|
||||
ok: true,
|
||||
session_json: Some(serialize_json(&session)),
|
||||
error_message: None,
|
||||
},
|
||||
Err(message) => PuzzleAgentSessionProcedureResult {
|
||||
ok: false,
|
||||
session_json: None,
|
||||
error_message: Some(message),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[spacetimedb::procedure]
|
||||
pub fn compile_puzzle_agent_draft(
|
||||
ctx: &mut ProcedureContext,
|
||||
@@ -472,11 +491,9 @@ fn submit_puzzle_agent_message_tx(
|
||||
ctx: &TxContext,
|
||||
input: module_puzzle::PuzzleAgentMessageSubmitInput,
|
||||
) -> Result<PuzzleAgentSessionSnapshot, String> {
|
||||
let row = get_owned_session_row(ctx, &input.session_id, &input.owner_user_id)?;
|
||||
get_owned_session_row(ctx, &input.session_id, &input.owner_user_id)?;
|
||||
ensure_message_missing(ctx, &input.user_message_id)?;
|
||||
let submitted_at = Timestamp::from_micros_since_unix_epoch(input.submitted_at_micros);
|
||||
let next_anchor_pack = infer_anchor_pack(&row.seed_text, Some(&input.user_message_text));
|
||||
let assistant_message_text = build_puzzle_assistant_reply(&next_anchor_pack);
|
||||
|
||||
ctx.db.puzzle_agent_message().insert(PuzzleAgentMessageRow {
|
||||
message_id: input.user_message_id.clone(),
|
||||
@@ -486,19 +503,75 @@ fn submit_puzzle_agent_message_tx(
|
||||
text: input.user_message_text.clone(),
|
||||
created_at: submitted_at,
|
||||
});
|
||||
let assistant_message_id = format!(
|
||||
"{}assistant-{}",
|
||||
input.session_id, input.submitted_at_micros
|
||||
);
|
||||
|
||||
get_puzzle_agent_session_tx(
|
||||
ctx,
|
||||
PuzzleAgentSessionGetInput {
|
||||
session_id: input.session_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn finalize_puzzle_agent_message_turn_tx(
|
||||
ctx: &TxContext,
|
||||
input: PuzzleAgentMessageFinalizeInput,
|
||||
) -> Result<PuzzleAgentSessionSnapshot, String> {
|
||||
let row = get_owned_session_row(ctx, &input.session_id, &input.owner_user_id)?;
|
||||
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
|
||||
|
||||
if let Some(error_message) = input
|
||||
.error_message
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
&row,
|
||||
PuzzleAgentSessionRow {
|
||||
session_id: row.session_id.clone(),
|
||||
owner_user_id: row.owner_user_id.clone(),
|
||||
seed_text: row.seed_text.clone(),
|
||||
current_turn: row.current_turn,
|
||||
progress_percent: row.progress_percent,
|
||||
stage: row.stage,
|
||||
anchor_pack_json: row.anchor_pack_json.clone(),
|
||||
draft_json: row.draft_json.clone(),
|
||||
last_assistant_reply: row.last_assistant_reply.clone(),
|
||||
published_profile_id: row.published_profile_id.clone(),
|
||||
created_at: row.created_at,
|
||||
updated_at,
|
||||
},
|
||||
);
|
||||
return Err(error_message.to_string());
|
||||
}
|
||||
|
||||
let assistant_message_id = input
|
||||
.assistant_message_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or_else(|| "拼图 assistant_message_id 不能为空".to_string())?
|
||||
.to_string();
|
||||
let assistant_reply_text = input
|
||||
.assistant_reply_text
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or_else(|| "拼图 assistant_reply_text 不能为空".to_string())?
|
||||
.to_string();
|
||||
ensure_message_missing(ctx, &assistant_message_id)?;
|
||||
let next_anchor_pack = deserialize_anchor_pack(&input.anchor_pack_json)?;
|
||||
|
||||
ctx.db.puzzle_agent_message().insert(PuzzleAgentMessageRow {
|
||||
message_id: assistant_message_id,
|
||||
session_id: input.session_id.clone(),
|
||||
role: PuzzleAgentMessageRole::Assistant,
|
||||
kind: PuzzleAgentMessageKind::Summary,
|
||||
text: assistant_message_text.clone(),
|
||||
created_at: submitted_at,
|
||||
kind: PuzzleAgentMessageKind::Chat,
|
||||
text: assistant_reply_text.clone(),
|
||||
created_at: updated_at,
|
||||
});
|
||||
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
&row,
|
||||
@@ -507,14 +580,14 @@ fn submit_puzzle_agent_message_tx(
|
||||
owner_user_id: row.owner_user_id.clone(),
|
||||
seed_text: row.seed_text.clone(),
|
||||
current_turn: row.current_turn.saturating_add(1),
|
||||
progress_percent: (row.progress_percent + 18).min(82),
|
||||
stage: PuzzleAgentStage::CollectingAnchors,
|
||||
progress_percent: input.progress_percent.min(100),
|
||||
stage: input.stage,
|
||||
anchor_pack_json: serialize_json(&next_anchor_pack),
|
||||
draft_json: row.draft_json.clone(),
|
||||
last_assistant_reply: Some(assistant_message_text),
|
||||
last_assistant_reply: Some(assistant_reply_text),
|
||||
published_profile_id: row.published_profile_id.clone(),
|
||||
created_at: row.created_at,
|
||||
updated_at: submitted_at,
|
||||
updated_at,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -535,6 +608,15 @@ fn compile_puzzle_agent_draft_tx(
|
||||
let anchor_pack = deserialize_anchor_pack(&row.anchor_pack_json)?;
|
||||
let messages = list_session_messages(ctx, &row.session_id);
|
||||
let draft = compile_result_draft(&anchor_pack, &messages);
|
||||
// 创作中心的拼图草稿卡只是 Agent session 的列表投影,
|
||||
// 每次编译结果页时同步 upsert,保证后续能按 source_session_id 恢复聊天。
|
||||
upsert_puzzle_draft_work_profile(
|
||||
ctx,
|
||||
&row.session_id,
|
||||
&row.owner_user_id,
|
||||
&draft,
|
||||
input.compiled_at_micros,
|
||||
)?;
|
||||
let compiled_at = Timestamp::from_micros_since_unix_epoch(input.compiled_at_micros);
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
@@ -601,6 +683,14 @@ fn save_puzzle_generated_images_tx(
|
||||
} else {
|
||||
PuzzleAgentStage::ImageRefining
|
||||
};
|
||||
// 结果页草稿封面和候选图发生变化后,草稿卡需要同步刷新。
|
||||
upsert_puzzle_draft_work_profile(
|
||||
ctx,
|
||||
&row.session_id,
|
||||
&row.owner_user_id,
|
||||
&draft,
|
||||
input.saved_at_micros,
|
||||
)?;
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
&row,
|
||||
@@ -642,6 +732,14 @@ fn select_puzzle_cover_image_tx(
|
||||
} else {
|
||||
PuzzleAgentStage::ImageRefining
|
||||
};
|
||||
// 选定正式封面后,创作中心草稿卡要立即反映最新正式图。
|
||||
upsert_puzzle_draft_work_profile(
|
||||
ctx,
|
||||
&row.session_id,
|
||||
&row.owner_user_id,
|
||||
&draft,
|
||||
input.selected_at_micros,
|
||||
)?;
|
||||
replace_puzzle_agent_session(
|
||||
ctx,
|
||||
&row,
|
||||
@@ -682,9 +780,10 @@ fn publish_puzzle_work_tx(
|
||||
input.theme_tags.clone(),
|
||||
)
|
||||
.map_err(|error| error.to_string())?;
|
||||
let (work_id, profile_id) = build_puzzle_work_ids_from_session_id(&input.session_id);
|
||||
let mut profile = create_work_profile(
|
||||
input.work_id.clone(),
|
||||
input.profile_id.clone(),
|
||||
work_id,
|
||||
profile_id,
|
||||
input.owner_user_id.clone(),
|
||||
Some(input.session_id.clone()),
|
||||
input.author_display_name.clone(),
|
||||
@@ -996,6 +1095,42 @@ fn build_puzzle_work_profile_from_row(
|
||||
})
|
||||
}
|
||||
|
||||
fn build_puzzle_work_ids_from_session_id(session_id: &str) -> (String, String) {
|
||||
let stable_suffix = session_id
|
||||
.strip_prefix("puzzle-session-")
|
||||
.unwrap_or(session_id);
|
||||
(
|
||||
format!("puzzle-work-{stable_suffix}"),
|
||||
format!("puzzle-profile-{stable_suffix}"),
|
||||
)
|
||||
}
|
||||
|
||||
fn upsert_puzzle_draft_work_profile(
|
||||
ctx: &TxContext,
|
||||
session_id: &str,
|
||||
owner_user_id: &str,
|
||||
draft: &PuzzleResultDraft,
|
||||
updated_at_micros: i64,
|
||||
) -> Result<(), String> {
|
||||
let (work_id, profile_id) = build_puzzle_work_ids_from_session_id(session_id);
|
||||
if let Some(existing) = ctx.db.puzzle_work_profile().profile_id().find(&profile_id) {
|
||||
if existing.publication_status == PuzzlePublicationStatus::Published {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let profile = create_work_profile(
|
||||
work_id,
|
||||
profile_id,
|
||||
owner_user_id.to_string(),
|
||||
Some(session_id.to_string()),
|
||||
"创作者".to_string(),
|
||||
draft,
|
||||
updated_at_micros,
|
||||
)
|
||||
.map_err(|error| error.to_string())?;
|
||||
upsert_puzzle_work_profile(ctx, profile)
|
||||
}
|
||||
|
||||
fn list_session_messages(ctx: &TxContext, session_id: &str) -> Vec<PuzzleAgentMessageSnapshot> {
|
||||
let mut items = ctx
|
||||
.db
|
||||
@@ -1045,15 +1180,6 @@ fn build_puzzle_suggested_actions(
|
||||
}
|
||||
}
|
||||
|
||||
fn build_puzzle_assistant_reply(anchor_pack: &PuzzleAnchorPack) -> String {
|
||||
format!(
|
||||
"我先帮你收束成一版拼图方向:题材是“{}”,主体聚焦“{}”,氛围偏“{}”。",
|
||||
anchor_pack.theme_promise.value,
|
||||
anchor_pack.visual_subject.value,
|
||||
anchor_pack.visual_mood.value
|
||||
)
|
||||
}
|
||||
|
||||
fn append_system_message(
|
||||
ctx: &TxContext,
|
||||
session_id: &str,
|
||||
|
||||
Reference in New Issue
Block a user