推进 server-rs DDD 分层与新接口接线

This commit is contained in:
Codex
2026-04-29 15:46:16 +08:00
parent 9d3fcfae77
commit f82775b852
89 changed files with 3657 additions and 9636 deletions

View File

@@ -1,4 +1,239 @@
//! AI 领域模型过渡落位。
//!
//! 当前历史实现仍在 `lib.rs`。后续迁移 `AiTask`、阶段、流式片段和结果引用时,
//! 只能放入纯领域类型与状态迁移,不能引入 LLM、HTTP 或 SpacetimeDB adapter。
use serde::{Deserialize, Serialize};
use shared_kernel::{
build_prefixed_seed_id, normalize_optional_string as normalize_shared_optional_string,
normalize_string_list as normalize_shared_string_list,
};
#[cfg(feature = "spacetime-types")]
use spacetimedb::SpacetimeType;
pub const AI_TASK_ID_PREFIX: &str = "aitask_";
pub const AI_TASK_STAGE_ID_PREFIX: &str = "aistage_";
pub const AI_RESULT_REF_ID_PREFIX: &str = "aires_";
pub const AI_TEXT_CHUNK_ID_PREFIX: &str = "aichunk_";
pub const INITIAL_AI_TASK_VERSION: u32 = 1;
// AI 编排类型与当前正式运行时主链保持一致,具体 prompt 策略留给上层模块。
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AiTaskKind {
StoryGeneration,
CharacterChat,
NpcChat,
CustomWorldGeneration,
QuestIntent,
RuntimeItemIntent,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AiTaskStatus {
Pending,
Running,
Completed,
Failed,
Cancelled,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AiTaskStageKind {
PreparePrompt,
RequestModel,
RepairResponse,
NormalizeResult,
PersistResult,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AiTaskStageStatus {
Pending,
Running,
Completed,
Skipped,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AiResultReferenceKind {
StorySession,
StoryEvent,
CustomWorldProfile,
QuestRecord,
RuntimeItemRecord,
AssetObject,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AiTaskStageBlueprint {
pub stage_kind: AiTaskStageKind,
pub label: String,
pub detail: String,
pub order: u32,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AiTaskStageSnapshot {
pub stage_kind: AiTaskStageKind,
pub label: String,
pub detail: String,
pub order: u32,
pub status: AiTaskStageStatus,
pub text_output: Option<String>,
pub structured_payload_json: Option<String>,
pub warning_messages: Vec<String>,
pub started_at_micros: Option<i64>,
pub completed_at_micros: Option<i64>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AiTaskSnapshot {
pub task_id: String,
pub task_kind: AiTaskKind,
pub owner_user_id: String,
pub request_label: String,
pub source_module: String,
pub source_entity_id: Option<String>,
pub request_payload_json: Option<String>,
pub status: AiTaskStatus,
pub failure_message: Option<String>,
pub stages: Vec<AiTaskStageSnapshot>,
pub result_references: Vec<AiResultReferenceSnapshot>,
pub latest_text_output: Option<String>,
pub latest_structured_payload_json: Option<String>,
pub version: u32,
pub created_at_micros: i64,
pub started_at_micros: Option<i64>,
pub completed_at_micros: Option<i64>,
pub updated_at_micros: i64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AiTextChunkSnapshot {
pub chunk_id: String,
pub task_id: String,
pub stage_kind: AiTaskStageKind,
pub sequence: u32,
pub delta_text: String,
pub created_at_micros: i64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AiResultReferenceSnapshot {
pub result_ref_id: String,
pub task_id: String,
pub reference_kind: AiResultReferenceKind,
pub reference_id: String,
pub label: Option<String>,
pub created_at_micros: i64,
}
impl AiTaskKind {
pub fn default_stage_blueprints(self) -> Vec<AiTaskStageBlueprint> {
let ordered_kinds = match self {
Self::StoryGeneration => vec![
AiTaskStageKind::PreparePrompt,
AiTaskStageKind::RequestModel,
AiTaskStageKind::RepairResponse,
AiTaskStageKind::NormalizeResult,
],
Self::CharacterChat | Self::NpcChat | Self::QuestIntent | Self::RuntimeItemIntent => {
vec![
AiTaskStageKind::PreparePrompt,
AiTaskStageKind::RequestModel,
AiTaskStageKind::NormalizeResult,
]
}
Self::CustomWorldGeneration => vec![
AiTaskStageKind::PreparePrompt,
AiTaskStageKind::RequestModel,
AiTaskStageKind::RepairResponse,
AiTaskStageKind::NormalizeResult,
AiTaskStageKind::PersistResult,
],
};
ordered_kinds
.into_iter()
.enumerate()
.map(|(index, stage_kind)| AiTaskStageBlueprint {
stage_kind,
label: stage_kind.default_label().to_string(),
detail: stage_kind.default_detail().to_string(),
order: index as u32,
})
.collect()
}
}
impl AiTaskStageKind {
pub fn as_str(self) -> &'static str {
match self {
Self::PreparePrompt => "prepare_prompt",
Self::RequestModel => "request_model",
Self::RepairResponse => "repair_response",
Self::NormalizeResult => "normalize_result",
Self::PersistResult => "persist_result",
}
}
pub fn default_label(self) -> &'static str {
match self {
Self::PreparePrompt => "整理提示词",
Self::RequestModel => "请求模型",
Self::RepairResponse => "修复响应",
Self::NormalizeResult => "归一结果",
Self::PersistResult => "回写结果",
}
}
pub fn default_detail(self) -> &'static str {
match self {
Self::PreparePrompt => "整理输入上下文并构建本轮提示词。",
Self::RequestModel => "向上游模型发起正式推理请求。",
Self::RepairResponse => "对非严格输出做补救修复或二次编排。",
Self::NormalizeResult => "把模型输出归一成模块可消费结构。",
Self::PersistResult => "把结果引用或聚合状态回写到下游模块。",
}
}
}
impl AiTaskStatus {
pub fn is_terminal(self) -> bool {
matches!(self, Self::Completed | Self::Failed | Self::Cancelled)
}
}
pub fn generate_ai_task_id(seed_micros: i64) -> String {
build_prefixed_seed_id(AI_TASK_ID_PREFIX, seed_micros)
}
pub fn generate_ai_task_stage_id(task_id: &str, stage_kind: AiTaskStageKind) -> String {
format!(
"{}{}_{}",
AI_TASK_STAGE_ID_PREFIX,
task_id.trim(),
stage_kind.as_str()
)
}
pub fn generate_ai_result_ref_id(seed_micros: i64) -> String {
build_prefixed_seed_id(AI_RESULT_REF_ID_PREFIX, seed_micros)
}
pub fn generate_ai_text_chunk_id(seed_micros: i64, sequence: u32) -> String {
format!("{}{seed_micros:x}_{sequence:x}", AI_TEXT_CHUNK_ID_PREFIX)
}
pub fn normalize_optional_text(value: Option<String>) -> Option<String> {
normalize_shared_optional_string(value)
}
pub fn normalize_string_list(values: Vec<String>) -> Vec<String> {
normalize_shared_string_list(values)
}