diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index ab2b7ef82..a2d1ce0b4 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -65,7 +65,9 @@ use spacetime_client::{ use crate::{ api_response::json_success_body, asset_billing::{ - begin_editor_generation_commit_attempt, editor_generation_commit_attempt_was_dispatched, + begin_editor_generation_commit_attempt, + current_external_generation_billing_price_mud_points, + editor_generation_commit_attempt_was_dispatched, execute_billable_asset_operation_with_cost, mark_editor_generation_commit_dispatched, mark_editor_generation_commit_outcome_confirmed, with_editor_generation_durable_billing_boundary, @@ -2952,20 +2954,25 @@ where } else { provider_request_size }; - let configured_price_mud_points = state - .editor_generation_pricing() - .await - .map_err(|error| { - AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ - "provider": "editor-generation-pricing", - "message": error.to_string(), - })) - })? - .image_generation_mud_points( - normalized_kind, - Some(generation_options.model), - Some(generation_options.image_size), - ); + let effective_price_mud_points = + if let Some(price_mud_points) = current_external_generation_billing_price_mud_points() { + price_mud_points + } else { + state + .editor_generation_pricing() + .await + .map_err(|error| { + AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({ + "provider": "editor-generation-pricing", + "message": error.to_string(), + })) + })? + .image_generation_mud_points( + normalized_kind, + Some(generation_options.model), + Some(generation_options.image_size), + ) + }; let prompt_generation_inputs = payload.generation_inputs.take(); let generate_operation = async { let prompt_build = prompt_builder(prompt_generation_inputs).await?; @@ -3062,7 +3069,7 @@ where caller.owner_user_id.as_str(), editor_image_generation_billing_asset_kind(normalized_kind), request_context.request_id(), - u64::from(configured_price_mud_points), + u64::from(effective_price_mud_points), generate_operation, ) .await?; @@ -3168,7 +3175,7 @@ where .clone() .or_else(|| Some("character".to_string())), generation_inputs: generation_inputs.clone(), - generation_cost_mud_points: u64::from(configured_price_mud_points), + generation_cost_mud_points: u64::from(effective_price_mud_points), thumbnail_src: None, group_task_id: None, group_task_expected_asset_count: None, @@ -3435,7 +3442,7 @@ where generation_cost_mud_points: if is_character_generation { 0 } else { - u64::from(configured_price_mud_points) + u64::from(effective_price_mud_points) }, image_sequence_frames: None, image_sequence_duration_ms: None, @@ -15970,7 +15977,7 @@ mod tests { assert_function_contains( source, "pub(crate) async fn generate_editor_image_for_owner", - "let configured_price_mud_points", + "let effective_price_mud_points", &[ "is_publication_material_generation", "Some(GPT_IMAGE_2_MODEL)", @@ -18951,7 +18958,7 @@ mod tests { "fn normalize_editor_image_generation_size", &[ "execute_billable_asset_operation_with_cost", - "configured_price_mud_points", + "effective_price_mud_points", ], ); assert_function_contains( @@ -18983,6 +18990,23 @@ mod tests { ); } + #[test] + fn queued_image_generation_persists_the_frozen_billing_price() { + let source = include_str!("editor_project.rs"); + assert_function_contains_in_order( + source, + "pub(crate) async fn generate_editor_image_for_owner_with_prompt_builder", + "fn editor_image_generation_billing_asset_kind", + &[ + "current_external_generation_billing_price_mud_points()", + ".editor_generation_pricing()", + "execute_billable_asset_operation_with_cost(", + "u64::from(effective_price_mud_points)", + "generation_cost_mud_points: u64::from(effective_price_mud_points)", + ], + ); + } + #[test] fn editor_ui_design_asset_extraction_commits_prepared_bundle_atomically() { let source = include_str!("editor_project.rs");