use super::*; impl From for CustomWorldProfileUpsertInput { fn from(input: CustomWorldProfileUpsertRecordInput) -> Self { Self { profile_id: input.profile_id, owner_user_id: input.owner_user_id, public_work_code: input.public_work_code, author_public_user_code: input.author_public_user_code, source_agent_session_id: input.source_agent_session_id, world_name: input.world_name, subtitle: input.subtitle, summary_text: input.summary_text, theme_mode: map_custom_world_theme_mode(input.theme_mode), cover_image_src: input.cover_image_src, profile_payload_json: input.profile_payload_json, playable_npc_count: input.playable_npc_count, landmark_count: input.landmark_count, author_display_name: input.author_display_name, updated_at_micros: input.updated_at_micros, } } } pub(crate) fn map_custom_world_profile_list_result( result: CustomWorldProfileListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } result .entries .into_iter() .map(map_custom_world_library_entry_from_profile_snapshot) .collect() } pub(crate) fn map_custom_world_library_detail_result( result: CustomWorldLibraryMutationResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let entry = result .entry .ok_or_else(|| SpacetimeClientError::Procedure("custom_world_profile 不存在".to_string())) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; Ok(CustomWorldLibraryMutationRecord { entry, gallery_entry, }) } pub(crate) fn map_custom_world_gallery_list_result( result: CustomWorldGalleryListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } Ok(result .entries .into_iter() .map(map_custom_world_gallery_entry_snapshot) .collect::, _>>()?) } pub(crate) fn map_custom_world_library_mutation_result( result: CustomWorldLibraryMutationResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let entry = result .entry .ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry")) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; Ok(CustomWorldLibraryMutationRecord { entry, gallery_entry, }) } pub(crate) fn map_custom_world_publish_world_result( result: CustomWorldPublishWorldResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let compiled_record = result .compiled_record .ok_or_else(|| SpacetimeClientError::missing_snapshot("published profile compile 快照")) .and_then(map_custom_world_published_profile_compile_snapshot)?; let entry = result .entry .ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world entry")) .and_then(map_custom_world_library_entry_from_profile_snapshot)?; let gallery_entry = result .gallery_entry .map(map_custom_world_gallery_entry_snapshot) .transpose()?; let session_stage = result .session_stage .ok_or_else(|| SpacetimeClientError::missing_snapshot("session stage")) .map(map_rpg_agent_stage)?; Ok(CustomWorldPublishWorldRecord { compiled_record, entry, gallery_entry, session_stage, }) } pub(crate) fn map_custom_world_agent_session_procedure_result( result: CustomWorldAgentSessionProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let session = result .session .ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world agent session 快照"))?; map_custom_world_agent_session_snapshot(session) } pub(crate) fn map_custom_world_agent_operation_procedure_result( result: CustomWorldAgentOperationProcedureResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let operation = result.operation.ok_or_else(|| { SpacetimeClientError::missing_snapshot("custom world agent operation 快照") })?; Ok(map_custom_world_agent_operation_snapshot(operation)) } pub(crate) fn map_custom_world_works_list_result( result: CustomWorldWorksListResult, ) -> Result, SpacetimeClientError> { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } result .items .into_iter() .map(map_custom_world_work_summary_snapshot) .collect() } pub(crate) fn map_custom_world_draft_card_detail_result( result: CustomWorldDraftCardDetailResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let card = result .card .ok_or_else(|| SpacetimeClientError::missing_snapshot("custom world card detail 快照"))?; map_custom_world_draft_card_detail_snapshot(card) } pub(crate) fn map_custom_world_agent_action_execute_result( result: CustomWorldAgentActionExecuteResult, ) -> Result { if !result.ok { return Err(SpacetimeClientError::procedure_failed(result.error_message)); } let operation = result.operation.ok_or_else(|| { SpacetimeClientError::missing_snapshot("custom world action operation 快照") })?; Ok(CustomWorldAgentActionExecuteRecord { operation: map_custom_world_agent_operation_snapshot(operation), }) } pub(crate) fn map_custom_world_library_entry_from_profile_snapshot( snapshot: CustomWorldProfileSnapshot, ) -> Result { let profile = serde_json::from_str::(&snapshot.profile_payload_json) .map_err(|error| { SpacetimeClientError::Runtime(format!( "custom world profile payload JSON 非法: {error}" )) })?; Ok(CustomWorldLibraryEntryRecord { owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, public_work_code: snapshot.public_work_code, author_public_user_code: snapshot.author_public_user_code, profile, visibility: map_custom_world_publication_status(snapshot.publication_status).to_string(), published_at: snapshot.published_at_micros.map(format_timestamp_micros), updated_at: format_timestamp_micros(snapshot.updated_at_micros), author_display_name: snapshot.author_display_name, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, play_count: snapshot.play_count, remix_count: snapshot.remix_count, like_count: snapshot.like_count, recent_play_count_7d: 0, }) } pub(crate) fn map_custom_world_gallery_entry_snapshot( snapshot: CustomWorldGalleryEntrySnapshot, ) -> Result { Ok(CustomWorldGalleryEntryRecord { owner_user_id: snapshot.owner_user_id, profile_id: snapshot.profile_id, public_work_code: snapshot.public_work_code, author_public_user_code: snapshot.author_public_user_code, visibility: "published".to_string(), published_at: Some(format_timestamp_micros(snapshot.published_at_micros)), updated_at: format_timestamp_micros(snapshot.updated_at_micros), author_display_name: snapshot.author_display_name, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, cover_image_src: snapshot.cover_image_src, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, play_count: snapshot.play_count, remix_count: snapshot.remix_count, like_count: snapshot.like_count, recent_play_count_7d: snapshot.recent_play_count_7_d, }) } pub(crate) fn map_custom_world_gallery_entry_row( row: CustomWorldGalleryEntry, recent_play_count_7d: u32, ) -> CustomWorldGalleryEntryRecord { CustomWorldGalleryEntryRecord { owner_user_id: row.owner_user_id, profile_id: row.profile_id, public_work_code: row.public_work_code, author_public_user_code: row.author_public_user_code, visibility: "published".to_string(), published_at: Some(format_timestamp_micros( row.published_at.to_micros_since_unix_epoch(), )), updated_at: format_timestamp_micros(row.updated_at.to_micros_since_unix_epoch()), author_display_name: row.author_display_name, world_name: row.world_name, subtitle: row.subtitle, summary_text: row.summary_text, cover_image_src: row.cover_image_src, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( row.theme_mode, )) .to_string(), playable_npc_count: row.playable_npc_count, landmark_count: row.landmark_count, play_count: row.play_count, remix_count: row.remix_count, like_count: row.like_count, recent_play_count_7d, } } pub(crate) fn map_custom_world_published_profile_compile_snapshot( snapshot: CustomWorldPublishedProfileCompileSnapshot, ) -> Result { let compiled_profile = serde_json::from_str::(&snapshot.compiled_profile_payload_json) .map_err(|error| { SpacetimeClientError::Runtime(format!( "published profile compile JSON 非法: {error}" )) })?; Ok(CustomWorldPublishedProfileCompileRecord { profile_id: snapshot.profile_id, owner_user_id: snapshot.owner_user_id, world_name: snapshot.world_name, subtitle: snapshot.subtitle, summary_text: snapshot.summary_text, theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( snapshot.theme_mode, )) .to_string(), cover_image_src: snapshot.cover_image_src, playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, author_display_name: snapshot.author_display_name, compiled_profile: compiled_profile, updated_at: format_timestamp_micros(snapshot.updated_at_micros), }) } pub(crate) fn map_custom_world_work_summary_snapshot( snapshot: CustomWorldWorkSummarySnapshot, ) -> Result { Ok(CustomWorldWorkSummaryRecord { work_id: snapshot.work_id, source_type: snapshot.source_type, status: snapshot.status, title: snapshot.title, subtitle: snapshot.subtitle, summary: snapshot.summary, cover_image_src: snapshot.cover_image_src, cover_render_mode: snapshot.cover_render_mode, cover_character_image_srcs: parse_json_string_array( &snapshot.cover_character_image_srcs_json, "custom world work cover_character_image_srcs_json", )?, updated_at: format_timestamp_micros(snapshot.updated_at_micros), published_at: snapshot.published_at_micros.map(format_timestamp_micros), stage: snapshot.stage.map(map_rpg_agent_stage), stage_label: snapshot.stage_label, playable_npc_count: snapshot.playable_npc_count, landmark_count: snapshot.landmark_count, role_visual_ready_count: snapshot.role_visual_ready_count, role_animation_ready_count: snapshot.role_animation_ready_count, role_asset_summary_label: snapshot.role_asset_summary_label, session_id: snapshot.session_id, profile_id: snapshot.profile_id, can_resume: snapshot.can_resume, can_enter_world: snapshot.can_enter_world, blocker_count: snapshot.blocker_count, publish_ready: snapshot.publish_ready, }) } pub(crate) fn map_custom_world_agent_session_snapshot( snapshot: CustomWorldAgentSessionSnapshot, ) -> Result { let anchor_content = parse_json_value( &snapshot.anchor_content_json, "custom world agent anchor_content_json", )?; let creator_intent = parse_optional_json_value( snapshot.creator_intent_json.as_deref(), serde_json::json!({}), "custom world agent creator_intent_json", )?; let creator_intent_readiness = parse_json_value( &snapshot.creator_intent_readiness_json, "custom world agent creator_intent_readiness_json", )?; let anchor_pack = parse_optional_json_value( snapshot.anchor_pack_json.as_deref(), serde_json::json!({}), "custom world agent anchor_pack_json", )?; let lock_state = parse_optional_json_value( snapshot.lock_state_json.as_deref(), serde_json::json!({}), "custom world agent lock_state_json", )?; let draft_profile = parse_optional_json_value( snapshot.draft_profile_json.as_deref(), serde_json::json!({}), "custom world agent draft_profile_json", )?; let pending_clarifications = parse_json_array( &snapshot.pending_clarifications_json, "custom world agent pending_clarifications_json", )?; let suggested_actions = parse_json_array( &snapshot.suggested_actions_json, "custom world agent suggested_actions_json", )?; let recommended_replies = parse_json_string_array( &snapshot.recommended_replies_json, "custom world agent recommended_replies_json", )?; let quality_findings = parse_json_array( &snapshot.quality_findings_json, "custom world agent quality_findings_json", )?; let asset_coverage = parse_json_value( &snapshot.asset_coverage_json, "custom world agent asset_coverage_json", )?; let checkpoints_json = parse_json_array( &snapshot.checkpoints_json, "custom world agent checkpoints_json", )?; let checkpoints = checkpoints_json .into_iter() .map(map_custom_world_checkpoint_record) .collect::, _>>()?; let supported_actions = parse_supported_actions_json(&snapshot.supported_actions_json)?; let publish_gate = snapshot .publish_gate_json .as_deref() .map(parse_custom_world_publish_gate_record) .transpose()?; Ok(CustomWorldAgentSessionRecord { session_id: snapshot.session_id, seed_text: snapshot.seed_text, current_turn: snapshot.current_turn, anchor_content, progress_percent: snapshot.progress_percent, last_assistant_reply: snapshot.last_assistant_reply, stage: map_rpg_agent_stage(snapshot.stage), focus_card_id: snapshot.focus_card_id, creator_intent, creator_intent_readiness, anchor_pack, lock_state, draft_profile, messages: snapshot .messages .into_iter() .map(map_custom_world_agent_message_snapshot) .collect(), draft_cards: snapshot .draft_cards .into_iter() .map(map_custom_world_draft_card_snapshot) .collect::, _>>()?, pending_clarifications, suggested_actions, recommended_replies, quality_findings, asset_coverage, checkpoints, supported_actions, publish_gate, result_preview: snapshot .result_preview_json .as_deref() .map(|value| parse_json_value(value, "custom world agent result_preview_json")) .transpose()?, updated_at: format_timestamp_micros(snapshot.updated_at_micros), }) } pub(crate) fn map_custom_world_agent_message_snapshot( snapshot: CustomWorldAgentMessageSnapshot, ) -> CustomWorldAgentMessageRecord { CustomWorldAgentMessageRecord { message_id: snapshot.message_id, role: format_rpg_agent_message_role(snapshot.role).to_string(), kind: format_rpg_agent_message_kind(snapshot.kind).to_string(), text: snapshot.text, created_at: format_timestamp_micros(snapshot.created_at_micros), related_operation_id: snapshot.related_operation_id, } } pub(crate) fn map_custom_world_agent_operation_snapshot( snapshot: CustomWorldAgentOperationSnapshot, ) -> CustomWorldAgentOperationRecord { CustomWorldAgentOperationRecord { operation_id: snapshot.operation_id, operation_type: format_rpg_agent_operation_type(snapshot.operation_type).to_string(), status: format_rpg_agent_operation_status(snapshot.status).to_string(), phase_label: snapshot.phase_label, phase_detail: snapshot.phase_detail, progress: snapshot.progress, error_message: snapshot.error_message, started_at_micros: snapshot.created_at_micros, updated_at_micros: snapshot.updated_at_micros, } } pub(crate) fn map_custom_world_draft_card_snapshot( snapshot: CustomWorldDraftCardSnapshot, ) -> Result { Ok(CustomWorldDraftCardRecord { card_id: snapshot.card_id, kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), title: snapshot.title, subtitle: snapshot.subtitle, summary: snapshot.summary, status: format_rpg_agent_draft_card_status(snapshot.status).to_string(), linked_ids: parse_json_string_array( &snapshot.linked_ids_json, "custom world draft_card linked_ids_json", )?, warning_count: snapshot.warning_count, asset_status: snapshot .asset_status .map(format_custom_world_role_asset_status_back), asset_status_label: snapshot.asset_status_label, detail_payload: snapshot .detail_payload_json .as_deref() .map(|value| parse_json_value(value, "custom world draft_card detail_payload_json")) .transpose()?, }) } pub(crate) fn map_custom_world_draft_card_detail_snapshot( snapshot: CustomWorldDraftCardDetailSnapshot, ) -> Result { Ok(CustomWorldDraftCardDetailRecord { card_id: snapshot.card_id, kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), title: snapshot.title, sections: snapshot .sections .into_iter() .map(map_custom_world_draft_card_detail_section_snapshot) .collect(), linked_ids: parse_json_string_array( &snapshot.linked_ids_json, "custom world card detail linked_ids_json", )?, locked: snapshot.locked, editable: snapshot.editable, editable_section_ids: parse_json_string_array( &snapshot.editable_section_ids_json, "custom world card detail editable_section_ids_json", )?, warning_messages: parse_json_string_array( &snapshot.warning_messages_json, "custom world card detail warning_messages_json", )?, asset_status: snapshot .asset_status .map(format_custom_world_role_asset_status_back), asset_status_label: snapshot.asset_status_label, }) } pub(crate) fn map_custom_world_draft_card_detail_section_snapshot( snapshot: CustomWorldDraftCardDetailSectionSnapshot, ) -> CustomWorldDraftCardDetailSectionRecord { CustomWorldDraftCardDetailSectionRecord { section_id: snapshot.section_id, label: snapshot.label, value: snapshot.value, } } pub(crate) fn map_custom_world_theme_mode( value: DomainCustomWorldThemeMode, ) -> CustomWorldThemeMode { match value { DomainCustomWorldThemeMode::Martial => CustomWorldThemeMode::Martial, DomainCustomWorldThemeMode::Arcane => CustomWorldThemeMode::Arcane, DomainCustomWorldThemeMode::Machina => CustomWorldThemeMode::Machina, DomainCustomWorldThemeMode::Tide => CustomWorldThemeMode::Tide, DomainCustomWorldThemeMode::Rift => CustomWorldThemeMode::Rift, DomainCustomWorldThemeMode::Mythic => CustomWorldThemeMode::Mythic, } } pub(crate) fn map_custom_world_theme_mode_back( value: CustomWorldThemeMode, ) -> DomainCustomWorldThemeMode { match value { CustomWorldThemeMode::Martial => DomainCustomWorldThemeMode::Martial, CustomWorldThemeMode::Arcane => DomainCustomWorldThemeMode::Arcane, CustomWorldThemeMode::Machina => DomainCustomWorldThemeMode::Machina, CustomWorldThemeMode::Tide => DomainCustomWorldThemeMode::Tide, CustomWorldThemeMode::Rift => DomainCustomWorldThemeMode::Rift, CustomWorldThemeMode::Mythic => DomainCustomWorldThemeMode::Mythic, } } pub(crate) fn map_custom_world_publication_status( value: CustomWorldPublicationStatus, ) -> &'static str { match value { CustomWorldPublicationStatus::Draft => "draft", CustomWorldPublicationStatus::Published => "published", } } pub(crate) fn map_rpg_agent_stage(value: crate::module_bindings::RpgAgentStage) -> String { match value { crate::module_bindings::RpgAgentStage::CollectingIntent => "collecting_intent", crate::module_bindings::RpgAgentStage::Clarifying => "clarifying", crate::module_bindings::RpgAgentStage::FoundationReview => "foundation_review", crate::module_bindings::RpgAgentStage::ObjectRefining => "object_refining", crate::module_bindings::RpgAgentStage::VisualRefining => "visual_refining", crate::module_bindings::RpgAgentStage::LongTailReview => "long_tail_review", crate::module_bindings::RpgAgentStage::ReadyToPublish => "ready_to_publish", crate::module_bindings::RpgAgentStage::Published => "published", crate::module_bindings::RpgAgentStage::Error => "error", } .to_string() } pub(crate) fn parse_rpg_agent_stage_record( value: &str, ) -> Result { match value.trim() { "collecting_intent" => Ok(crate::module_bindings::RpgAgentStage::CollectingIntent), "clarifying" => Ok(crate::module_bindings::RpgAgentStage::Clarifying), "foundation_review" => Ok(crate::module_bindings::RpgAgentStage::FoundationReview), "object_refining" => Ok(crate::module_bindings::RpgAgentStage::ObjectRefining), "visual_refining" => Ok(crate::module_bindings::RpgAgentStage::VisualRefining), "long_tail_review" => Ok(crate::module_bindings::RpgAgentStage::LongTailReview), "ready_to_publish" => Ok(crate::module_bindings::RpgAgentStage::ReadyToPublish), "published" => Ok(crate::module_bindings::RpgAgentStage::Published), "error" => Ok(crate::module_bindings::RpgAgentStage::Error), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent stage: {other}" ))), } } pub(crate) fn format_rpg_agent_message_role( value: crate::module_bindings::RpgAgentMessageRole, ) -> &'static str { match value { crate::module_bindings::RpgAgentMessageRole::User => "user", crate::module_bindings::RpgAgentMessageRole::Assistant => "assistant", crate::module_bindings::RpgAgentMessageRole::System => "system", } } pub(crate) fn format_rpg_agent_message_kind( value: crate::module_bindings::RpgAgentMessageKind, ) -> &'static str { match value { crate::module_bindings::RpgAgentMessageKind::Chat => "chat", crate::module_bindings::RpgAgentMessageKind::Clarification => "clarification", crate::module_bindings::RpgAgentMessageKind::Summary => "summary", crate::module_bindings::RpgAgentMessageKind::Checkpoint => "checkpoint", crate::module_bindings::RpgAgentMessageKind::Warning => "warning", crate::module_bindings::RpgAgentMessageKind::ActionResult => "action_result", } } pub(crate) fn format_rpg_agent_operation_type( value: crate::module_bindings::RpgAgentOperationType, ) -> &'static str { match value { crate::module_bindings::RpgAgentOperationType::ProcessMessage => "process_message", crate::module_bindings::RpgAgentOperationType::DraftFoundation => "draft_foundation", crate::module_bindings::RpgAgentOperationType::UpdateDraftCard => "update_draft_card", crate::module_bindings::RpgAgentOperationType::SyncResultProfile => "sync_result_profile", crate::module_bindings::RpgAgentOperationType::GenerateCharacters => "generate_characters", crate::module_bindings::RpgAgentOperationType::GenerateLandmarks => "generate_landmarks", crate::module_bindings::RpgAgentOperationType::GenerateRoleAssets => "generate_role_assets", crate::module_bindings::RpgAgentOperationType::SyncRoleAssets => "sync_role_assets", crate::module_bindings::RpgAgentOperationType::GenerateSceneAssets => { "generate_scene_assets" } crate::module_bindings::RpgAgentOperationType::SyncSceneAssets => "sync_scene_assets", crate::module_bindings::RpgAgentOperationType::ExpandLongTail => "expand_long_tail", crate::module_bindings::RpgAgentOperationType::PublishWorld => "publish_world", crate::module_bindings::RpgAgentOperationType::RevertCheckpoint => "revert_checkpoint", crate::module_bindings::RpgAgentOperationType::DeleteCharacters => "delete_characters", crate::module_bindings::RpgAgentOperationType::DeleteLandmarks => "delete_landmarks", } } pub(crate) fn parse_rpg_agent_operation_type_record( value: &str, ) -> Result { match value.trim() { "process_message" => Ok(crate::module_bindings::RpgAgentOperationType::ProcessMessage), "draft_foundation" => Ok(crate::module_bindings::RpgAgentOperationType::DraftFoundation), "update_draft_card" => Ok(crate::module_bindings::RpgAgentOperationType::UpdateDraftCard), "sync_result_profile" => { Ok(crate::module_bindings::RpgAgentOperationType::SyncResultProfile) } "generate_characters" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateCharacters) } "generate_landmarks" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateLandmarks) } "generate_role_assets" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateRoleAssets) } "sync_role_assets" => Ok(crate::module_bindings::RpgAgentOperationType::SyncRoleAssets), "generate_scene_assets" => { Ok(crate::module_bindings::RpgAgentOperationType::GenerateSceneAssets) } "sync_scene_assets" => Ok(crate::module_bindings::RpgAgentOperationType::SyncSceneAssets), "expand_long_tail" => Ok(crate::module_bindings::RpgAgentOperationType::ExpandLongTail), "publish_world" => Ok(crate::module_bindings::RpgAgentOperationType::PublishWorld), "revert_checkpoint" => Ok(crate::module_bindings::RpgAgentOperationType::RevertCheckpoint), "delete_characters" => Ok(crate::module_bindings::RpgAgentOperationType::DeleteCharacters), "delete_landmarks" => Ok(crate::module_bindings::RpgAgentOperationType::DeleteLandmarks), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent operation type: {other}" ))), } } pub(crate) fn format_rpg_agent_operation_status( value: crate::module_bindings::RpgAgentOperationStatus, ) -> &'static str { match value { crate::module_bindings::RpgAgentOperationStatus::Queued => "queued", crate::module_bindings::RpgAgentOperationStatus::Running => "running", crate::module_bindings::RpgAgentOperationStatus::Completed => "completed", crate::module_bindings::RpgAgentOperationStatus::Failed => "failed", } } pub(crate) fn parse_rpg_agent_operation_status_record( value: &str, ) -> Result { match value.trim() { "queued" => Ok(crate::module_bindings::RpgAgentOperationStatus::Queued), "running" => Ok(crate::module_bindings::RpgAgentOperationStatus::Running), "completed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Completed), "failed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Failed), other => Err(SpacetimeClientError::Runtime(format!( "未知 rpg agent operation status: {other}" ))), } } pub(crate) fn format_rpg_agent_draft_card_kind( value: crate::module_bindings::RpgAgentDraftCardKind, ) -> &'static str { match value { crate::module_bindings::RpgAgentDraftCardKind::World => "world", crate::module_bindings::RpgAgentDraftCardKind::Camp => "camp", crate::module_bindings::RpgAgentDraftCardKind::Faction => "faction", crate::module_bindings::RpgAgentDraftCardKind::Character => "character", crate::module_bindings::RpgAgentDraftCardKind::Landmark => "landmark", crate::module_bindings::RpgAgentDraftCardKind::Thread => "thread", crate::module_bindings::RpgAgentDraftCardKind::Chapter => "chapter", crate::module_bindings::RpgAgentDraftCardKind::SceneChapter => "scene_chapter", crate::module_bindings::RpgAgentDraftCardKind::Carrier => "carrier", crate::module_bindings::RpgAgentDraftCardKind::SidequestSeed => "sidequest_seed", } } pub(crate) fn format_rpg_agent_draft_card_status( value: crate::module_bindings::RpgAgentDraftCardStatus, ) -> &'static str { match value { crate::module_bindings::RpgAgentDraftCardStatus::Suggested => "suggested", crate::module_bindings::RpgAgentDraftCardStatus::Confirmed => "confirmed", crate::module_bindings::RpgAgentDraftCardStatus::Locked => "locked", crate::module_bindings::RpgAgentDraftCardStatus::Warning => "warning", } } pub(crate) fn format_custom_world_role_asset_status_back( value: crate::module_bindings::CustomWorldRoleAssetStatus, ) -> String { match value { crate::module_bindings::CustomWorldRoleAssetStatus::Missing => "missing", crate::module_bindings::CustomWorldRoleAssetStatus::VisualReady => "visual_ready", crate::module_bindings::CustomWorldRoleAssetStatus::AnimationsReady => "animations_ready", crate::module_bindings::CustomWorldRoleAssetStatus::Complete => "complete", } .to_string() } pub(crate) fn format_custom_world_theme_mode(value: DomainCustomWorldThemeMode) -> &'static str { match value { DomainCustomWorldThemeMode::Martial => "martial", DomainCustomWorldThemeMode::Arcane => "arcane", DomainCustomWorldThemeMode::Machina => "machina", DomainCustomWorldThemeMode::Tide => "tide", DomainCustomWorldThemeMode::Rift => "rift", DomainCustomWorldThemeMode::Mythic => "mythic", } } pub(crate) fn format_ai_task_kind(value: AiTaskKind) -> &'static str { match value { AiTaskKind::StoryGeneration => "story_generation", AiTaskKind::CharacterChat => "character_chat", AiTaskKind::NpcChat => "npc_chat", AiTaskKind::CustomWorldGeneration => "custom_world_generation", AiTaskKind::QuestIntent => "quest_intent", AiTaskKind::RuntimeItemIntent => "runtime_item_intent", } } pub(crate) fn format_ai_result_reference_kind(value: AiResultReferenceKind) -> &'static str { match value { AiResultReferenceKind::StorySession => "story_session", AiResultReferenceKind::StoryEvent => "story_event", AiResultReferenceKind::CustomWorldProfile => "custom_world_profile", AiResultReferenceKind::QuestRecord => "quest_record", AiResultReferenceKind::RuntimeItemRecord => "runtime_item_record", AiResultReferenceKind::AssetObject => "asset_object", } } pub(crate) fn map_custom_world_checkpoint_record( value: serde_json::Value, ) -> Result { let object = value.as_object().ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint 必须是 JSON object".to_string()) })?; let checkpoint_id = object .get("checkpointId") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.checkpointId 缺失".to_string()) })?; let created_at = object .get("createdAt") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.createdAt 缺失".to_string()) })?; let label = object .get("label") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world checkpoint.label 缺失".to_string()) })?; Ok(CustomWorldCheckpointRecord { checkpoint_id: checkpoint_id.to_string(), created_at: created_at.to_string(), label: label.to_string(), }) } pub(crate) fn parse_custom_world_publish_gate_record( value: &str, ) -> Result { let object = parse_json_value(value, "custom world publish_gate_json")? .as_object() .cloned() .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish_gate_json 必须是 JSON object".to_string(), ) })?; let profile_id = object .get("profileId") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.profileId 缺失".to_string()) })?; let blockers = object .get("blockers") .and_then(serde_json::Value::as_array) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.blockers 缺失".to_string()) })? .iter() .cloned() .map(|entry| { let object = entry.as_object().ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker 必须是 JSON object".to_string(), ) })?; let id = object .get("id") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.id 缺失".to_string(), ) })?; let code = object .get("code") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.code 缺失".to_string(), ) })?; let message = object .get("message") .and_then(serde_json::Value::as_str) .map(str::trim) .filter(|value| !value.is_empty()) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish gate blocker.message 缺失".to_string(), ) })?; Ok(CustomWorldResultPreviewBlockerRecord { id: id.to_string(), code: code.to_string(), message: message.to_string(), }) }) .collect::, _>>()?; let blocker_count = object .get("blockerCount") .and_then(serde_json::Value::as_u64) .and_then(|value| u32::try_from(value).ok()) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.blockerCount 缺失".to_string()) })?; let publish_ready = object .get("publishReady") .and_then(serde_json::Value::as_bool) .ok_or_else(|| { SpacetimeClientError::Runtime("custom world publish_gate.publishReady 缺失".to_string()) })?; let can_enter_world = object .get("canEnterWorld") .and_then(serde_json::Value::as_bool) .ok_or_else(|| { SpacetimeClientError::Runtime( "custom world publish_gate.canEnterWorld 缺失".to_string(), ) })?; Ok(CustomWorldPublishGateRecord { profile_id: profile_id.to_string(), blockers, blocker_count, publish_ready, can_enter_world, }) }