1419 lines · 60.5 KB · Rust
RawDownload
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 1419.