This commit is contained in:
2026-04-24 12:21:33 +08:00
parent 3528980645
commit 70b5a7cf73
515 changed files with 14971 additions and 6831 deletions

View File

@@ -74,7 +74,10 @@ pub(crate) fn build_ai_task_snapshot_from_row(
}
}
pub(crate) fn build_ai_task_stage_row(task_id: &str, snapshot: &AiTaskStageSnapshot) -> AiTaskStage {
pub(crate) fn build_ai_task_stage_row(
task_id: &str,
snapshot: &AiTaskStageSnapshot,
) -> AiTaskStage {
AiTaskStage {
task_stage_id: generate_ai_task_stage_id(task_id, snapshot.stage_kind),
task_id: task_id.to_string(),

View File

@@ -1,5 +1,8 @@
use crate::*;
use module_ai::{generate_ai_result_ref_id, generate_ai_text_chunk_id, normalize_optional_text, normalize_string_list};
use module_ai::{
generate_ai_result_ref_id, generate_ai_text_chunk_id, normalize_optional_text,
normalize_string_list,
};
#[spacetimedb::table(
accessor = ai_task_stage,
@@ -184,7 +187,9 @@ pub(crate) fn append_ai_text_chunk_tx(
delta_text: input.delta_text.trim().to_string(),
created_at_micros: input.created_at_micros,
};
ctx.db.ai_text_chunk().insert(build_ai_text_chunk_row(&chunk));
ctx.db
.ai_text_chunk()
.insert(build_ai_text_chunk_row(&chunk));
let aggregated_text = collect_ai_stage_text_output(ctx, &chunk.task_id, chunk.stage_kind);

View File

@@ -1,5 +1,5 @@
use crate::*;
use module_ai::{normalize_optional_text, validate_task_create_input, INITIAL_AI_TASK_VERSION};
use module_ai::{INITIAL_AI_TASK_VERSION, normalize_optional_text, validate_task_create_input};
#[spacetimedb::table(
accessor = ai_task,

View File

@@ -84,6 +84,25 @@ pub fn submit_big_fish_message(
}
}
#[spacetimedb::procedure]
pub fn finalize_big_fish_agent_message_turn(
ctx: &mut ProcedureContext,
input: BigFishMessageFinalizeInput,
) -> BigFishSessionProcedureResult {
match ctx.try_with_tx(|tx| finalize_big_fish_agent_message_turn_tx(tx, input.clone())) {
Ok(session) => BigFishSessionProcedureResult {
ok: true,
session: Some(session),
error_message: None,
},
Err(message) => BigFishSessionProcedureResult {
ok: false,
session: None,
error_message: Some(message),
},
}
}
#[spacetimedb::procedure]
pub fn compile_big_fish_draft(
ctx: &mut ProcedureContext,
@@ -247,17 +266,103 @@ pub(crate) fn submit_big_fish_message_tx(
created_at: submitted_at,
});
let anchor_pack = infer_anchor_pack(&session.seed_text, Some(&input.user_message_text));
let assistant_text =
"我已经把这版方向收束成 4 个高杠杆锚点,可以继续细化,也可以直接编译第一版玩法草稿。"
.to_string();
let next_session = BigFishCreationSession {
session_id: session.session_id.clone(),
owner_user_id: session.owner_user_id.clone(),
seed_text: session.seed_text.clone(),
current_turn: session.current_turn,
progress_percent: session.progress_percent,
stage: BigFishCreationStage::CollectingAnchors,
anchor_pack_json: session.anchor_pack_json.clone(),
draft_json: session.draft_json.clone(),
asset_coverage_json: session.asset_coverage_json.clone(),
last_assistant_reply: session.last_assistant_reply.clone(),
publish_ready: session.publish_ready,
created_at: session.created_at,
updated_at: submitted_at,
};
replace_big_fish_session(ctx, &session, next_session);
get_big_fish_session_tx(
ctx,
BigFishSessionGetInput {
session_id: input.session_id,
owner_user_id: input.owner_user_id,
},
)
}
pub(crate) fn finalize_big_fish_agent_message_turn_tx(
ctx: &ReducerContext,
input: BigFishMessageFinalizeInput,
) -> Result<BigFishSessionSnapshot, String> {
validate_message_finalize_input(&input).map_err(|error| error.to_string())?;
let session = ctx
.db
.big_fish_creation_session()
.session_id()
.find(&input.session_id)
.filter(|row| row.owner_user_id == input.owner_user_id)
.ok_or_else(|| "big_fish_creation_session 不存在".to_string())?;
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())
{
let next_session = BigFishCreationSession {
session_id: session.session_id.clone(),
owner_user_id: session.owner_user_id.clone(),
seed_text: session.seed_text.clone(),
current_turn: session.current_turn,
progress_percent: session.progress_percent,
stage: session.stage,
anchor_pack_json: session.anchor_pack_json.clone(),
draft_json: session.draft_json.clone(),
asset_coverage_json: session.asset_coverage_json.clone(),
last_assistant_reply: session.last_assistant_reply.clone(),
publish_ready: session.publish_ready,
created_at: session.created_at,
updated_at,
};
replace_big_fish_session(ctx, &session, next_session);
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(|| "big_fish 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(|| "big_fish assistant_reply_text 不能为空".to_string())?
.to_string();
if ctx
.db
.big_fish_agent_message()
.message_id()
.find(&assistant_message_id)
.is_some()
{
return Err("big_fish_agent_message.assistant_message_id 已存在".to_string());
}
let next_anchor_pack =
deserialize_anchor_pack(&input.anchor_pack_json).map_err(|error| error.to_string())?;
ctx.db.big_fish_agent_message().insert(BigFishAgentMessage {
message_id: input.assistant_message_id,
message_id: assistant_message_id,
session_id: input.session_id.clone(),
role: BigFishAgentMessageRole::Assistant,
kind: BigFishAgentMessageKind::Summary,
text: assistant_text.clone(),
created_at: submitted_at,
kind: BigFishAgentMessageKind::Chat,
text: assistant_reply_text.clone(),
created_at: updated_at,
});
let next_session = BigFishCreationSession {
@@ -265,15 +370,16 @@ pub(crate) fn submit_big_fish_message_tx(
owner_user_id: session.owner_user_id.clone(),
seed_text: session.seed_text.clone(),
current_turn: session.current_turn.saturating_add(1),
progress_percent: 60,
stage: BigFishCreationStage::CollectingAnchors,
anchor_pack_json: serialize_anchor_pack(&anchor_pack).map_err(|error| error.to_string())?,
progress_percent: input.progress_percent.min(100),
stage: input.stage,
anchor_pack_json: serialize_anchor_pack(&next_anchor_pack)
.map_err(|error| error.to_string())?,
draft_json: session.draft_json.clone(),
asset_coverage_json: session.asset_coverage_json.clone(),
last_assistant_reply: Some(assistant_text),
last_assistant_reply: Some(assistant_reply_text),
publish_ready: session.publish_ready,
created_at: session.created_at,
updated_at: submitted_at,
updated_at,
};
replace_big_fish_session(ctx, &session, next_session);

File diff suppressed because it is too large Load Diff

View File

@@ -1746,7 +1746,6 @@ pub fn turn_in_quest(ctx: &ReducerContext, input: QuestTurnInInput) -> Result<()
Ok(())
}
// M5 Stage 2 先把 library profile upsert 固定成最小正式写入口;已发布作品在这里同步刷新 gallery 投影。
#[spacetimedb::reducer]
pub fn upsert_custom_world_profile(
@@ -2023,7 +2022,6 @@ pub fn execute_custom_world_agent_action(
}
}
// Stage 3 先把 published profile compile 作为独立 procedure 暴露,避免把编译逻辑和表写入、发布动作强耦合。
#[spacetimedb::procedure]
pub fn compile_custom_world_published_profile(

View File

@@ -224,8 +224,9 @@ pub(crate) fn resume_profile_save_archive_record(
ctx: &ReducerContext,
input: RuntimeProfileSaveArchiveResumeInput,
) -> Result<(RuntimeProfileSaveArchiveSnapshot, RuntimeSnapshot), String> {
let validated_input = build_runtime_profile_save_archive_resume_input(input.user_id, input.world_key)
.map_err(|error| error.to_string())?;
let validated_input =
build_runtime_profile_save_archive_resume_input(input.user_id, input.world_key)
.map_err(|error| error.to_string())?;
let archive = ctx
.db
.profile_save_archive()

View File

@@ -202,7 +202,8 @@ pub(crate) fn build_runtime_snapshot_from_row(row: &RuntimeSnapshotRow) -> Runti
}
pub(crate) fn parse_json_str(raw: &str) -> Result<JsonValue, String> {
serde_json::from_str::<JsonValue>(raw).map_err(|error| format!("game_state_json 解析失败: {error}"))
serde_json::from_str::<JsonValue>(raw)
.map_err(|error| format!("game_state_json 解析失败: {error}"))
}
pub(crate) fn parse_optional_json_str(raw: Option<&str>) -> Result<Option<JsonValue>, String> {