This commit is contained in:
164
server-rs/crates/shared-contracts/src/story.rs
Normal file
164
server-rs/crates/shared-contracts/src/story.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BeginStorySessionRequest {
|
||||
pub runtime_session_id: String,
|
||||
pub world_profile_id: String,
|
||||
pub initial_prompt: String,
|
||||
#[serde(default)]
|
||||
pub opening_summary: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ContinueStoryRequest {
|
||||
pub story_session_id: String,
|
||||
pub narrative_text: String,
|
||||
#[serde(default)]
|
||||
pub choice_function_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StorySessionPayload {
|
||||
pub story_session_id: String,
|
||||
pub runtime_session_id: String,
|
||||
pub actor_user_id: String,
|
||||
pub world_profile_id: String,
|
||||
pub initial_prompt: String,
|
||||
#[serde(default)]
|
||||
pub opening_summary: Option<String>,
|
||||
pub latest_narrative_text: String,
|
||||
#[serde(default)]
|
||||
pub latest_choice_function_id: Option<String>,
|
||||
pub status: String,
|
||||
pub version: u32,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StoryEventPayload {
|
||||
pub event_id: String,
|
||||
pub story_session_id: String,
|
||||
pub event_kind: String,
|
||||
pub narrative_text: String,
|
||||
#[serde(default)]
|
||||
pub choice_function_id: Option<String>,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StorySessionMutationResponse {
|
||||
pub story_session: StorySessionPayload,
|
||||
pub story_event: StoryEventPayload,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StorySessionStateResponse {
|
||||
pub story_session: StorySessionPayload,
|
||||
pub story_events: Vec<StoryEventPayload>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn continue_story_request_uses_camel_case_fields() {
|
||||
let payload = serde_json::to_value(ContinueStoryRequest {
|
||||
story_session_id: "storysess_1".to_string(),
|
||||
narrative_text: "继续前进".to_string(),
|
||||
choice_function_id: Some("npc_chat".to_string()),
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(
|
||||
payload,
|
||||
json!({
|
||||
"storySessionId": "storysess_1",
|
||||
"narrativeText": "继续前进",
|
||||
"choiceFunctionId": "npc_chat"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn story_session_mutation_response_uses_camel_case_fields() {
|
||||
let payload = serde_json::to_value(StorySessionMutationResponse {
|
||||
story_session: StorySessionPayload {
|
||||
story_session_id: "storysess_1".to_string(),
|
||||
runtime_session_id: "runtime_1".to_string(),
|
||||
actor_user_id: "user_1".to_string(),
|
||||
world_profile_id: "profile_1".to_string(),
|
||||
initial_prompt: "进入营地".to_string(),
|
||||
opening_summary: Some("营地开场".to_string()),
|
||||
latest_narrative_text: "篝火正在燃烧。".to_string(),
|
||||
latest_choice_function_id: Some("talk".to_string()),
|
||||
status: "active".to_string(),
|
||||
version: 1,
|
||||
created_at: "1.000000Z".to_string(),
|
||||
updated_at: "1.000000Z".to_string(),
|
||||
},
|
||||
story_event: StoryEventPayload {
|
||||
event_id: "storyevt_1".to_string(),
|
||||
story_session_id: "storysess_1".to_string(),
|
||||
event_kind: "session_started".to_string(),
|
||||
narrative_text: "篝火正在燃烧。".to_string(),
|
||||
choice_function_id: Some("talk".to_string()),
|
||||
created_at: "1.000000Z".to_string(),
|
||||
},
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(
|
||||
payload["storySession"]["storySessionId"],
|
||||
json!("storysess_1")
|
||||
);
|
||||
assert_eq!(payload["storyEvent"]["eventKind"], json!("session_started"));
|
||||
assert_eq!(payload["storyEvent"]["choiceFunctionId"], json!("talk"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn story_session_state_response_uses_camel_case_fields() {
|
||||
let payload = serde_json::to_value(StorySessionStateResponse {
|
||||
story_session: StorySessionPayload {
|
||||
story_session_id: "storysess_1".to_string(),
|
||||
runtime_session_id: "runtime_1".to_string(),
|
||||
actor_user_id: "user_1".to_string(),
|
||||
world_profile_id: "profile_1".to_string(),
|
||||
initial_prompt: "进入营地".to_string(),
|
||||
opening_summary: Some("营地开场".to_string()),
|
||||
latest_narrative_text: "你看见篝火边有人招手。".to_string(),
|
||||
latest_choice_function_id: Some("talk_to_npc".to_string()),
|
||||
status: "active".to_string(),
|
||||
version: 2,
|
||||
created_at: "1.000000Z".to_string(),
|
||||
updated_at: "2.000000Z".to_string(),
|
||||
},
|
||||
story_events: vec![StoryEventPayload {
|
||||
event_id: "storyevt_2".to_string(),
|
||||
story_session_id: "storysess_1".to_string(),
|
||||
event_kind: "story_continued".to_string(),
|
||||
narrative_text: "你看见篝火边有人招手。".to_string(),
|
||||
choice_function_id: Some("talk_to_npc".to_string()),
|
||||
created_at: "2.000000Z".to_string(),
|
||||
}],
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(
|
||||
payload["storySession"]["latestChoiceFunctionId"],
|
||||
json!("talk_to_npc")
|
||||
);
|
||||
assert_eq!(
|
||||
payload["storyEvents"][0]["eventKind"],
|
||||
json!("story_continued")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user