From 02c256e994337b98ca78675c0df092cb726aaf4c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 29 Mar 2026 08:06:27 -0400 Subject: [PATCH] failure state --- .../poll_characters/poll_characters.rs | 79 +++++++++++++------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/crates/api_clients/seedance2pro_client/src/requests/poll_characters/poll_characters.rs b/crates/api_clients/seedance2pro_client/src/requests/poll_characters/poll_characters.rs index 4e31f73cfb..79acbb922c 100644 --- a/crates/api_clients/seedance2pro_client/src/requests/poll_characters/poll_characters.rs +++ b/crates/api_clients/seedance2pro_client/src/requests/poll_characters/poll_characters.rs @@ -29,29 +29,46 @@ pub struct PollCharactersResponse { // --- Public types --- -/// The lifecycle status of a character creation task. +/// Our resolved status for a character creation job. +/// +/// This is NOT 1:1 with Kinovi's API. A character can have `taskStatus: "COMPLETED"` +/// but `assetStatus: "Failed"`, which we treat as `Failed` on our end. #[derive(Debug, Clone, PartialEq)] -pub enum CharacterTaskStatus { - Pending, - Processing, - Completed, +pub enum CharacterCreationStatus { + /// The character was successfully created and the asset is active. + Success, + /// The character creation failed (either the task failed or the asset failed). Failed, - Unknown(String), + /// The character is still being created (pending or processing). + Pending, } -impl CharacterTaskStatus { - fn from_str(s: &str) -> Self { - match s { - "PENDING" => Self::Pending, - "PROCESSING" => Self::Processing, - "COMPLETED" => Self::Completed, +impl CharacterCreationStatus { + /// Derive our status from the raw Kinovi API fields. + /// + /// Logic: + /// - taskStatus "FAILED" => Failed + /// - taskStatus "COMPLETED" + assetStatus "Active" => Success + /// - taskStatus "COMPLETED" + assetStatus "Failed" => Failed + /// - taskStatus "COMPLETED" + assetStatus is null/other => Failed (defensive) + /// - taskStatus "PENDING" or "PROCESSING" => Pending + /// - anything else => Pending (defensive) + fn from_api(task_status: &str, asset_status: Option<&str>) -> Self { + match task_status { "FAILED" => Self::Failed, - other => Self::Unknown(other.to_string()), + "COMPLETED" => { + match asset_status { + Some("Active") => Self::Success, + _ => Self::Failed, + } + } + "PENDING" | "PROCESSING" => Self::Pending, + _ => Self::Pending, } } pub fn is_terminal(&self) -> bool { - matches!(self, Self::Completed | Self::Failed) + matches!(self, Self::Success | Self::Failed) } } @@ -83,17 +100,20 @@ pub struct CharacterStatus { /// Result images generated during character creation. pub result_images: Vec, - /// The task status. - pub task_status: CharacterTaskStatus, + /// Our resolved status (Success, Failed, or Pending). + pub status: CharacterCreationStatus, - /// If the task failed, the reason. + /// If the task failed, the reason from the API. pub fail_reason: Option, - /// The asset ID, present when the character is completed. + /// The asset ID, present when the character completed successfully. pub asset_id: Option, - /// The asset status (e.g. "Active"), present when the character is completed. - pub asset_status: Option, + /// Raw task status from the Kinovi API (for debugging). + pub raw_task_status: String, + + /// Raw asset status from the Kinovi API (for debugging). + pub raw_asset_status: Option, /// ISO 8601 timestamp of creation. pub created_at: String, @@ -185,6 +205,11 @@ pub async fn poll_characters(args: PollCharactersArgs<'_>) -> Result) -> Result