diff --git a/packages/backend/native/src/runtime/backend_runtime/copilot/context.rs b/packages/backend/native/src/runtime/backend_runtime/copilot/context.rs index af0943f6ee..05d6b977ec 100644 --- a/packages/backend/native/src/runtime/backend_runtime/copilot/context.rs +++ b/packages/backend/native/src/runtime/backend_runtime/copilot/context.rs @@ -248,9 +248,12 @@ fn managed_endpoint(profile: &CopilotManagedProfileConfig) -> RuntimeResult format!( "https://api.cloudflare.com/client/v4/accounts/{}/ai", @@ -311,3 +314,41 @@ pub(super) fn required_config_text<'a>( .filter(|value| !value.trim().is_empty()) .ok_or_else(|| RuntimeError::invalid_state(format!("managed copilot profile requires {field}"))) } + +#[cfg(test)] +mod tests { + use serde_json::json; + + use super::{BackendEndpoint, CopilotManagedProfileConfig, managed_endpoint}; + + fn vertex_profile(location: &str) -> CopilotManagedProfileConfig { + CopilotManagedProfileConfig { + id: "vertex".to_string(), + provider: "geminiVertex".to_string(), + enabled: true, + models: vec!["gemini-3.6-flash".to_string()], + config: json!({ "project": "affine-us", "location": location }), + } + } + + #[test] + fn managed_vertex_endpoint_uses_global_host() { + assert_eq!( + managed_endpoint(&vertex_profile("global")).unwrap(), + BackendEndpoint::Custom( + "https://aiplatform.googleapis.com/v1/projects/affine-us/locations/global/publishers/google".to_string() + ) + ); + } + + #[test] + fn managed_vertex_endpoint_uses_regional_host() { + assert_eq!( + managed_endpoint(&vertex_profile("us-central1")).unwrap(), + BackendEndpoint::Custom( + "https://us-central1-aiplatform.googleapis.com/v1/projects/affine-us/locations/us-central1/publishers/google" + .to_string() + ) + ); + } +} diff --git a/packages/frontend/core/src/modules/media/entities/audio-attachment-block.ts b/packages/frontend/core/src/modules/media/entities/audio-attachment-block.ts index 062c52c748..8eb4fea2ef 100644 --- a/packages/frontend/core/src/modules/media/entities/audio-attachment-block.ts +++ b/packages/frontend/core/src/modules/media/entities/audio-attachment-block.ts @@ -169,8 +169,8 @@ export class AudioAttachmentBlock extends Entity { readonly transcribe = async () => { try { - // if job is already running, we should not start it again - if (this.transcriptionJob.status$.value.status !== 'waiting-for-job') { + const initialStatus = this.transcriptionJob.status$.value.status; + if (initialStatus !== 'waiting-for-job' && initialStatus !== 'failed') { return; } const status = await this.transcriptionJob.start();