use std::collections::HashMap; use anyhow::{Context, Result, anyhow};use async_channel::Sender;use async_trait::async_trait;use chrono::{DateTime, Utc};// #[cfg(any(test, feature = "test-util"))]// pub use cloud_object_client::MockObjectClient;use cloud_object_client::{ GetCloudObjectResponse, InitialLoadResponse, ObjectActionHistory, ObjectActionType, ObjectDeleteResult, ObjectMetadataUpdateResult, ObjectPermissionUpdateResult, ObjectPermissionsUpdateData, ObjectUpdateMessage,};pub use cloud_object_client::{GuestIdentifier, ObjectClient};use cloud_object_models::JsonSerializer;use cynic::{MutationBuilder, QueryBuilder, SubscriptionBuilder};use warp_errors::report_error;use warp_graphql::error::UserFacingErrorInterface;use warp_graphql::generic_string_object::GenericStringObjectInput;use warp_graphql::mutations::add_object_guests::{ AddObjectGuests, AddObjectGuestsInput, AddObjectGuestsResult, AddObjectGuestsVariables,};use warp_graphql::mutations::bulk_create_objects::{ BulkCreateGenericStringObjectsInput, BulkCreateObjects, BulkCreateObjectsInput, BulkCreateObjectsResult, BulkCreateObjectsVariables,};use warp_graphql::mutations::create_folder::{ CreateFolder, CreateFolderInput, CreateFolderResult, CreateFolderVariables,};use warp_graphql::mutations::create_generic_string_object::{ CreateGenericStringObject, CreateGenericStringObjectInput, CreateGenericStringObjectResult, CreateGenericStringObjectVariables,};use warp_graphql::mutations::create_notebook::{ CreateNotebook, CreateNotebookInput, CreateNotebookResult, CreateNotebookVariables,};use warp_graphql::mutations::create_workflow::{ CreateWorkflow, CreateWorkflowInput, CreateWorkflowResult, CreateWorkflowVariables,};use warp_graphql::mutations::delete_object::{ DeleteObject, DeleteObjectInput, DeleteObjectResult, DeleteObjectVariables,};use warp_graphql::mutations::empty_trash::{ EmptyTrash, EmptyTrashInput, EmptyTrashResult, EmptyTrashVariables,};use warp_graphql::mutations::give_up_notebook_edit_access::{ GiveUpNotebookEditAccess, GiveUpNotebookEditAccessVariables,};use warp_graphql::mutations::grab_notebook_edit_access::{ GrabNotebookEditAccess, GrabNotebookEditAccessVariables,};use warp_graphql::mutations::leave_object::{ LeaveObject, LeaveObjectInput, LeaveObjectResult, LeaveObjectVariables,};use warp_graphql::mutations::move_object::{ MoveObject, MoveObjectInput, MoveObjectResult, MoveObjectVariables,};use warp_graphql::mutations::record_object_action::{ RecordObjectAction, RecordObjectActionInput, RecordObjectActionResult, RecordObjectActionVariables,};use warp_graphql::mutations::remove_object_guest::{ RemoveObjectGuest, RemoveObjectGuestInput, RemoveObjectGuestResult, RemoveObjectGuestVariables,};use warp_graphql::mutations::remove_object_link_permissions::{ RemoveObjectLinkPermissions, RemoveObjectLinkPermissionsInput, RemoveObjectLinkPermissionsResult, RemoveObjectLinkPermissionsVariables,};use warp_graphql::mutations::set_object_link_permissions::{ SetObjectLinkPermissions, SetObjectLinkPermissionsInput, SetObjectLinkPermissionsResult, SetObjectLinkPermissionsVariables,};use warp_graphql::mutations::transfer_generic_string_object_owner::{ TransferGenericStringObjectOwner, TransferGenericStringObjectOwnerInput, TransferGenericStringObjectOwnerResult, TransferGenericStringObjectOwnerVariables,};use warp_graphql::mutations::transfer_notebook_owner::{ TransferNotebookOwner, TransferNotebookOwnerInput, TransferNotebookOwnerResult, TransferNotebookOwnerVariables,};use warp_graphql::mutations::transfer_workflow_owner::{ TransferWorkflowOwner, TransferWorkflowOwnerInput, TransferWorkflowOwnerResult, TransferWorkflowOwnerVariables,};use warp_graphql::mutations::trash_object::{ TrashObject, TrashObjectInput, TrashObjectResult, TrashObjectVariables,};use warp_graphql::mutations::untrash_object::{ UntrashObject, UntrashObjectInput, UntrashObjectVariables,};use warp_graphql::mutations::update_folder::{ UpdateFolder, UpdateFolderInput, UpdateFolderResult, UpdateFolderVariables,};use warp_graphql::mutations::update_generic_string_object::{ UpdateGenericStringObject, UpdateGenericStringObjectInput, UpdateGenericStringObjectVariables,};use warp_graphql::mutations::update_notebook::{ NotebookUpdate, UpdateNotebook, UpdateNotebookInput, UpdateNotebookResult, UpdateNotebookVariables,};use warp_graphql::mutations::update_object_guests::{ UpdateObjectGuests, UpdateObjectGuestsInput, UpdateObjectGuestsResult, UpdateObjectGuestsVariables,};use warp_graphql::mutations::update_workflow::{ UpdateWorkflow, UpdateWorkflowInput, UpdateWorkflowResult, UpdateWorkflowVariables, WorkflowUpdate,};use warp_graphql::notebook::{UpdateNotebookEditAccessInput, UpdateNotebookEditAccessResult};use warp_graphql::object::CloudObjectWithDescendants;use warp_graphql::object_permissions::AccessLevel;use warp_graphql::queries::get_cloud_environments::{ GetCloudEnvironmentsQuery, GetCloudEnvironmentsQueryVariables, GetCloudEnvironmentsResult,};use warp_graphql::queries::get_cloud_object::{ CloudObjectInput, CloudObjectResult, GetCloudObject, GetCloudObjectVariables,};use warp_graphql::queries::get_updated_cloud_objects::{ GetUpdatedCloudObjects, GetUpdatedCloudObjectsVariables, UpdatedCloudObjectsInput, UpdatedCloudObjectsResult,};use warp_graphql::subscriptions::get_warp_drive_updates::GetWarpDriveUpdates;use warp_graphql::subscriptions::start_graphql_streaming_operation; use crate::ai::ambient_agents::scheduled::ScheduledAmbientAgent;use crate::ai::cloud_environments::AmbientAgentEnvironment;use crate::ai::document::ai_document_model::AIDocumentId;use crate::ai::execution_profiles::AIExecutionProfile;use crate::ai::facts::AIFact;use crate::ai::mcp::{MCPServer, TemplatableMCPServer};use crate::channel::ChannelState;use crate::cloud_object::model::generic_string_model::{ GenericStringModel, GenericStringObjectId, Serializer, StringModel,};use crate::cloud_object::{ BulkCreateCloudObjectResult, BulkCreateGenericStringObjectsRequest, CreateCloudObjectResult, CreateObjectRequest, CreatedCloudObject, GenericCloudObject, GenericServerObject, GenericStringObjectFormat, GenericStringObjectUniqueKey, JsonObjectType, ObjectIdType, ObjectType, ObjectsToUpdate, Owner, Revision, RevisionAndLastEditor, ServerCloudObject, ServerFolder, ServerMetadata, ServerNotebook, ServerObject, ServerPermissions, ServerWorkflow, TryFromGql as _, UpdateCloudObjectResult,};use crate::drive::folders::FolderId;use crate::drive::sharing::SharingAccessLevel;use crate::env_vars::EnvVarCollection;use crate::notebooks::{NotebookId, SerializedNotebook};use crate::server::graphql::schema::{ action_type_to_gql_action_type, object_action_history_from_gql, object_update_success_to_update_result, update_generic_string_object_result_to_update_result,};use crate::server::graphql::{get_request_context, get_user_facing_error_message};use crate::server::ids::{ClientId, HashableId, ServerId, ServerIdAndType, SyncId, ToServerId};use crate::server::server_api::ServerApi;use crate::server::sync_queue::SerializedModel;use crate::settings::Preference;use crate::workflows::WorkflowId;use crate::workflows::workflow_enum::WorkflowEnum;use crate::workspaces::gql_convert::object_update_message_from_gql;use crate::workspaces::user_profiles::UserProfileWithUID; #[cfg_attr(not(target_family = "wasm"), async_trait)]#[cfg_attr(target_family = "wasm", async_trait(?Send))]impl ObjectClient for ServerApi { async fn create_workflow( &self, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let model = request .serialized_model .ok_or_else(|| anyhow!("missing model for creating workflow"))?; let variables = CreateWorkflowVariables { input: CreateWorkflowInput { data: model.take(), entrypoint: request.entrypoint.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), owner: request.owner.into(), }, request_context: get_request_context(), }; let operation = CreateWorkflow::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_workflow { CreateWorkflowResult::CreateWorkflowOutput(output) => { let metadata = output.workflow.metadata; let workflow_id: WorkflowId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { client_id: request.client_id, revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: workflow_id.to_server_id(), id_type: ObjectIdType::Workflow, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: output.workflow.permissions.try_into()?, }, }) } CreateWorkflowResult::UserFacingError(e) => Ok( CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), ), CreateWorkflowResult::Unknown => { Err(anyhow!("Failed to create workflow due to unknown variant")) } } } async fn update_workflow( &self, workflow_id: WorkflowId, data: SerializedModel, revision: Option<Revision>, ) -> Result<UpdateCloudObjectResult<ServerWorkflow>> { let variables = UpdateWorkflowVariables { input: UpdateWorkflowInput { data: data.model_as_str().to_owned(), uid: cynic::Id::new(workflow_id), revision_ts: revision.map(|r| r.into()), }, request_context: get_request_context(), }; let operation = UpdateWorkflow::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.update_workflow { UpdateWorkflowResult::UpdateWorkflowOutput(output) => match output.update { WorkflowUpdate::ObjectUpdateSuccess(success) => { Ok(UpdateCloudObjectResult::Success { revision_and_editor: RevisionAndLastEditor { revision: success.revision_ts.into(), last_editor_uid: Some(success.last_editor_uid.into_inner()), }, }) } WorkflowUpdate::WorkflowUpdateRejected(rejected) => { Ok(UpdateCloudObjectResult::Rejected { object: ServerWorkflow::try_from_gql(rejected.conflicting_workflow)?, }) } WorkflowUpdate::Unknown => Err(anyhow!("WorkflowUpdate has unknown variant")), }, UpdateWorkflowResult::UserFacingError(e) => { Err(anyhow!(get_user_facing_error_message(e))) } UpdateWorkflowResult::Unknown => { Err(anyhow!("Failed to update workflow due to unknown variant")) } } } async fn bulk_create_generic_string_objects( &self, owner: Owner, objects: &[BulkCreateGenericStringObjectsRequest], ) -> Result<BulkCreateCloudObjectResult> { let variables = BulkCreateObjectsVariables { input: BulkCreateObjectsInput { generic_string_objects: Some(BulkCreateGenericStringObjectsInput { owner: owner.into(), objects: objects .iter() .map(|object| GenericStringObjectInput { client_id: cynic::Id::new(object.id.to_string()), serialized_model: object.serialized_model.model_as_str().to_owned(), format: object.format.into(), uniqueness_key: object .uniqueness_key .clone() .map(GenericStringObjectUniqueKey::into), initial_folder_id: object.initial_folder_id.map(FolderId::into), entrypoint: object.entrypoint.into(), }) .collect(), }), }, request_context: get_request_context(), }; let operation = BulkCreateObjects::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.bulk_create_objects { BulkCreateObjectsResult::BulkCreateObjectsOutput(output) => { if let Some(gso_result) = output.generic_string_objects { let mut created_cloud_objects = Vec::new(); for gso in gso_result.objects { let metadata = gso.generic_string_object.metadata; let uid = metadata.uid.into_inner(); let object_id: GenericStringObjectId = uid.into(); created_cloud_objects.push(CreatedCloudObject { client_id: ClientId::from_hash(&gso.client_id.into_inner()) .ok_or_else(|| anyhow!("invalid client id"))?, revision_and_editor: RevisionAndLastEditor { revision: metadata.revision_ts.into(), last_editor_uid: metadata .last_editor_uid .map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: object_id.to_server_id(), id_type: ObjectIdType::GenericStringObject, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: gso.generic_string_object.permissions.try_into()?, }); } Ok(BulkCreateCloudObjectResult::Success { created_cloud_objects, }) } else { Err(anyhow!( "No generic string objects found in BulkCreateGenericStringObjectsOutput" )) } } BulkCreateObjectsResult::UserFacingError(e) => match e.error { UserFacingErrorInterface::GenericStringObjectUniqueKeyConflict(_) => { Ok(BulkCreateCloudObjectResult::GenericStringObjectUniqueKeyConflict) } _ => Err(anyhow!(get_user_facing_error_message(e))), }, BulkCreateObjectsResult::Unknown => Err(anyhow!( "Failed to bulk create objects due to unknown variant" )), } } async fn create_generic_string_object( &self, format: GenericStringObjectFormat, uniqueness_key: Option<GenericStringObjectUniqueKey>, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let model = request .serialized_model .ok_or_else(|| anyhow!("missing model for creating generic string model"))?; let variables = CreateGenericStringObjectVariables { input: CreateGenericStringObjectInput { generic_string_object: GenericStringObjectInput { client_id: cynic::Id::new(request.client_id.to_hash()), entrypoint: request.entrypoint.into(), format: format.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), serialized_model: model.take(), uniqueness_key: uniqueness_key.map(|key| key.into()), }, owner: request.owner.into(), }, request_context: get_request_context(), }; let operation = CreateGenericStringObject::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_generic_string_object { CreateGenericStringObjectResult::CreateGenericStringObjectOutput(output) => { let metadata = output.generic_string_object.metadata; let gso_id: GenericStringObjectId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: gso_id.to_server_id(), id_type: ObjectIdType::GenericStringObject, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), client_id: request.client_id, permissions: output.generic_string_object.permissions.try_into()?, }, }) } CreateGenericStringObjectResult::UserFacingError(e) => Ok(match e.error { UserFacingErrorInterface::GenericStringObjectUniqueKeyConflict(_) => { CreateCloudObjectResult::GenericStringObjectUniqueKeyConflict } _ => CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), }), CreateGenericStringObjectResult::Unknown => Err(anyhow!( "Failed to create generic string object due to unknown variant" )), } } async fn create_notebook( &self, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let serialized = request .serialized_model .as_ref() .ok_or_else(|| anyhow!("Missing serialized model for notebook"))?; let notebook: SerializedNotebook = serde_json::from_str(serialized.model_as_str()) .context("Failed to deserialize notebook model")?; let ai_document_id = notebook .ai_document_id .and_then(|id| AIDocumentId::try_from(id).ok()); let variables = CreateNotebookVariables { input: CreateNotebookInput { data: Some(notebook.data), entrypoint: request.entrypoint.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), owner: request.owner.into(), title: request.title, ai_document_id: ai_document_id.map(|id| id.to_string()), conversation_id: notebook.conversation_id, }, request_context: get_request_context(), }; let operation = CreateNotebook::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_notebook { CreateNotebookResult::CreateNotebookOutput(output) => { let metadata = output.notebook.metadata; let notebook_id: NotebookId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { client_id: request.client_id, revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: notebook_id.to_server_id(), id_type: ObjectIdType::Notebook, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: output.notebook.permissions.try_into()?, }, }) } CreateNotebookResult::UserFacingError(e) => Ok( CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), ), CreateNotebookResult::Unknown => { Err(anyhow!("Failed to create notebook due to unknown variant")) } } } async fn update_notebook( &self, notebook_id: NotebookId, title: Option<String>, data: Option<SerializedModel>, revision: Option<Revision>, ) -> Result<UpdateCloudObjectResult<ServerNotebook>> { let variables = UpdateNotebookVariables { input: UpdateNotebookInput { data: data.map(|data| data.model_as_str().to_owned()), title, uid: cynic::Id::new(notebook_id), revision_ts: revision.map(|r| r.into()), }, request_context: get_request_context(), }; let operation = UpdateNotebook::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.update_notebook { UpdateNotebookResult::UpdateNotebookOutput(output) => match output.update { NotebookUpdate::ObjectUpdateSuccess(success) => { Ok(UpdateCloudObjectResult::Success { revision_and_editor: RevisionAndLastEditor { revision: success.revision_ts.into(), last_editor_uid: Some(success.last_editor_uid.into_inner()), }, }) } NotebookUpdate::NotebookUpdateRejected(rejected) => { Ok(UpdateCloudObjectResult::Rejected { object: ServerNotebook::try_from_gql(rejected.conflicting_notebook)?, }) } NotebookUpdate::Unknown => Err(anyhow!("NotebookUpdate has unknown variant")), }, UpdateNotebookResult::UserFacingError(e) => { Err(anyhow!(get_user_facing_error_message(e))) } UpdateNotebookResult::Unknown => {Lines 1–500 of 1416. Load more
use std::collections::HashMap; use anyhow::{Context, Result, anyhow}; use async_channel::Sender; use async_trait::async_trait; use chrono::{DateTime, Utc}; // #[cfg(any(test, feature = "test-util"))] // pub use cloud_object_client::MockObjectClient; use cloud_object_client::{ GetCloudObjectResponse, InitialLoadResponse, ObjectActionHistory, ObjectActionType, ObjectDeleteResult, ObjectMetadataUpdateResult, ObjectPermissionUpdateResult, ObjectPermissionsUpdateData, ObjectUpdateMessage, }; pub use cloud_object_client::{GuestIdentifier, ObjectClient}; use cloud_object_models::JsonSerializer; use cynic::{MutationBuilder, QueryBuilder, SubscriptionBuilder}; use warp_errors::report_error; use warp_graphql::error::UserFacingErrorInterface; use warp_graphql::generic_string_object::GenericStringObjectInput; use warp_graphql::mutations::add_object_guests::{ AddObjectGuests, AddObjectGuestsInput, AddObjectGuestsResult, AddObjectGuestsVariables, }; use warp_graphql::mutations::bulk_create_objects::{ BulkCreateGenericStringObjectsInput, BulkCreateObjects, BulkCreateObjectsInput, BulkCreateObjectsResult, BulkCreateObjectsVariables, }; use warp_graphql::mutations::create_folder::{ CreateFolder, CreateFolderInput, CreateFolderResult, CreateFolderVariables, }; use warp_graphql::mutations::create_generic_string_object::{ CreateGenericStringObject, CreateGenericStringObjectInput, CreateGenericStringObjectResult, CreateGenericStringObjectVariables, }; use warp_graphql::mutations::create_notebook::{ CreateNotebook, CreateNotebookInput, CreateNotebookResult, CreateNotebookVariables, }; use warp_graphql::mutations::create_workflow::{ CreateWorkflow, CreateWorkflowInput, CreateWorkflowResult, CreateWorkflowVariables, }; use warp_graphql::mutations::delete_object::{ DeleteObject, DeleteObjectInput, DeleteObjectResult, DeleteObjectVariables, }; use warp_graphql::mutations::empty_trash::{ EmptyTrash, EmptyTrashInput, EmptyTrashResult, EmptyTrashVariables, }; use warp_graphql::mutations::give_up_notebook_edit_access::{ GiveUpNotebookEditAccess, GiveUpNotebookEditAccessVariables, }; use warp_graphql::mutations::grab_notebook_edit_access::{ GrabNotebookEditAccess, GrabNotebookEditAccessVariables, }; use warp_graphql::mutations::leave_object::{ LeaveObject, LeaveObjectInput, LeaveObjectResult, LeaveObjectVariables, }; use warp_graphql::mutations::move_object::{ MoveObject, MoveObjectInput, MoveObjectResult, MoveObjectVariables, }; use warp_graphql::mutations::record_object_action::{ RecordObjectAction, RecordObjectActionInput, RecordObjectActionResult, RecordObjectActionVariables, }; use warp_graphql::mutations::remove_object_guest::{ RemoveObjectGuest, RemoveObjectGuestInput, RemoveObjectGuestResult, RemoveObjectGuestVariables, }; use warp_graphql::mutations::remove_object_link_permissions::{ RemoveObjectLinkPermissions, RemoveObjectLinkPermissionsInput, RemoveObjectLinkPermissionsResult, RemoveObjectLinkPermissionsVariables, }; use warp_graphql::mutations::set_object_link_permissions::{ SetObjectLinkPermissions, SetObjectLinkPermissionsInput, SetObjectLinkPermissionsResult, SetObjectLinkPermissionsVariables, }; use warp_graphql::mutations::transfer_generic_string_object_owner::{ TransferGenericStringObjectOwner, TransferGenericStringObjectOwnerInput, TransferGenericStringObjectOwnerResult, TransferGenericStringObjectOwnerVariables, }; use warp_graphql::mutations::transfer_notebook_owner::{ TransferNotebookOwner, TransferNotebookOwnerInput, TransferNotebookOwnerResult, TransferNotebookOwnerVariables, }; use warp_graphql::mutations::transfer_workflow_owner::{ TransferWorkflowOwner, TransferWorkflowOwnerInput, TransferWorkflowOwnerResult, TransferWorkflowOwnerVariables, }; use warp_graphql::mutations::trash_object::{ TrashObject, TrashObjectInput, TrashObjectResult, TrashObjectVariables, }; use warp_graphql::mutations::untrash_object::{ UntrashObject, UntrashObjectInput, UntrashObjectVariables, }; use warp_graphql::mutations::update_folder::{ UpdateFolder, UpdateFolderInput, UpdateFolderResult, UpdateFolderVariables, }; use warp_graphql::mutations::update_generic_string_object::{ UpdateGenericStringObject, UpdateGenericStringObjectInput, UpdateGenericStringObjectVariables, }; use warp_graphql::mutations::update_notebook::{ NotebookUpdate, UpdateNotebook, UpdateNotebookInput, UpdateNotebookResult, UpdateNotebookVariables, }; use warp_graphql::mutations::update_object_guests::{ UpdateObjectGuests, UpdateObjectGuestsInput, UpdateObjectGuestsResult, UpdateObjectGuestsVariables, }; use warp_graphql::mutations::update_workflow::{ UpdateWorkflow, UpdateWorkflowInput, UpdateWorkflowResult, UpdateWorkflowVariables, WorkflowUpdate, }; use warp_graphql::notebook::{UpdateNotebookEditAccessInput, UpdateNotebookEditAccessResult}; use warp_graphql::object::CloudObjectWithDescendants; use warp_graphql::object_permissions::AccessLevel; use warp_graphql::queries::get_cloud_environments::{ GetCloudEnvironmentsQuery, GetCloudEnvironmentsQueryVariables, GetCloudEnvironmentsResult, }; use warp_graphql::queries::get_cloud_object::{ CloudObjectInput, CloudObjectResult, GetCloudObject, GetCloudObjectVariables, }; use warp_graphql::queries::get_updated_cloud_objects::{ GetUpdatedCloudObjects, GetUpdatedCloudObjectsVariables, UpdatedCloudObjectsInput, UpdatedCloudObjectsResult, }; use warp_graphql::subscriptions::get_warp_drive_updates::GetWarpDriveUpdates; use warp_graphql::subscriptions::start_graphql_streaming_operation; use crate::ai::ambient_agents::scheduled::ScheduledAmbientAgent; use crate::ai::cloud_environments::AmbientAgentEnvironment; use crate::ai::document::ai_document_model::AIDocumentId; use crate::ai::execution_profiles::AIExecutionProfile; use crate::ai::facts::AIFact; use crate::ai::mcp::{MCPServer, TemplatableMCPServer}; use crate::channel::ChannelState; use crate::cloud_object::model::generic_string_model::{ GenericStringModel, GenericStringObjectId, Serializer, StringModel, }; use crate::cloud_object::{ BulkCreateCloudObjectResult, BulkCreateGenericStringObjectsRequest, CreateCloudObjectResult, CreateObjectRequest, CreatedCloudObject, GenericCloudObject, GenericServerObject, GenericStringObjectFormat, GenericStringObjectUniqueKey, JsonObjectType, ObjectIdType, ObjectType, ObjectsToUpdate, Owner, Revision, RevisionAndLastEditor, ServerCloudObject, ServerFolder, ServerMetadata, ServerNotebook, ServerObject, ServerPermissions, ServerWorkflow, TryFromGql as _, UpdateCloudObjectResult, }; use crate::drive::folders::FolderId; use crate::drive::sharing::SharingAccessLevel; use crate::env_vars::EnvVarCollection; use crate::notebooks::{NotebookId, SerializedNotebook}; use crate::server::graphql::schema::{ action_type_to_gql_action_type, object_action_history_from_gql, object_update_success_to_update_result, update_generic_string_object_result_to_update_result, }; use crate::server::graphql::{get_request_context, get_user_facing_error_message}; use crate::server::ids::{ClientId, HashableId, ServerId, ServerIdAndType, SyncId, ToServerId}; use crate::server::server_api::ServerApi; use crate::server::sync_queue::SerializedModel; use crate::settings::Preference; use crate::workflows::WorkflowId; use crate::workflows::workflow_enum::WorkflowEnum; use crate::workspaces::gql_convert::object_update_message_from_gql; use crate::workspaces::user_profiles::UserProfileWithUID; #[cfg_attr(not(target_family = "wasm"), async_trait)] #[cfg_attr(target_family = "wasm", async_trait(?Send))] impl ObjectClient for ServerApi { async fn create_workflow( &self, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let model = request .serialized_model .ok_or_else(|| anyhow!("missing model for creating workflow"))?; let variables = CreateWorkflowVariables { input: CreateWorkflowInput { data: model.take(), entrypoint: request.entrypoint.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), owner: request.owner.into(), }, request_context: get_request_context(), }; let operation = CreateWorkflow::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_workflow { CreateWorkflowResult::CreateWorkflowOutput(output) => { let metadata = output.workflow.metadata; let workflow_id: WorkflowId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { client_id: request.client_id, revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: workflow_id.to_server_id(), id_type: ObjectIdType::Workflow, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: output.workflow.permissions.try_into()?, }, }) } CreateWorkflowResult::UserFacingError(e) => Ok( CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), ), CreateWorkflowResult::Unknown => { Err(anyhow!("Failed to create workflow due to unknown variant")) } } } async fn update_workflow( &self, workflow_id: WorkflowId, data: SerializedModel, revision: Option<Revision>, ) -> Result<UpdateCloudObjectResult<ServerWorkflow>> { let variables = UpdateWorkflowVariables { input: UpdateWorkflowInput { data: data.model_as_str().to_owned(), uid: cynic::Id::new(workflow_id), revision_ts: revision.map(|r| r.into()), }, request_context: get_request_context(), }; let operation = UpdateWorkflow::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.update_workflow { UpdateWorkflowResult::UpdateWorkflowOutput(output) => match output.update { WorkflowUpdate::ObjectUpdateSuccess(success) => { Ok(UpdateCloudObjectResult::Success { revision_and_editor: RevisionAndLastEditor { revision: success.revision_ts.into(), last_editor_uid: Some(success.last_editor_uid.into_inner()), }, }) } WorkflowUpdate::WorkflowUpdateRejected(rejected) => { Ok(UpdateCloudObjectResult::Rejected { object: ServerWorkflow::try_from_gql(rejected.conflicting_workflow)?, }) } WorkflowUpdate::Unknown => Err(anyhow!("WorkflowUpdate has unknown variant")), }, UpdateWorkflowResult::UserFacingError(e) => { Err(anyhow!(get_user_facing_error_message(e))) } UpdateWorkflowResult::Unknown => { Err(anyhow!("Failed to update workflow due to unknown variant")) } } } async fn bulk_create_generic_string_objects( &self, owner: Owner, objects: &[BulkCreateGenericStringObjectsRequest], ) -> Result<BulkCreateCloudObjectResult> { let variables = BulkCreateObjectsVariables { input: BulkCreateObjectsInput { generic_string_objects: Some(BulkCreateGenericStringObjectsInput { owner: owner.into(), objects: objects .iter() .map(|object| GenericStringObjectInput { client_id: cynic::Id::new(object.id.to_string()), serialized_model: object.serialized_model.model_as_str().to_owned(), format: object.format.into(), uniqueness_key: object .uniqueness_key .clone() .map(GenericStringObjectUniqueKey::into), initial_folder_id: object.initial_folder_id.map(FolderId::into), entrypoint: object.entrypoint.into(), }) .collect(), }), }, request_context: get_request_context(), }; let operation = BulkCreateObjects::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.bulk_create_objects { BulkCreateObjectsResult::BulkCreateObjectsOutput(output) => { if let Some(gso_result) = output.generic_string_objects { let mut created_cloud_objects = Vec::new(); for gso in gso_result.objects { let metadata = gso.generic_string_object.metadata; let uid = metadata.uid.into_inner(); let object_id: GenericStringObjectId = uid.into(); created_cloud_objects.push(CreatedCloudObject { client_id: ClientId::from_hash(&gso.client_id.into_inner()) .ok_or_else(|| anyhow!("invalid client id"))?, revision_and_editor: RevisionAndLastEditor { revision: metadata.revision_ts.into(), last_editor_uid: metadata .last_editor_uid .map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: object_id.to_server_id(), id_type: ObjectIdType::GenericStringObject, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: gso.generic_string_object.permissions.try_into()?, }); } Ok(BulkCreateCloudObjectResult::Success { created_cloud_objects, }) } else { Err(anyhow!( "No generic string objects found in BulkCreateGenericStringObjectsOutput" )) } } BulkCreateObjectsResult::UserFacingError(e) => match e.error { UserFacingErrorInterface::GenericStringObjectUniqueKeyConflict(_) => { Ok(BulkCreateCloudObjectResult::GenericStringObjectUniqueKeyConflict) } _ => Err(anyhow!(get_user_facing_error_message(e))), }, BulkCreateObjectsResult::Unknown => Err(anyhow!( "Failed to bulk create objects due to unknown variant" )), } } async fn create_generic_string_object( &self, format: GenericStringObjectFormat, uniqueness_key: Option<GenericStringObjectUniqueKey>, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let model = request .serialized_model .ok_or_else(|| anyhow!("missing model for creating generic string model"))?; let variables = CreateGenericStringObjectVariables { input: CreateGenericStringObjectInput { generic_string_object: GenericStringObjectInput { client_id: cynic::Id::new(request.client_id.to_hash()), entrypoint: request.entrypoint.into(), format: format.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), serialized_model: model.take(), uniqueness_key: uniqueness_key.map(|key| key.into()), }, owner: request.owner.into(), }, request_context: get_request_context(), }; let operation = CreateGenericStringObject::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_generic_string_object { CreateGenericStringObjectResult::CreateGenericStringObjectOutput(output) => { let metadata = output.generic_string_object.metadata; let gso_id: GenericStringObjectId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: gso_id.to_server_id(), id_type: ObjectIdType::GenericStringObject, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), client_id: request.client_id, permissions: output.generic_string_object.permissions.try_into()?, }, }) } CreateGenericStringObjectResult::UserFacingError(e) => Ok(match e.error { UserFacingErrorInterface::GenericStringObjectUniqueKeyConflict(_) => { CreateCloudObjectResult::GenericStringObjectUniqueKeyConflict } _ => CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), }), CreateGenericStringObjectResult::Unknown => Err(anyhow!( "Failed to create generic string object due to unknown variant" )), } } async fn create_notebook( &self, request: CreateObjectRequest, ) -> Result<CreateCloudObjectResult> { let serialized = request .serialized_model .as_ref() .ok_or_else(|| anyhow!("Missing serialized model for notebook"))?; let notebook: SerializedNotebook = serde_json::from_str(serialized.model_as_str()) .context("Failed to deserialize notebook model")?; let ai_document_id = notebook .ai_document_id .and_then(|id| AIDocumentId::try_from(id).ok()); let variables = CreateNotebookVariables { input: CreateNotebookInput { data: Some(notebook.data), entrypoint: request.entrypoint.into(), initial_folder_id: request.initial_folder_id.map(|folder_id| folder_id.into()), owner: request.owner.into(), title: request.title, ai_document_id: ai_document_id.map(|id| id.to_string()), conversation_id: notebook.conversation_id, }, request_context: get_request_context(), }; let operation = CreateNotebook::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.create_notebook { CreateNotebookResult::CreateNotebookOutput(output) => { let metadata = output.notebook.metadata; let notebook_id: NotebookId = metadata.uid.into_inner().into(); Ok(CreateCloudObjectResult::Success { created_cloud_object: CreatedCloudObject { client_id: request.client_id, revision_and_editor: RevisionAndLastEditor { revision: output.revision_ts.into(), last_editor_uid: metadata.last_editor_uid.map(|uid| uid.into_inner()), }, metadata_ts: metadata.metadata_last_updated_ts, server_id_and_type: ServerIdAndType { id: notebook_id.to_server_id(), id_type: ObjectIdType::Notebook, }, creator_uid: metadata.creator_uid.map(|uid| uid.into_inner()), permissions: output.notebook.permissions.try_into()?, }, }) } CreateNotebookResult::UserFacingError(e) => Ok( CreateCloudObjectResult::UserFacingError(get_user_facing_error_message(e)), ), CreateNotebookResult::Unknown => { Err(anyhow!("Failed to create notebook due to unknown variant")) } } } async fn update_notebook( &self, notebook_id: NotebookId, title: Option<String>, data: Option<SerializedModel>, revision: Option<Revision>, ) -> Result<UpdateCloudObjectResult<ServerNotebook>> { let variables = UpdateNotebookVariables { input: UpdateNotebookInput { data: data.map(|data| data.model_as_str().to_owned()), title, uid: cynic::Id::new(notebook_id), revision_ts: revision.map(|r| r.into()), }, request_context: get_request_context(), }; let operation = UpdateNotebook::build(variables); let response = self.send_graphql_request(operation, None).await?; match response.update_notebook { UpdateNotebookResult::UpdateNotebookOutput(output) => match output.update { NotebookUpdate::ObjectUpdateSuccess(success) => { Ok(UpdateCloudObjectResult::Success { revision_and_editor: RevisionAndLastEditor { revision: success.revision_ts.into(), last_editor_uid: Some(success.last_editor_uid.into_inner()), }, }) } NotebookUpdate::NotebookUpdateRejected(rejected) => { Ok(UpdateCloudObjectResult::Rejected { object: ServerNotebook::try_from_gql(rejected.conflicting_notebook)?, }) } NotebookUpdate::Unknown => Err(anyhow!("NotebookUpdate has unknown variant")), }, UpdateNotebookResult::UserFacingError(e) => { Err(anyhow!(get_user_facing_error_message(e))) } UpdateNotebookResult::Unknown => {