//! 剧情领域事件。 //! //! 事件只表达 story session 已经发生的领域事实;是否写入 SpacetimeDB event table 或 //! 映射成 HTTP/SSE 输出,由外层 adapter 决定。 use crate::domain::StorySessionSnapshot; use serde::{Deserialize, Serialize}; use shared_kernel::build_prefixed_seed_id; #[cfg(feature = "spacetime-types")] use spacetimedb::SpacetimeType; /// 剧情事件 ID 的稳定前缀。 pub const STORY_EVENT_ID_PREFIX: &str = "storyevt_"; /// 剧情事件类型,当前覆盖开局和续写两条最小主链。 #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum StoryEventKind { SessionStarted, StoryContinued, } impl StoryEventKind { pub fn as_str(&self) -> &'static str { match self { Self::SessionStarted => "session_started", Self::StoryContinued => "story_continued", } } } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct StoryEventSnapshot { pub event_id: String, pub story_session_id: String, pub event_kind: StoryEventKind, pub narrative_text: String, pub choice_function_id: Option, pub created_at_micros: i64, } pub fn build_story_started_event(snapshot: &StorySessionSnapshot) -> StoryEventSnapshot { StoryEventSnapshot { event_id: generate_story_event_id(snapshot.created_at_micros), story_session_id: snapshot.story_session_id.clone(), event_kind: StoryEventKind::SessionStarted, narrative_text: snapshot .opening_summary .clone() .unwrap_or_else(|| snapshot.initial_prompt.clone()), choice_function_id: None, created_at_micros: snapshot.created_at_micros, } } pub fn generate_story_event_id(seed_micros: i64) -> String { build_prefixed_seed_id(STORY_EVENT_ID_PREFIX, seed_micros) }