Close DDD cleanup and tests-support closure
This commit is contained in:
@@ -1,3 +1,957 @@
|
||||
//! 自定义世界应用编排过渡落位。
|
||||
//! 自定义世界应用规则。
|
||||
//!
|
||||
//! 这里只组合领域规则并返回草稿、发布门禁、投影刷新等结果或事件。
|
||||
//! 这里只组合纯领域校验、草稿编译、profile 归一化和默认 JSON 结构,不承接外部副作用。
|
||||
|
||||
use crate::{commands::*, domain::*, errors::CustomWorldFieldError};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub fn validate_custom_world_profile_fields(
|
||||
profile_id: &str,
|
||||
owner_user_id: &str,
|
||||
world_name: &str,
|
||||
profile_payload_json: &str,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if world_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingWorldName);
|
||||
}
|
||||
if profile_payload_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfilePayloadJson);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_published_profile_compile_input(
|
||||
input: &CustomWorldPublishedProfileCompileInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.draft_profile_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingDraftProfileJson);
|
||||
}
|
||||
if input.setting_text.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSettingText);
|
||||
}
|
||||
if input.author_display_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAuthorDisplayName);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_publish_world_input(
|
||||
input: &CustomWorldPublishWorldInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.author_public_user_code.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
validate_custom_world_published_profile_compile_input(
|
||||
&CustomWorldPublishedProfileCompileInput {
|
||||
session_id: input.session_id.clone(),
|
||||
profile_id: input.profile_id.clone(),
|
||||
owner_user_id: input.owner_user_id.clone(),
|
||||
draft_profile_json: input.draft_profile_json.clone(),
|
||||
legacy_result_profile_json: input.legacy_result_profile_json.clone(),
|
||||
setting_text: input.setting_text.clone(),
|
||||
author_display_name: input.author_display_name.clone(),
|
||||
updated_at_micros: input.published_at_micros,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_profile_upsert_input(
|
||||
input: &CustomWorldProfileUpsertInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
validate_custom_world_profile_fields(
|
||||
&input.profile_id,
|
||||
&input.owner_user_id,
|
||||
&input.world_name,
|
||||
&input.profile_payload_json,
|
||||
)?;
|
||||
|
||||
if input.author_display_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAuthorDisplayName);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_profile_publish_input(
|
||||
input: &CustomWorldProfilePublishInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.author_display_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAuthorDisplayName);
|
||||
}
|
||||
if input.author_public_user_code.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_profile_unpublish_input(
|
||||
input: &CustomWorldProfileUnpublishInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.author_display_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAuthorDisplayName);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_profile_delete_input(
|
||||
input: &CustomWorldProfileDeleteInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_profile_list_input(
|
||||
input: &CustomWorldProfileListInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_library_detail_input(
|
||||
input: &CustomWorldLibraryDetailInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_gallery_detail_input(
|
||||
input: &CustomWorldGalleryDetailInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_gallery_detail_by_code_input(
|
||||
input: &CustomWorldGalleryDetailByCodeInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.public_work_code.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingPublicWorkCode);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_session_fields(
|
||||
session_id: &str,
|
||||
owner_user_id: &str,
|
||||
setting_text: &str,
|
||||
question_snapshot_json: &str,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if setting_text.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSettingText);
|
||||
}
|
||||
if question_snapshot_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingQuestionSnapshotJson);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_session_fields(
|
||||
session_id: &str,
|
||||
owner_user_id: &str,
|
||||
anchor_content_json: &str,
|
||||
creator_intent_readiness_json: &str,
|
||||
pending_clarifications_json: &str,
|
||||
asset_coverage_json: &str,
|
||||
progress_percent: u32,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if anchor_content_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAnchorContentJson);
|
||||
}
|
||||
if creator_intent_readiness_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingCreatorIntentReadinessJson);
|
||||
}
|
||||
if pending_clarifications_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingPendingClarificationsJson);
|
||||
}
|
||||
if asset_coverage_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAssetCoverageJson);
|
||||
}
|
||||
if progress_percent > MAX_PROGRESS_PERCENT {
|
||||
return Err(CustomWorldFieldError::InvalidProgressPercent);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_session_create_input(
|
||||
input: &CustomWorldAgentSessionCreateInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
validate_custom_world_agent_session_fields(
|
||||
&input.session_id,
|
||||
&input.owner_user_id,
|
||||
&input.anchor_content_json,
|
||||
&input.creator_intent_readiness_json,
|
||||
&input.pending_clarifications_json,
|
||||
&input.asset_coverage_json,
|
||||
0,
|
||||
)?;
|
||||
|
||||
validate_custom_world_agent_message_fields(
|
||||
&input.welcome_message_id,
|
||||
&input.session_id,
|
||||
&input.welcome_message_text,
|
||||
)?;
|
||||
ensure_json_object(&input.anchor_content_json)?;
|
||||
ensure_optional_json_object(input.creator_intent_json.as_deref())?;
|
||||
ensure_json_object(&input.creator_intent_readiness_json)?;
|
||||
ensure_optional_json_object(input.anchor_pack_json.as_deref())?;
|
||||
ensure_optional_json_object(input.lock_state_json.as_deref())?;
|
||||
ensure_optional_json_object(input.draft_profile_json.as_deref())?;
|
||||
ensure_json_array(&input.pending_clarifications_json)?;
|
||||
ensure_json_array(&input.suggested_actions_json)?;
|
||||
ensure_json_array(&input.recommended_replies_json)?;
|
||||
ensure_json_array(&input.quality_findings_json)?;
|
||||
ensure_json_object(&input.asset_coverage_json)?;
|
||||
ensure_json_array(&input.checkpoints_json)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_session_get_input(
|
||||
input: &CustomWorldAgentSessionGetInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_message_submit_input(
|
||||
input: &CustomWorldAgentMessageSubmitInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
validate_custom_world_agent_message_fields(
|
||||
&input.user_message_id,
|
||||
&input.session_id,
|
||||
&input.user_message_text,
|
||||
)?;
|
||||
validate_custom_world_agent_operation_fields(
|
||||
&input.operation_id,
|
||||
&input.session_id,
|
||||
"消息已处理",
|
||||
MAX_PROGRESS_PERCENT,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_message_finalize_input(
|
||||
input: &CustomWorldAgentMessageFinalizeInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
match input.operation_status {
|
||||
RpgAgentOperationStatus::Completed => {
|
||||
validate_custom_world_agent_message_fields(
|
||||
input.assistant_message_id.as_deref().unwrap_or_default(),
|
||||
&input.session_id,
|
||||
input.assistant_reply_text.as_deref().unwrap_or_default(),
|
||||
)?;
|
||||
}
|
||||
RpgAgentOperationStatus::Failed => {}
|
||||
_ => {
|
||||
validate_custom_world_agent_message_fields(
|
||||
input.assistant_message_id.as_deref().unwrap_or_default(),
|
||||
&input.session_id,
|
||||
input.assistant_reply_text.as_deref().unwrap_or_default(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
validate_custom_world_agent_operation_fields(
|
||||
&input.operation_id,
|
||||
&input.session_id,
|
||||
&input.phase_label,
|
||||
input.operation_progress,
|
||||
)?;
|
||||
validate_custom_world_agent_session_fields(
|
||||
&input.session_id,
|
||||
&input.owner_user_id,
|
||||
&input.anchor_content_json,
|
||||
&input.creator_intent_readiness_json,
|
||||
&input.pending_clarifications_json,
|
||||
&input.asset_coverage_json,
|
||||
input.progress_percent,
|
||||
)?;
|
||||
ensure_json_object(&input.anchor_content_json)?;
|
||||
ensure_optional_json_object(input.creator_intent_json.as_deref())?;
|
||||
ensure_json_object(&input.creator_intent_readiness_json)?;
|
||||
ensure_optional_json_object(input.anchor_pack_json.as_deref())?;
|
||||
ensure_optional_json_object(input.draft_profile_json.as_deref())?;
|
||||
ensure_json_array(&input.pending_clarifications_json)?;
|
||||
ensure_json_array(&input.suggested_actions_json)?;
|
||||
ensure_json_array(&input.recommended_replies_json)?;
|
||||
ensure_json_array(&input.quality_findings_json)?;
|
||||
ensure_json_object(&input.asset_coverage_json)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_operation_get_input(
|
||||
input: &CustomWorldAgentOperationGetInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.operation_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOperationId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_operation_progress_input(
|
||||
input: &CustomWorldAgentOperationProgressInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
validate_custom_world_agent_operation_get_input(&CustomWorldAgentOperationGetInput {
|
||||
session_id: input.session_id.clone(),
|
||||
owner_user_id: input.owner_user_id.clone(),
|
||||
operation_id: input.operation_id.clone(),
|
||||
})?;
|
||||
validate_custom_world_agent_operation_fields(
|
||||
&input.operation_id,
|
||||
&input.session_id,
|
||||
&input.phase_label,
|
||||
input.operation_progress,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_works_list_input(
|
||||
input: &CustomWorldWorksListInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_card_detail_get_input(
|
||||
input: &CustomWorldAgentCardDetailGetInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if input.session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if input.owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if input.card_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingCardId);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_action_execute_input(
|
||||
input: &CustomWorldAgentActionExecuteInput,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
validate_custom_world_agent_operation_get_input(&CustomWorldAgentOperationGetInput {
|
||||
session_id: input.session_id.clone(),
|
||||
owner_user_id: input.owner_user_id.clone(),
|
||||
operation_id: input.operation_id.clone(),
|
||||
})?;
|
||||
if input.action.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAction);
|
||||
}
|
||||
ensure_optional_json_object(input.payload_json.as_deref())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_message_fields(
|
||||
message_id: &str,
|
||||
session_id: &str,
|
||||
text: &str,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if message_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingMessageId);
|
||||
}
|
||||
if session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if text.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingMessageText);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_agent_operation_fields(
|
||||
operation_id: &str,
|
||||
session_id: &str,
|
||||
phase_label: &str,
|
||||
progress: u32,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if operation_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOperationId);
|
||||
}
|
||||
if session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if phase_label.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingPhaseLabel);
|
||||
}
|
||||
if progress > MAX_PROGRESS_PERCENT {
|
||||
return Err(CustomWorldFieldError::InvalidProgressPercent);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_draft_card_fields(
|
||||
card_id: &str,
|
||||
session_id: &str,
|
||||
title: &str,
|
||||
summary: &str,
|
||||
linked_ids_json: &str,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if card_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingCardId);
|
||||
}
|
||||
if session_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingSessionId);
|
||||
}
|
||||
if title.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingCardTitle);
|
||||
}
|
||||
if summary.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingCardSummary);
|
||||
}
|
||||
if linked_ids_json.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingLinkedIdsJson);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_custom_world_gallery_entry_fields(
|
||||
profile_id: &str,
|
||||
owner_user_id: &str,
|
||||
author_display_name: &str,
|
||||
world_name: &str,
|
||||
) -> Result<(), CustomWorldFieldError> {
|
||||
if profile_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingProfileId);
|
||||
}
|
||||
if owner_user_id.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingOwnerUserId);
|
||||
}
|
||||
if author_display_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingAuthorDisplayName);
|
||||
}
|
||||
if world_name.trim().is_empty() {
|
||||
return Err(CustomWorldFieldError::MissingWorldName);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_custom_world_published_profile_compile_snapshot(
|
||||
input: CustomWorldPublishedProfileCompileInput,
|
||||
) -> Result<CustomWorldPublishedProfileCompileSnapshot, CustomWorldFieldError> {
|
||||
validate_custom_world_published_profile_compile_input(&input)?;
|
||||
|
||||
let draft = parse_required_json_object(
|
||||
&input.draft_profile_json,
|
||||
CustomWorldFieldError::InvalidDraftProfileJson,
|
||||
)?;
|
||||
let legacy = parse_optional_json_object(
|
||||
input.legacy_result_profile_json.clone(),
|
||||
CustomWorldFieldError::InvalidLegacyResultProfileJson,
|
||||
)?;
|
||||
|
||||
let world_name = resolve_text_field(&draft, &legacy, "name")
|
||||
.ok_or(CustomWorldFieldError::MissingWorldName)?;
|
||||
let subtitle = resolve_text_field(&draft, &legacy, "subtitle").unwrap_or_default();
|
||||
let summary_text = resolve_text_field(&draft, &legacy, "summary").unwrap_or_default();
|
||||
let cover_image_src = resolve_cover_image_src(&draft, &legacy);
|
||||
let theme_mode = resolve_theme_mode(&legacy);
|
||||
let playable_npc_count =
|
||||
count_distinct_roles(draft.get("playableNpcs"), draft.get("storyNpcs"));
|
||||
let landmark_count = to_array(draft.get("landmarks")).len() as u32;
|
||||
|
||||
let compiled_payload_json = build_compiled_profile_payload_json(
|
||||
&input,
|
||||
&draft,
|
||||
&legacy,
|
||||
&world_name,
|
||||
&subtitle,
|
||||
&summary_text,
|
||||
)?;
|
||||
|
||||
Ok(CustomWorldPublishedProfileCompileSnapshot {
|
||||
profile_id: input.profile_id,
|
||||
owner_user_id: input.owner_user_id,
|
||||
world_name,
|
||||
subtitle,
|
||||
summary_text,
|
||||
theme_mode,
|
||||
cover_image_src,
|
||||
playable_npc_count,
|
||||
landmark_count,
|
||||
author_display_name: input.author_display_name,
|
||||
compiled_profile_payload_json: compiled_payload_json,
|
||||
updated_at_micros: input.updated_at_micros,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn canonicalize_custom_world_profile_before_save(profile: &mut Value) -> bool {
|
||||
let Some(object) = profile.as_object_mut() else {
|
||||
return false;
|
||||
};
|
||||
let foundation_text = build_creator_intent_foundation_text(object.get("creatorIntent"))
|
||||
.trim()
|
||||
.to_string();
|
||||
if foundation_text.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let current_setting_text = object
|
||||
.get("settingText")
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.unwrap_or_default();
|
||||
if current_setting_text == foundation_text {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 中文注释:保存与 session 同步前统一以后端 creatorIntent 锚点重建 settingText,
|
||||
// 避免浏览器继续持有正式 profile canonicalize 规则。
|
||||
object.insert("settingText".to_string(), Value::String(foundation_text));
|
||||
true
|
||||
}
|
||||
|
||||
pub fn empty_agent_anchor_content_json() -> String {
|
||||
r#"{"worldPromise":null,"playerFantasy":null,"themeBoundary":null,"playerEntryPoint":null,"coreConflict":null,"keyRelationships":null,"hiddenLines":null,"iconicElements":null}"#.to_string()
|
||||
}
|
||||
|
||||
pub fn empty_agent_creator_intent_readiness_json() -> String {
|
||||
r#"{"isReady":false,"completedKeys":[],"missingKeys":[]}"#.to_string()
|
||||
}
|
||||
|
||||
pub fn empty_agent_asset_coverage_json() -> String {
|
||||
r#"{"roleAssets":[],"sceneAssets":[],"allRoleAssetsReady":false,"allSceneAssetsReady":false}"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn empty_json_object() -> String {
|
||||
"{}".to_string()
|
||||
}
|
||||
|
||||
pub fn empty_json_array() -> String {
|
||||
"[]".to_string()
|
||||
}
|
||||
|
||||
pub fn normalize_optional_json_slice(value: Option<String>) -> Option<String> {
|
||||
value.and_then(|value| {
|
||||
let value = value.trim().to_string();
|
||||
if value.is_empty() { None } else { Some(value) }
|
||||
})
|
||||
}
|
||||
|
||||
fn ensure_json_object(value: &str) -> Result<(), CustomWorldFieldError> {
|
||||
match serde_json::from_str::<Value>(value) {
|
||||
Ok(Value::Object(_)) => Ok(()),
|
||||
_ => Err(CustomWorldFieldError::InvalidJsonPayload),
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_optional_json_object(value: Option<&str>) -> Result<(), CustomWorldFieldError> {
|
||||
match value.map(str::trim).filter(|value| !value.is_empty()) {
|
||||
Some(value) => ensure_json_object(value),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_json_array(value: &str) -> Result<(), CustomWorldFieldError> {
|
||||
match serde_json::from_str::<Value>(value) {
|
||||
Ok(Value::Array(_)) => Ok(()),
|
||||
_ => Err(CustomWorldFieldError::InvalidJsonPayload),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_required_json_object(
|
||||
value: &str,
|
||||
error: CustomWorldFieldError,
|
||||
) -> Result<Map<String, Value>, CustomWorldFieldError> {
|
||||
match serde_json::from_str::<Value>(value) {
|
||||
Ok(Value::Object(object)) => Ok(object),
|
||||
_ => Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_optional_json_object(
|
||||
value: Option<String>,
|
||||
error: CustomWorldFieldError,
|
||||
) -> Result<Map<String, Value>, CustomWorldFieldError> {
|
||||
match normalize_optional_json_slice(value) {
|
||||
Some(value) => parse_required_json_object(&value, error),
|
||||
None => Ok(Map::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_text(value: Option<&Value>) -> Option<String> {
|
||||
match value {
|
||||
Some(Value::String(value)) => {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(trimmed.to_string())
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_array(value: Option<&Value>) -> Vec<Value> {
|
||||
match value {
|
||||
Some(Value::Array(items)) => items.clone(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_object(value: Option<&Value>) -> Option<Map<String, Value>> {
|
||||
match value {
|
||||
Some(Value::Object(object)) => Some(object.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_creator_intent_foundation_text(value: Option<&Value>) -> String {
|
||||
let Some(intent) = value.and_then(Value::as_object) else {
|
||||
return String::new();
|
||||
};
|
||||
if !has_meaningful_creator_intent(intent) {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let relationship_text = intent
|
||||
.get("keyCharacters")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|items| items.first())
|
||||
.and_then(Value::as_object)
|
||||
.map(build_creator_intent_relationship_text)
|
||||
.unwrap_or_default();
|
||||
let player_opening_text = [
|
||||
read_text(intent, "playerPremise"),
|
||||
read_text(intent, "openingSituation"),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.join(";");
|
||||
let theme_tone_text = [
|
||||
read_string_list(intent, "themeKeywords").join("、"),
|
||||
read_string_list(intent, "toneDirectives").join("、"),
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|value| !value.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" / ");
|
||||
|
||||
[
|
||||
build_anchor_line(
|
||||
"世界一句话",
|
||||
read_text(intent, "worldHook").unwrap_or_default(),
|
||||
),
|
||||
build_anchor_line("玩家开局", player_opening_text),
|
||||
build_anchor_line("主题气质", theme_tone_text),
|
||||
build_anchor_line(
|
||||
"核心冲突",
|
||||
read_string_list(intent, "coreConflicts").join(";"),
|
||||
),
|
||||
build_anchor_line("关键关系", relationship_text),
|
||||
build_anchor_line(
|
||||
"标志元素",
|
||||
read_string_list(intent, "iconicElements").join("、"),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|value| !value.is_empty())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
fn has_meaningful_creator_intent(intent: &Map<String, Value>) -> bool {
|
||||
[
|
||||
"rawSettingText",
|
||||
"worldHook",
|
||||
"playerPremise",
|
||||
"openingSituation",
|
||||
]
|
||||
.iter()
|
||||
.any(|key| read_text(intent, key).is_some())
|
||||
|| [
|
||||
"themeKeywords",
|
||||
"toneDirectives",
|
||||
"coreConflicts",
|
||||
"iconicElements",
|
||||
"forbiddenDirectives",
|
||||
]
|
||||
.iter()
|
||||
.any(|key| !read_string_list(intent, key).is_empty())
|
||||
|| ["keyFactions", "keyCharacters", "keyLandmarks"]
|
||||
.iter()
|
||||
.any(|key| has_meaningful_creator_seed_array(intent.get(*key)))
|
||||
}
|
||||
|
||||
fn build_creator_intent_relationship_text(character: &Map<String, Value>) -> String {
|
||||
[
|
||||
read_text(character, "name"),
|
||||
read_text(character, "role"),
|
||||
read_text(character, "relationToPlayer").map(|value| format!("与玩家 {value}")),
|
||||
read_text(character, "hiddenHook").map(|value| format!("暗线 {value}")),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" · ")
|
||||
}
|
||||
|
||||
fn build_anchor_line(label: &str, content: String) -> String {
|
||||
if content.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("{label}:{content}")
|
||||
}
|
||||
}
|
||||
|
||||
fn read_text(object: &Map<String, Value>, key: &str) -> Option<String> {
|
||||
object
|
||||
.get(key)
|
||||
.and_then(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
fn read_string_list(object: &Map<String, Value>, key: &str) -> Vec<String> {
|
||||
object
|
||||
.get(key)
|
||||
.and_then(Value::as_array)
|
||||
.map(|items| {
|
||||
items
|
||||
.iter()
|
||||
.filter_map(Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn has_meaningful_creator_seed_array(value: Option<&Value>) -> bool {
|
||||
value.and_then(Value::as_array).is_some_and(|items| {
|
||||
items.iter().any(|item| {
|
||||
item.as_object().is_some_and(|object| {
|
||||
[
|
||||
"name",
|
||||
"publicGoal",
|
||||
"tension",
|
||||
"notes",
|
||||
"role",
|
||||
"publicMask",
|
||||
"hiddenHook",
|
||||
"relationToPlayer",
|
||||
"purpose",
|
||||
"mood",
|
||||
"secret",
|
||||
]
|
||||
.iter()
|
||||
.any(|key| read_text(object, key).is_some())
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_text_field(
|
||||
draft: &Map<String, Value>,
|
||||
legacy: &Map<String, Value>,
|
||||
key: &str,
|
||||
) -> Option<String> {
|
||||
to_text(draft.get(key)).or_else(|| to_text(legacy.get(key)))
|
||||
}
|
||||
|
||||
fn resolve_theme_mode(legacy: &Map<String, Value>) -> CustomWorldThemeMode {
|
||||
to_text(legacy.get("themeMode"))
|
||||
.and_then(|value| CustomWorldThemeMode::from_client_str(&value))
|
||||
.unwrap_or(CustomWorldThemeMode::Mythic)
|
||||
}
|
||||
|
||||
fn resolve_cover_image_src(
|
||||
draft: &Map<String, Value>,
|
||||
legacy: &Map<String, Value>,
|
||||
) -> Option<String> {
|
||||
if let Some(camp) = to_object(draft.get("camp")) {
|
||||
if let Some(image_src) = to_text(camp.get("imageSrc")) {
|
||||
return Some(image_src);
|
||||
}
|
||||
}
|
||||
|
||||
for landmark in to_array(draft.get("landmarks")) {
|
||||
if let Value::Object(landmark) = landmark {
|
||||
if let Some(image_src) = to_text(landmark.get("imageSrc")) {
|
||||
return Some(image_src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cover) = to_object(legacy.get("cover")) {
|
||||
if let Some(image_src) = to_text(cover.get("imageSrc")) {
|
||||
return Some(image_src);
|
||||
}
|
||||
}
|
||||
|
||||
to_text(legacy.get("coverImageSrc"))
|
||||
}
|
||||
|
||||
fn count_distinct_roles(playable: Option<&Value>, story: Option<&Value>) -> u32 {
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
|
||||
for role in to_array(playable).into_iter().chain(to_array(story)) {
|
||||
if let Value::Object(role) = role {
|
||||
let key = to_text(role.get("id"))
|
||||
.or_else(|| to_text(role.get("name")))
|
||||
.unwrap_or_else(|| format!("role-{}", seen.len()));
|
||||
seen.insert(key);
|
||||
}
|
||||
}
|
||||
|
||||
seen.len() as u32
|
||||
}
|
||||
|
||||
fn build_compiled_profile_payload_json(
|
||||
input: &CustomWorldPublishedProfileCompileInput,
|
||||
draft: &Map<String, Value>,
|
||||
legacy: &Map<String, Value>,
|
||||
world_name: &str,
|
||||
subtitle: &str,
|
||||
summary_text: &str,
|
||||
) -> Result<String, CustomWorldFieldError> {
|
||||
let mut payload = legacy.clone();
|
||||
|
||||
payload.insert("id".to_string(), Value::String(input.profile_id.clone()));
|
||||
payload.insert(
|
||||
"settingText".to_string(),
|
||||
Value::String(input.setting_text.trim().to_string()),
|
||||
);
|
||||
payload.insert("name".to_string(), Value::String(world_name.to_string()));
|
||||
payload.insert("subtitle".to_string(), Value::String(subtitle.to_string()));
|
||||
payload.insert(
|
||||
"summary".to_string(),
|
||||
Value::String(summary_text.to_string()),
|
||||
);
|
||||
payload.insert(
|
||||
"updatedAtMicros".to_string(),
|
||||
Value::Number(input.updated_at_micros.into()),
|
||||
);
|
||||
|
||||
for key in ["tone", "playerGoal"] {
|
||||
if let Some(value) = draft.get(key) {
|
||||
payload.insert(key.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
for key in [
|
||||
"majorFactions",
|
||||
"coreConflicts",
|
||||
"playableNpcs",
|
||||
"storyNpcs",
|
||||
"landmarks",
|
||||
"camp",
|
||||
] {
|
||||
if let Some(value) = draft.get(key) {
|
||||
payload.insert(key.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(scene_chapters) = draft
|
||||
.get("sceneChapterBlueprints")
|
||||
.or_else(|| draft.get("sceneChapters"))
|
||||
{
|
||||
payload.insert("sceneChapterBlueprints".to_string(), scene_chapters.clone());
|
||||
}
|
||||
|
||||
serde_json::to_string(&Value::Object(payload))
|
||||
.map_err(|_| CustomWorldFieldError::InvalidDraftProfileJson)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,283 @@
|
||||
//! 自定义世界写入命令过渡落位。
|
||||
//! 自定义世界写入命令。
|
||||
//!
|
||||
//! 用于表达会话创建、消息写入、草稿更新、发布和下架等用例输入。
|
||||
|
||||
use crate::domain::{
|
||||
CustomWorldAgentOperationSnapshot, CustomWorldGalleryEntrySnapshot, CustomWorldProfileSnapshot,
|
||||
CustomWorldThemeMode, RpgAgentOperationStatus, RpgAgentOperationType, RpgAgentStage,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "spacetime-types")]
|
||||
use spacetimedb::SpacetimeType;
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileUpsertInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub public_work_code: Option<String>,
|
||||
pub author_public_user_code: Option<String>,
|
||||
pub source_agent_session_id: Option<String>,
|
||||
pub world_name: String,
|
||||
pub subtitle: String,
|
||||
pub summary_text: String,
|
||||
pub theme_mode: CustomWorldThemeMode,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub profile_payload_json: String,
|
||||
pub playable_npc_count: u32,
|
||||
pub landmark_count: u32,
|
||||
pub author_display_name: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfilePublishInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub public_work_code: Option<String>,
|
||||
pub author_public_user_code: String,
|
||||
pub author_display_name: String,
|
||||
pub published_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileUnpublishInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub author_display_name: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileDeleteInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub deleted_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileListInput {
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldLibraryDetailInput {
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldGalleryDetailInput {
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldGalleryDetailByCodeInput {
|
||||
pub public_work_code: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentSessionCreateInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub seed_text: String,
|
||||
pub welcome_message_id: String,
|
||||
pub welcome_message_text: String,
|
||||
pub anchor_content_json: String,
|
||||
pub creator_intent_json: Option<String>,
|
||||
pub creator_intent_readiness_json: String,
|
||||
pub anchor_pack_json: Option<String>,
|
||||
pub lock_state_json: Option<String>,
|
||||
pub draft_profile_json: Option<String>,
|
||||
pub pending_clarifications_json: String,
|
||||
pub suggested_actions_json: String,
|
||||
pub recommended_replies_json: String,
|
||||
pub quality_findings_json: String,
|
||||
pub asset_coverage_json: String,
|
||||
pub checkpoints_json: String,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentSessionGetInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentMessageSubmitInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub user_message_id: String,
|
||||
pub user_message_text: String,
|
||||
pub operation_id: String,
|
||||
pub submitted_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentMessageFinalizeInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub operation_id: String,
|
||||
pub assistant_message_id: Option<String>,
|
||||
pub assistant_reply_text: Option<String>,
|
||||
pub phase_label: String,
|
||||
pub phase_detail: String,
|
||||
pub operation_status: RpgAgentOperationStatus,
|
||||
pub operation_progress: u32,
|
||||
pub stage: RpgAgentStage,
|
||||
pub progress_percent: u32,
|
||||
pub focus_card_id: Option<String>,
|
||||
pub anchor_content_json: String,
|
||||
pub creator_intent_json: Option<String>,
|
||||
pub creator_intent_readiness_json: String,
|
||||
pub anchor_pack_json: Option<String>,
|
||||
pub draft_profile_json: Option<String>,
|
||||
pub pending_clarifications_json: String,
|
||||
pub suggested_actions_json: String,
|
||||
pub recommended_replies_json: String,
|
||||
pub quality_findings_json: String,
|
||||
pub asset_coverage_json: String,
|
||||
pub error_message: Option<String>,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentOperationGetInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub operation_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentOperationProgressInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub operation_id: String,
|
||||
pub operation_type: RpgAgentOperationType,
|
||||
pub operation_status: RpgAgentOperationStatus,
|
||||
pub phase_label: String,
|
||||
pub phase_detail: String,
|
||||
pub operation_progress: u32,
|
||||
pub error_message: Option<String>,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentOperationProcedureResult {
|
||||
pub ok: bool,
|
||||
pub operation: Option<CustomWorldAgentOperationSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldWorksListInput {
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentCardDetailGetInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub card_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentActionExecuteInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub operation_id: String,
|
||||
pub action: String,
|
||||
pub payload_json: Option<String>,
|
||||
pub submitted_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentActionExecuteResult {
|
||||
pub ok: bool,
|
||||
pub operation: Option<CustomWorldAgentOperationSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishedProfileCompileInput {
|
||||
pub session_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub draft_profile_json: String,
|
||||
pub legacy_result_profile_json: Option<String>,
|
||||
pub setting_text: String,
|
||||
pub author_display_name: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishedProfileCompileSnapshot {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub world_name: String,
|
||||
pub subtitle: String,
|
||||
pub summary_text: String,
|
||||
pub theme_mode: CustomWorldThemeMode,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub playable_npc_count: u32,
|
||||
pub landmark_count: u32,
|
||||
pub author_display_name: String,
|
||||
pub compiled_profile_payload_json: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishedProfileCompileResult {
|
||||
pub ok: bool,
|
||||
pub record: Option<CustomWorldPublishedProfileCompileSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishWorldInput {
|
||||
pub session_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub public_work_code: Option<String>,
|
||||
pub author_public_user_code: String,
|
||||
pub draft_profile_json: String,
|
||||
pub legacy_result_profile_json: Option<String>,
|
||||
pub setting_text: String,
|
||||
pub author_display_name: String,
|
||||
pub published_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishWorldResult {
|
||||
pub ok: bool,
|
||||
pub compiled_record: Option<CustomWorldPublishedProfileCompileSnapshot>,
|
||||
pub entry: Option<CustomWorldProfileSnapshot>,
|
||||
pub gallery_entry: Option<CustomWorldGalleryEntrySnapshot>,
|
||||
pub session_stage: Option<RpgAgentStage>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! 自定义世界领域模型过渡落位。
|
||||
//! 自定义世界领域模型。
|
||||
//!
|
||||
//! 后续迁移 profile、Agent 会话、草稿卡、发布门禁和画廊投影规则时,
|
||||
//! 只保留纯领域结构;LLM 推理、SSE 和 OSS 均留在外层 adapter。
|
||||
//! 只保留 profile、Agent 会话、草稿卡、发布门禁和画廊投影的纯领域结构;LLM 推理、SSE 和 OSS 均留在外层 adapter。
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "spacetime-types")]
|
||||
@@ -139,6 +138,248 @@ pub enum CustomWorldRoleAssetStatus {
|
||||
Complete,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileSnapshot {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub public_work_code: Option<String>,
|
||||
pub author_public_user_code: Option<String>,
|
||||
pub source_agent_session_id: Option<String>,
|
||||
pub publication_status: CustomWorldPublicationStatus,
|
||||
pub world_name: String,
|
||||
pub subtitle: String,
|
||||
pub summary_text: String,
|
||||
pub theme_mode: CustomWorldThemeMode,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub profile_payload_json: String,
|
||||
pub playable_npc_count: u32,
|
||||
pub landmark_count: u32,
|
||||
pub author_display_name: String,
|
||||
pub published_at_micros: Option<i64>,
|
||||
pub deleted_at_micros: Option<i64>,
|
||||
pub created_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldGalleryEntrySnapshot {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub public_work_code: String,
|
||||
pub author_public_user_code: String,
|
||||
pub author_display_name: String,
|
||||
pub world_name: String,
|
||||
pub subtitle: String,
|
||||
pub summary_text: String,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub theme_mode: CustomWorldThemeMode,
|
||||
pub playable_npc_count: u32,
|
||||
pub landmark_count: u32,
|
||||
pub published_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldLibraryMutationResult {
|
||||
pub ok: bool,
|
||||
pub entry: Option<CustomWorldProfileSnapshot>,
|
||||
pub gallery_entry: Option<CustomWorldGalleryEntrySnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileListResult {
|
||||
pub ok: bool,
|
||||
pub entries: Vec<CustomWorldProfileSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldGalleryListResult {
|
||||
pub ok: bool,
|
||||
pub entries: Vec<CustomWorldGalleryEntrySnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishBlockerSnapshot {
|
||||
pub blocker_id: String,
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldPublishGateSnapshot {
|
||||
pub profile_id: String,
|
||||
pub blockers: Vec<CustomWorldPublishBlockerSnapshot>,
|
||||
pub blocker_count: u32,
|
||||
pub publish_ready: bool,
|
||||
pub can_enter_world: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldWorkSummarySnapshot {
|
||||
pub work_id: String,
|
||||
pub source_type: String,
|
||||
pub status: String,
|
||||
pub title: String,
|
||||
pub subtitle: String,
|
||||
pub summary: String,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub cover_render_mode: Option<String>,
|
||||
pub cover_character_image_srcs_json: String,
|
||||
pub updated_at_micros: i64,
|
||||
pub published_at_micros: Option<i64>,
|
||||
pub stage: Option<RpgAgentStage>,
|
||||
pub stage_label: Option<String>,
|
||||
pub playable_npc_count: u32,
|
||||
pub landmark_count: u32,
|
||||
pub role_visual_ready_count: Option<u32>,
|
||||
pub role_animation_ready_count: Option<u32>,
|
||||
pub role_asset_summary_label: Option<String>,
|
||||
pub session_id: Option<String>,
|
||||
pub profile_id: Option<String>,
|
||||
pub can_resume: bool,
|
||||
pub can_enter_world: bool,
|
||||
pub blocker_count: u32,
|
||||
pub publish_ready: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldWorksListResult {
|
||||
pub ok: bool,
|
||||
pub items: Vec<CustomWorldWorkSummarySnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentMessageSnapshot {
|
||||
pub message_id: String,
|
||||
pub session_id: String,
|
||||
pub role: RpgAgentMessageRole,
|
||||
pub kind: RpgAgentMessageKind,
|
||||
pub text: String,
|
||||
pub related_operation_id: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentOperationSnapshot {
|
||||
pub operation_id: String,
|
||||
pub session_id: String,
|
||||
pub operation_type: RpgAgentOperationType,
|
||||
pub status: RpgAgentOperationStatus,
|
||||
pub phase_label: String,
|
||||
pub phase_detail: String,
|
||||
pub progress: u32,
|
||||
pub error_message: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldDraftCardSnapshot {
|
||||
pub card_id: String,
|
||||
pub session_id: String,
|
||||
pub kind: RpgAgentDraftCardKind,
|
||||
pub status: RpgAgentDraftCardStatus,
|
||||
pub title: String,
|
||||
pub subtitle: String,
|
||||
pub summary: String,
|
||||
pub linked_ids_json: String,
|
||||
pub warning_count: u32,
|
||||
pub asset_status: Option<CustomWorldRoleAssetStatus>,
|
||||
pub asset_status_label: Option<String>,
|
||||
pub detail_payload_json: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldDraftCardDetailSectionSnapshot {
|
||||
pub section_id: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldDraftCardDetailSnapshot {
|
||||
pub card_id: String,
|
||||
pub kind: RpgAgentDraftCardKind,
|
||||
pub title: String,
|
||||
pub sections: Vec<CustomWorldDraftCardDetailSectionSnapshot>,
|
||||
pub linked_ids_json: String,
|
||||
pub locked: bool,
|
||||
pub editable: bool,
|
||||
pub editable_section_ids_json: String,
|
||||
pub warning_messages_json: String,
|
||||
pub asset_status: Option<CustomWorldRoleAssetStatus>,
|
||||
pub asset_status_label: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldDraftCardDetailResult {
|
||||
pub ok: bool,
|
||||
pub card: Option<CustomWorldDraftCardDetailSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentSessionSnapshot {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub seed_text: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: RpgAgentStage,
|
||||
pub focus_card_id: Option<String>,
|
||||
pub anchor_content_json: String,
|
||||
pub creator_intent_json: Option<String>,
|
||||
pub creator_intent_readiness_json: String,
|
||||
pub anchor_pack_json: Option<String>,
|
||||
pub lock_state_json: Option<String>,
|
||||
pub draft_profile_json: Option<String>,
|
||||
pub last_assistant_reply: Option<String>,
|
||||
pub publish_gate_json: Option<String>,
|
||||
pub result_preview_json: Option<String>,
|
||||
pub pending_clarifications_json: String,
|
||||
pub quality_findings_json: String,
|
||||
pub suggested_actions_json: String,
|
||||
pub recommended_replies_json: String,
|
||||
pub asset_coverage_json: String,
|
||||
pub checkpoints_json: String,
|
||||
pub supported_actions_json: String,
|
||||
pub messages: Vec<CustomWorldAgentMessageSnapshot>,
|
||||
pub draft_cards: Vec<CustomWorldDraftCardSnapshot>,
|
||||
pub operations: Vec<CustomWorldAgentOperationSnapshot>,
|
||||
pub created_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentSessionProcedureResult {
|
||||
pub ok: bool,
|
||||
pub session: Option<CustomWorldAgentSessionSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
impl CustomWorldPublicationStatus {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
|
||||
@@ -1,3 +1,100 @@
|
||||
//! 自定义世界领域错误过渡落位。
|
||||
//! 自定义世界领域错误。
|
||||
//!
|
||||
//! 错误只表达世界创作规则失败,由 adapter 显式映射为 HTTP 或 reducer 错误。
|
||||
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CustomWorldFieldError {
|
||||
MissingProfileId,
|
||||
MissingSessionId,
|
||||
MissingOwnerUserId,
|
||||
MissingPublicWorkCode,
|
||||
MissingAction,
|
||||
MissingWorldName,
|
||||
MissingDraftProfileJson,
|
||||
MissingProfilePayloadJson,
|
||||
MissingSettingText,
|
||||
MissingQuestionSnapshotJson,
|
||||
MissingAnchorContentJson,
|
||||
MissingCreatorIntentReadinessJson,
|
||||
MissingAssetCoverageJson,
|
||||
MissingPendingClarificationsJson,
|
||||
MissingMessageId,
|
||||
MissingMessageText,
|
||||
MissingOperationId,
|
||||
MissingPhaseLabel,
|
||||
InvalidProgressPercent,
|
||||
MissingCardId,
|
||||
MissingCardTitle,
|
||||
MissingCardSummary,
|
||||
MissingLinkedIdsJson,
|
||||
MissingAuthorDisplayName,
|
||||
InvalidDraftProfileJson,
|
||||
InvalidLegacyResultProfileJson,
|
||||
InvalidJsonPayload,
|
||||
}
|
||||
|
||||
impl fmt::Display for CustomWorldFieldError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::MissingProfileId => f.write_str("custom_world.profile_id 不能为空"),
|
||||
Self::MissingSessionId => f.write_str("custom_world.session_id 不能为空"),
|
||||
Self::MissingOwnerUserId => f.write_str("custom_world.owner_user_id 不能为空"),
|
||||
Self::MissingPublicWorkCode => {
|
||||
f.write_str("custom_world_gallery_detail.public_work_code 不能为空")
|
||||
}
|
||||
Self::MissingAction => f.write_str("custom_world_agent_action.action 不能为空"),
|
||||
Self::MissingWorldName => f.write_str("custom_world.world_name 不能为空"),
|
||||
Self::MissingDraftProfileJson => {
|
||||
f.write_str("custom_world.compile.draft_profile_json 不能为空")
|
||||
}
|
||||
Self::MissingProfilePayloadJson => {
|
||||
f.write_str("custom_world.profile_payload_json 不能为空")
|
||||
}
|
||||
Self::MissingSettingText => f.write_str("custom_world.setting_text 不能为空"),
|
||||
Self::MissingQuestionSnapshotJson => {
|
||||
f.write_str("custom_world.question_snapshot_json 不能为空")
|
||||
}
|
||||
Self::MissingAnchorContentJson => {
|
||||
f.write_str("custom_world.anchor_content_json 不能为空")
|
||||
}
|
||||
Self::MissingCreatorIntentReadinessJson => {
|
||||
f.write_str("custom_world.creator_intent_readiness_json 不能为空")
|
||||
}
|
||||
Self::MissingAssetCoverageJson => {
|
||||
f.write_str("custom_world.asset_coverage_json 不能为空")
|
||||
}
|
||||
Self::MissingPendingClarificationsJson => {
|
||||
f.write_str("custom_world.pending_clarifications_json 不能为空")
|
||||
}
|
||||
Self::MissingMessageId => f.write_str("custom_world_agent_message.message_id 不能为空"),
|
||||
Self::MissingMessageText => f.write_str("custom_world_agent_message.text 不能为空"),
|
||||
Self::MissingOperationId => {
|
||||
f.write_str("custom_world_agent_operation.operation_id 不能为空")
|
||||
}
|
||||
Self::MissingPhaseLabel => {
|
||||
f.write_str("custom_world_agent_operation.phase_label 不能为空")
|
||||
}
|
||||
Self::InvalidProgressPercent => f.write_str("progress 必须位于 0~100"),
|
||||
Self::MissingCardId => f.write_str("custom_world_draft_card.card_id 不能为空"),
|
||||
Self::MissingCardTitle => f.write_str("custom_world_draft_card.title 不能为空"),
|
||||
Self::MissingCardSummary => f.write_str("custom_world_draft_card.summary 不能为空"),
|
||||
Self::MissingLinkedIdsJson => {
|
||||
f.write_str("custom_world_draft_card.linked_ids_json 不能为空")
|
||||
}
|
||||
Self::MissingAuthorDisplayName => {
|
||||
f.write_str("custom_world_gallery_entry.author_display_name 不能为空")
|
||||
}
|
||||
Self::InvalidDraftProfileJson => {
|
||||
f.write_str("custom_world.compile.draft_profile_json 不是合法 JSON object")
|
||||
}
|
||||
Self::InvalidLegacyResultProfileJson => {
|
||||
f.write_str("custom_world.compile.legacy_result_profile_json 不是合法 JSON object")
|
||||
}
|
||||
Self::InvalidJsonPayload => f.write_str("custom_world JSON payload 结构非法"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for CustomWorldFieldError {}
|
||||
|
||||
@@ -1,3 +1,68 @@
|
||||
//! 自定义世界领域事件过渡落位。
|
||||
//! 自定义世界领域事件。
|
||||
//!
|
||||
//! 用于表达草稿变化、profile 发布、画廊投影刷新和 Agent 操作进度变化。
|
||||
|
||||
use crate::domain::{
|
||||
RpgAgentDraftCardKind, RpgAgentOperationStatus, RpgAgentOperationType, RpgAgentStage,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "spacetime-types")]
|
||||
use spacetimedb::SpacetimeType;
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum CustomWorldDomainEvent {
|
||||
ProfileUpserted(CustomWorldProfileUpsertedEvent),
|
||||
ProfilePublished(CustomWorldProfilePublishedEvent),
|
||||
GalleryProjectionRefreshed(CustomWorldGalleryProjectionRefreshedEvent),
|
||||
AgentSessionAdvanced(CustomWorldAgentSessionAdvancedEvent),
|
||||
AgentOperationProgressed(CustomWorldAgentOperationProgressedEvent),
|
||||
DraftCardUpdated(CustomWorldDraftCardUpdatedEvent),
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfileUpsertedEvent {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldProfilePublishedEvent {
|
||||
pub profile_id: String,
|
||||
pub public_work_code: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldGalleryProjectionRefreshedEvent {
|
||||
pub profile_id: String,
|
||||
pub public_work_code: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentSessionAdvancedEvent {
|
||||
pub session_id: String,
|
||||
pub stage: RpgAgentStage,
|
||||
pub progress_percent: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldAgentOperationProgressedEvent {
|
||||
pub session_id: String,
|
||||
pub operation_id: String,
|
||||
pub operation_type: RpgAgentOperationType,
|
||||
pub status: RpgAgentOperationStatus,
|
||||
pub progress: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CustomWorldDraftCardUpdatedEvent {
|
||||
pub session_id: String,
|
||||
pub card_id: String,
|
||||
pub kind: RpgAgentDraftCardKind,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user