From 83463051782b9657b971ae065bba5fe3f7eb0981 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Thu, 28 Sep 2023 21:07:23 +0200 Subject: [PATCH 01/22] fix: typo (#1869) --- front/pages/w/[wId]/assistant/new.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/pages/w/[wId]/assistant/new.tsx b/front/pages/w/[wId]/assistant/new.tsx index ef00f51fbebd..7eb3df6e027c 100644 --- a/front/pages/w/[wId]/assistant/new.tsx +++ b/front/pages/w/[wId]/assistant/new.tsx @@ -216,7 +216,7 @@ export default function AssistantNew({ className="cursor-pointer" onClick={() => { void handleSubmit( - `Hi :mention[${agent.name}]{sId=${agent.sId}}, how can you help me with?`, + `Hi :mention[${agent.name}]{sId=${agent.sId}}, what can you help me with?`, [ { configurationId: agent.sId, From 7b88bcd5ccf24397e9212e1774d6ef583e874858 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Thu, 28 Sep 2023 21:22:08 +0200 Subject: [PATCH 02/22] Fix routers and mutation (#1868) * mutate on assistant delete * clean-up --- front/components/ConnectorPermissionsModal.tsx | 4 +++- .../components/assistant_builder/AssistantBuilder.tsx | 11 ++++------- front/lib/user.ts | 4 +++- front/pages/w/[wId]/a/[aId]/datasets/[name]/index.tsx | 8 ++++---- front/pages/w/[wId]/a/[aId]/datasets/index.tsx | 8 ++++---- front/pages/w/[wId]/a/[aId]/datasets/new.tsx | 8 ++++---- front/pages/w/[wId]/a/[aId]/index.tsx | 4 +++- front/pages/w/[wId]/a/index.tsx | 4 +++- .../w/[wId]/builder/data-sources/[name]/settings.tsx | 4 +++- .../pages/w/[wId]/u/extract/templates/[sId]/index.tsx | 4 +++- front/pages/w/[wId]/workspace/index.tsx | 4 +++- 11 files changed, 37 insertions(+), 26 deletions(-) diff --git a/front/components/ConnectorPermissionsModal.tsx b/front/components/ConnectorPermissionsModal.tsx index e37d86aba07a..55ea7ff65538 100644 --- a/front/components/ConnectorPermissionsModal.tsx +++ b/front/components/ConnectorPermissionsModal.tsx @@ -1,7 +1,7 @@ import { Checkbox, Modal } from "@dust-tt/sparkle"; import { Cog6ToothIcon } from "@heroicons/react/20/solid"; import { useState } from "react"; -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import { CONNECTOR_CONFIGURATIONS } from "@app/lib/connector_providers"; import { @@ -63,6 +63,8 @@ export default function ConnectorPermissionsModal({ setOpen: (open: boolean) => void; onEditPermission: () => void; }) { + const { mutate } = useSWRConfig(); + const [updatedPermissionByInternalId, setUpdatedPermissionByInternalId] = useState>({}); diff --git a/front/components/assistant_builder/AssistantBuilder.tsx b/front/components/assistant_builder/AssistantBuilder.tsx index c7bea7affc7e..c491bc4bd6a7 100644 --- a/front/components/assistant_builder/AssistantBuilder.tsx +++ b/front/components/assistant_builder/AssistantBuilder.tsx @@ -10,11 +10,10 @@ import { TrashIcon, } from "@dust-tt/sparkle"; import * as t from "io-ts"; -import router from "next/router"; +import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; import React from "react"; import ReactTextareaAutosize from "react-textarea-autosize"; -import { mutate } from "swr"; import { AvatarPicker } from "@app/components/assistant_builder/AssistantBuilderAvatarPicker"; import AssistantBuilderDataSourceModal from "@app/components/assistant_builder/AssistantBuilderDataSourceModal"; @@ -172,6 +171,8 @@ export default function AssistantBuilder({ initialBuilderState, agentConfigurationId, }: AssistantBuilderProps) { + const router = useRouter(); + const [builderState, setBuilderState] = useState({ ...DEFAULT_ASSISTANT_STATE, generationSettings: { @@ -476,7 +477,6 @@ export default function AssistantBuilder({ setIsSavingOrDeleting(false); return; } - await router.push(`/w/${owner.sId}/builder/assistants`); setIsSavingOrDeleting(false); }; @@ -552,10 +552,7 @@ export default function AssistantBuilder({ setIsSavingOrDeleting(true); submitForm() .then(async () => { - await mutate( - `/api/w/${owner.sId}/assistant/agent_configurations` - ); - void router.push( + await router.push( `/w/${owner.sId}/builder/assistants` ); setIsSavingOrDeleting(false); diff --git a/front/lib/user.ts b/front/lib/user.ts index fd666798efe8..024b1e639a38 100644 --- a/front/lib/user.ts +++ b/front/lib/user.ts @@ -1,4 +1,4 @@ -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import { GetUserMetadataResponseBody } from "@app/pages/api/user/metadata/[key]"; import { UserMetadataType } from "@app/types/user"; @@ -31,6 +31,8 @@ export async function getUserMetadataFromClient(key: string) { * @param metadata MetadataType the metadata to set for the current user. */ export function setUserMetadataFromClient(metadata: UserMetadataType) { + const { mutate } = useSWRConfig(); + void (async () => { try { const res = await fetch( diff --git a/front/pages/w/[wId]/a/[aId]/datasets/[name]/index.tsx b/front/pages/w/[wId]/a/[aId]/datasets/[name]/index.tsx index 96a8489b7529..56422d613aee 100644 --- a/front/pages/w/[wId]/a/[aId]/datasets/[name]/index.tsx +++ b/front/pages/w/[wId]/a/[aId]/datasets/[name]/index.tsx @@ -2,7 +2,7 @@ import "@uiw/react-textarea-code-editor/dist.css"; import { Button, Tab } from "@dust-tt/sparkle"; import { GetServerSideProps, InferGetServerSidePropsType } from "next"; -import Router, { useRouter } from "next/router"; +import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import DatasetView from "@app/components/app/DatasetView"; @@ -87,6 +87,8 @@ export default function ViewDatasetView({ dataset, gaTrackingId, }: InferGetServerSidePropsType) { + const router = useRouter(); + const [disable, setDisabled] = useState(true); const [loading, setLoading] = useState(false); @@ -102,7 +104,7 @@ export default function ViewDatasetView({ // this should happen. useEffect(() => { if (isFinishedEditing) { - void Router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); + void router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isFinishedEditing]); @@ -146,8 +148,6 @@ export default function ViewDatasetView({ setIsFinishedEditing(true); }; - const router = useRouter(); - return ( ) { + const router = useRouter(); + const handleDelete = async (datasetName: string) => { if (confirm("Are you sure you want to delete this dataset entirely?")) { await fetch( @@ -84,12 +86,10 @@ export default function DatasetsView({ }, } ); - await Router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); + await router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); } }; - const router = useRouter(); - return ( ) { + const router = useRouter(); + const [disable, setDisabled] = useState(true); const [loading, setLoading] = useState(false); const [dataset, setDataset] = useState(null as DatasetType | null); @@ -86,7 +88,7 @@ export default function NewDatasetView({ // this should happen. useEffect(() => { if (isFinishedEditing) { - void Router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); + void router.push(`/w/${owner.sId}/a/${app.sId}/datasets`); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isFinishedEditing]); @@ -119,8 +121,6 @@ export default function NewDatasetView({ setIsFinishedEditing(true); }; - const router = useRouter(); - return ( ) { + const { mutate } = useSWRConfig(); + const [spec, setSpec] = useState( JSON.parse(app.savedSpecification || `[]`) as SpecificationType ); diff --git a/front/pages/w/[wId]/a/index.tsx b/front/pages/w/[wId]/a/index.tsx index f5f736cbccff..202ab3dc18b6 100644 --- a/front/pages/w/[wId]/a/index.tsx +++ b/front/pages/w/[wId]/a/index.tsx @@ -10,7 +10,7 @@ import { GetServerSideProps, InferGetServerSidePropsType } from "next"; import Link from "next/link"; import { useRouter } from "next/router"; import { useState } from "react"; -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import AI21Setup from "@app/components/providers/AI21Setup"; import AnthropicSetup from "@app/components/providers/AnthropicSetup"; @@ -77,6 +77,8 @@ export const getServerSideProps: GetServerSideProps<{ }; export function APIKeys({ owner }: { owner: WorkspaceType }) { + const { mutate } = useSWRConfig(); + const { keys } = useKeys(owner); const [isRevealed, setIsRevealed] = useState( {} as { [key: string]: boolean } diff --git a/front/pages/w/[wId]/builder/data-sources/[name]/settings.tsx b/front/pages/w/[wId]/builder/data-sources/[name]/settings.tsx index f03ed392e922..87873b1fc1f7 100644 --- a/front/pages/w/[wId]/builder/data-sources/[name]/settings.tsx +++ b/front/pages/w/[wId]/builder/data-sources/[name]/settings.tsx @@ -3,7 +3,7 @@ import { ChevronRightIcon } from "@heroicons/react/20/solid"; import { GetServerSideProps, InferGetServerSidePropsType } from "next"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import ModelPicker from "@app/components/app/ModelPicker"; import AppLayout from "@app/components/sparkle/AppLayout"; @@ -159,6 +159,8 @@ function StandardDataSourceSettings({ }) => Promise; gaTrackingId: string; }) { + const { mutate } = useSWRConfig(); + const dataSourceConfig = JSON.parse(dataSource.config || "{}"); const [dataSourceDescription, setDataSourceDescription] = useState( diff --git a/front/pages/w/[wId]/u/extract/templates/[sId]/index.tsx b/front/pages/w/[wId]/u/extract/templates/[sId]/index.tsx index 91ab97b5c762..59e139e55491 100644 --- a/front/pages/w/[wId]/u/extract/templates/[sId]/index.tsx +++ b/front/pages/w/[wId]/u/extract/templates/[sId]/index.tsx @@ -16,7 +16,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; import React, { Fragment } from "react"; import { useState } from "react"; -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import AppLayout from "@app/components/sparkle/AppLayout"; import { subNavigationAdmin } from "@app/components/sparkle/navigation"; @@ -78,6 +78,8 @@ export default function AppExtractEventsReadData({ gaTrackingId, }: InferGetServerSidePropsType) { const router = useRouter(); + const { mutate } = useSWRConfig(); + const [isProcessing, setIsProcessing] = useState(false); const { events, isEventsLoading } = useExtractedEvents({ owner, diff --git a/front/pages/w/[wId]/workspace/index.tsx b/front/pages/w/[wId]/workspace/index.tsx index 3f929bb95538..cb754ec49fd8 100644 --- a/front/pages/w/[wId]/workspace/index.tsx +++ b/front/pages/w/[wId]/workspace/index.tsx @@ -9,7 +9,7 @@ import { Listbox } from "@headlessui/react"; import { CheckIcon } from "@heroicons/react/20/solid"; import { GetServerSideProps, InferGetServerSidePropsType } from "next"; import React, { useCallback, useEffect, useState } from "react"; -import { mutate } from "swr"; +import { useSWRConfig } from "swr"; import AppLayout from "@app/components/sparkle/AppLayout"; import { subNavigationAdmin } from "@app/components/sparkle/navigation"; @@ -56,6 +56,8 @@ export default function WorkspaceAdmin({ gaTrackingId, url, }: InferGetServerSidePropsType) { + const { mutate } = useSWRConfig(); + const [disable, setDisabled] = useState(true); const [updating, setUpdating] = useState(false); From 6a7d60cc8b51200b8405b807c8db00a7128a5771 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Thu, 28 Sep 2023 21:23:25 +0200 Subject: [PATCH 03/22] Revert "Debug plan check on document upsert (#1851)" (#1870) This reverts commit 288d2a397d64da87f1ec08877895310edde46d2f. --- .../[name]/documents/[documentId]/index.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/front/pages/api/v1/w/[wId]/data_sources/[name]/documents/[documentId]/index.ts b/front/pages/api/v1/w/[wId]/data_sources/[name]/documents/[documentId]/index.ts index 32d125eb2cb7..401134481243 100644 --- a/front/pages/api/v1/w/[wId]/data_sources/[name]/documents/[documentId]/index.ts +++ b/front/pages/api/v1/w/[wId]/data_sources/[name]/documents/[documentId]/index.ts @@ -16,7 +16,6 @@ import { Authenticator, getAPIKey } from "@app/lib/auth"; import { CoreAPI, CoreAPILightDocument } from "@app/lib/core_api"; import { ReturnedAPIErrorType } from "@app/lib/error"; import { validateUrl } from "@app/lib/utils"; -import logger from "@app/logger/logger"; import { apiError, withLogging } from "@app/logger/withlogging"; import { DataSourceType } from "@app/types/data_source"; import { DocumentType } from "@app/types/document"; @@ -227,19 +226,6 @@ async function handler( // the `getDataSourceDocuments` query involves a SELECT COUNT(*) in the DB that is not // optimized, so we avoid it for large workspaces if we know we're unlimited anyway if (owner.plan.limits.dataSources.documents.count != -1) { - logger.info( - { - requestWid: req.query.wId as string, - requestDataSourceName: req.query.name as string, - requestDocumentId: req.query.documentId as string, - planDocumentCount: owner.plan.limits.dataSources.documents.count, - planDocumentCountTypeOf: - typeof owner.plan.limits.dataSources.documents.count, - ownerPlan: JSON.stringify(owner.plan), - owner: owner.sId, - }, - "Checking documents count limit" - ); const documents = await CoreAPI.getDataSourceDocuments({ projectId: dataSource.dustAPIProjectId, dataSourceName: dataSource.name, From 6b2bc09084694ca3bc372509b3c91ba0b3c336bd Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 09:13:16 +0200 Subject: [PATCH 04/22] Tweak app and landing head to add touch icons (#1872) * Tweak app and landing head to add touch icons * fix paths --- front/components/sparkle/AppLayout.tsx | 44 ++++++++++++++++++++++++++ front/pages/index.tsx | 20 ++++++------ front/public/static/manifest.json | 0 3 files changed, 53 insertions(+), 11 deletions(-) delete mode 100644 front/public/static/manifest.json diff --git a/front/components/sparkle/AppLayout.tsx b/front/components/sparkle/AppLayout.tsx index 6022b9551a00..d7af8241853d 100644 --- a/front/components/sparkle/AppLayout.tsx +++ b/front/components/sparkle/AppLayout.tsx @@ -180,6 +180,50 @@ export default function AppLayout({ {`Dust - ${owner.name}`} + + + + + + + + + + + + Dust - Secure AI assistant with your company's knowledge - - - + Date: Fri, 29 Sep 2023 09:45:45 +0200 Subject: [PATCH 05/22] Add standardView query parameter to view managed data source as standard ones (#1873) --- front/pages/w/[wId]/a/[aId]/runs/index.tsx | 1 - .../w/[wId]/builder/data-sources/[name]/index.tsx | 13 +++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/front/pages/w/[wId]/a/[aId]/runs/index.tsx b/front/pages/w/[wId]/a/[aId]/runs/index.tsx index c33573ad2992..dce1443c8d18 100644 --- a/front/pages/w/[wId]/a/[aId]/runs/index.tsx +++ b/front/pages/w/[wId]/a/[aId]/runs/index.tsx @@ -55,7 +55,6 @@ export const getServerSideProps: GetServerSideProps<{ // `wIdTarget` is used to change the workspace owning the runs of the apps we're looking at. // Mostly useful for debugging as an example our use of `dust-apps` as `dust`. const wIdTarget = (context.query?.wIdTarget as string) || null; - console.log("WIDTARGET", wIdTarget); return { props: { diff --git a/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx b/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx index 4aaae71cce77..22d12d4b4abd 100644 --- a/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx +++ b/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx @@ -51,6 +51,7 @@ export const getServerSideProps: GetServerSideProps<{ isAdmin: boolean; dataSource: DataSourceType; connector: ConnectorType | null; + standardView: boolean; nangoConfig: { publicKey: string; slackConnectorId: string; @@ -94,6 +95,10 @@ export const getServerSideProps: GetServerSideProps<{ const readOnly = !auth.isBuilder(); const isAdmin = auth.isAdmin(); + // `standardView` is used to force the presentation of a managed data source as a standard one so + // that it can be explored. + const standardView = !!context.query?.standardView; + return { props: { user, @@ -102,6 +107,7 @@ export const getServerSideProps: GetServerSideProps<{ isAdmin, dataSource, connector, + standardView, nangoConfig: { publicKey: NANGO_PUBLIC_KEY, slackConnectorId: NANGO_SLACK_CONNECTOR_ID, @@ -557,6 +563,7 @@ export default function DataSourceView({ isAdmin, dataSource, connector, + standardView, nangoConfig, githubAppUrl, gaTrackingId, @@ -583,7 +590,7 @@ export default function DataSourceView({ } hideSidebar={true} > - {dataSource.connectorId && connector ? ( + {!standardView && dataSource.connectorId && connector ? ( ) : ( - + )} ); From 82464ac01e8e07659d94e6d8346dc7c5159cf6ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daphn=C3=A9=20Popin?= Date: Fri, 29 Sep 2023 10:16:39 +0200 Subject: [PATCH 06/22] Remove logic isOnV2 (#1875) * Remove logic isOnV2 * remove unused import --- front/components/sparkle/AppLayout.tsx | 5 +-- front/components/sparkle/navigation.tsx | 58 ++++++++----------------- front/lib/assistant.ts | 14 ------ front/lib/error.ts | 2 - front/pages/w/[wId]/index.tsx | 8 +--- 5 files changed, 21 insertions(+), 66 deletions(-) diff --git a/front/components/sparkle/AppLayout.tsx b/front/components/sparkle/AppLayout.tsx index d7af8241853d..5f8fe01026c5 100644 --- a/front/components/sparkle/AppLayout.tsx +++ b/front/components/sparkle/AppLayout.tsx @@ -15,7 +15,6 @@ import { signOut } from "next-auth/react"; import { Fragment, useState } from "react"; import WorkspacePicker from "@app/components/WorkspacePicker"; -import { isOnAssistantV2 } from "@app/lib/assistant"; import { classNames } from "@app/lib/utils"; import { UserType, WorkspaceType } from "@app/types/user"; @@ -56,9 +55,7 @@ function NavigationBar({ workspace={owner} readOnly={false} onWorkspaceUpdate={(workspace) => { - const assistantRoute = isOnAssistantV2(owner) - ? `/w/${workspace.sId}/assistant/new` - : `/w/${workspace.sId}/u/chat`; + const assistantRoute = `/w/${workspace.sId}/assistant/new`; if (workspace.id !== owner.id) { void router .push(assistantRoute) diff --git a/front/components/sparkle/navigation.tsx b/front/components/sparkle/navigation.tsx index cd6f6d2f4322..11d16f14fe6c 100644 --- a/front/components/sparkle/navigation.tsx +++ b/front/components/sparkle/navigation.tsx @@ -1,6 +1,5 @@ import { ArrowUpOnSquareIcon, - ChatBubbleBottomCenterTextIcon, ChatBubbleLeftRightIcon, CloudArrowDownIcon, Cog6ToothIcon, @@ -12,7 +11,6 @@ import { RobotIcon, } from "@dust-tt/sparkle"; -import { isOnAssistantV2 } from "@app/lib/assistant"; import { isDevelopmentOrDustWorkspace } from "@app/lib/development"; import { AppType } from "@app/types/app"; import { WorkspaceType } from "@app/types/user"; @@ -62,41 +60,25 @@ export const topNavigation = ({ owner: WorkspaceType; current: TopNavigationId; }) => { - const isOnV2 = isOnAssistantV2(owner); const nav: SparkleAppLayoutNavigation[] = []; - if (isOnV2) { - nav.push({ - id: "assistant", - label: "Conversations", - href: `/w/${owner.sId}/assistant/new`, - icon: ChatBubbleLeftRightIcon, - sizing: "hug", - current: current === "assistant", - hasSeparator: true, - }); - } else { - nav.push({ - id: "assistant", - label: "Assistant", - href: `/w/${owner.sId}/u/chat`, - icon: ChatBubbleBottomCenterTextIcon, - sizing: "hug", - current: current === "assistant", - hasSeparator: true, - }); - } + nav.push({ + id: "assistant", + label: "Conversations", + href: `/w/${owner.sId}/assistant/new`, + icon: ChatBubbleLeftRightIcon, + sizing: "hug", + current: current === "assistant", + hasSeparator: true, + }); if (owner.role === "admin" || owner.role === "builder") { - const defaultSettingsRoute = isOnV2 - ? `/w/${owner.sId}/builder/assistants` - : `/w/${owner.sId}/builder/data-sources`; nav.push({ id: "settings", label: "Settings", hideLabel: true, icon: Cog6ToothIcon, - href: defaultSettingsRoute, + href: `/w/${owner.sId}/builder/assistants`, current: current === "settings", }); } @@ -118,17 +100,15 @@ export const subNavigationAdmin = ({ const nav: SparkleAppLayoutNavigation[] = []; if (owner.role === "admin" || owner.role === "builder") { - if (isOnAssistantV2(owner)) { - nav.push({ - id: "assistants", - label: "Assistants Manager", - icon: RobotIcon, - href: `/w/${owner.sId}/builder/assistants`, - current: current === "assistants", - subMenuLabel: current === "assistants" ? subMenuLabel : undefined, - subMenu: current === "assistants" ? subMenu : undefined, - }); - } + nav.push({ + id: "assistants", + label: "Assistants Manager", + icon: RobotIcon, + href: `/w/${owner.sId}/builder/assistants`, + current: current === "assistants", + subMenuLabel: current === "assistants" ? subMenuLabel : undefined, + subMenu: current === "assistants" ? subMenu : undefined, + }); } nav.push({ diff --git a/front/lib/assistant.ts b/front/lib/assistant.ts index 73060dc86c4c..5f8705d20290 100644 --- a/front/lib/assistant.ts +++ b/front/lib/assistant.ts @@ -1,6 +1,5 @@ import { ExtractSpecificKeys } from "@app/lib/api/typescipt_utils"; import { AgentConfigurationType } from "@app/types/assistant/agent"; -import { WorkspaceType } from "@app/types/user"; /** * Supported models @@ -153,16 +152,3 @@ export function compareAgentsForSort( return 0; // Default: keep the original order } - -export function isOnAssistantV2(owner?: WorkspaceType): boolean { - // UNCOMMENT THIS TO ROLLBACK TO V1 - // const V2_ROLLED_OUT_WORKSPACES = [ - // "0ec9852c2f", // Dust - // "76e5b694df", // dust-test - // ]; - // return ( - // isDevelopmentOrDustWorkspace(owner) || - // V2_ROLLED_OUT_WORKSPACES.includes(owner.sId) - // ); - return owner !== null; -} diff --git a/front/lib/error.ts b/front/lib/error.ts index b876f37ca30f..5d501452edc1 100644 --- a/front/lib/error.ts +++ b/front/lib/error.ts @@ -32,8 +32,6 @@ export type APIErrorType = | "action_api_error" | "invitation_not_found" | "plan_limit_error" - | "chat_session_not_found" - | "chat_session_auth_error" | "template_not_found" | "chat_message_not_found" | "event_schema_not_found" diff --git a/front/pages/w/[wId]/index.tsx b/front/pages/w/[wId]/index.tsx index 0bb6f47b591f..1f285d43b220 100644 --- a/front/pages/w/[wId]/index.tsx +++ b/front/pages/w/[wId]/index.tsx @@ -1,6 +1,5 @@ import { GetServerSideProps } from "next"; -import { isOnAssistantV2 } from "@app/lib/assistant"; import { Authenticator, getSession, getUserFromSession } from "@app/lib/auth"; export const getServerSideProps: GetServerSideProps = async (context) => { @@ -18,14 +17,9 @@ export const getServerSideProps: GetServerSideProps = async (context) => { }; } - const isOnV2 = isOnAssistantV2(owner); - const redirectRoute = isOnV2 - ? `/w/${context.query.wId}/assistant/new` - : `/w/${context.query.wId}/u/chat`; - return { redirect: { - destination: redirectRoute, + destination: `/w/${context.query.wId}/assistant/new`, permanent: false, }, }; From 2c1442d8789cf296299e1ada8c2b37a7c5d969c2 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Fri, 29 Sep 2023 10:52:42 +0200 Subject: [PATCH 07/22] feat(conversations): assistant mentions are sticky (#1862) * feat(conversations): assistant mentions are sticky * fix + no cross user * use a ref instead of a regex * dry out mention node --- .../assistant/conversation/Conversation.tsx | 44 +++++++- .../assistant/conversation/InputBar.tsx | 100 +++++++++++++++--- front/pages/w/[wId]/assistant/[cId]/index.tsx | 17 ++- front/pages/w/[wId]/assistant/new.tsx | 6 +- 4 files changed, 148 insertions(+), 19 deletions(-) diff --git a/front/components/assistant/conversation/Conversation.tsx b/front/components/assistant/conversation/Conversation.tsx index 8dc262181510..0ea13413ebee 100644 --- a/front/components/assistant/conversation/Conversation.tsx +++ b/front/components/assistant/conversation/Conversation.tsx @@ -10,17 +10,24 @@ import { } from "@app/lib/api/assistant/conversation"; import { useConversation, useConversations } from "@app/lib/swr"; import { + AgentMention, AgentMessageType, + isAgentMention, + isUserMessageType, UserMessageType, } from "@app/types/assistant/conversation"; -import { WorkspaceType } from "@app/types/user"; +import { UserType, WorkspaceType } from "@app/types/user"; export default function Conversation({ owner, + user, conversationId, + onStickyMentionsChange, }: { owner: WorkspaceType; + user: UserType; conversationId: string; + onStickyMentionsChange?: (mentions: AgentMention[]) => void; }) { const { conversation, @@ -42,6 +49,41 @@ export default function Conversation({ } }, [conversation?.content.length]); + useEffect(() => { + if (!onStickyMentionsChange) { + return; + } + const lastUserMessageContent = conversation?.content.findLast( + (versionedMessages) => + versionedMessages.some( + (message) => + isUserMessageType(message) && + message.visibility !== "deleted" && + message.user?.id === user.id + ) + ); + + if (!lastUserMessageContent) { + return; + } + + const lastUserMessage = + lastUserMessageContent[lastUserMessageContent.length - 1]; + + if (!lastUserMessage || !isUserMessageType(lastUserMessage)) { + return; + } + + const mentions = lastUserMessage.mentions; + const agentMentions = mentions.filter(isAgentMention); + onStickyMentionsChange(agentMentions); + }, [ + conversation?.content, + conversation?.content.length, + onStickyMentionsChange, + user.id, + ]); + const buildEventSourceURL = useCallback( (lastEvent: string | null) => { const esURL = `/api/w/${owner.sId}/assistant/conversations/${conversationId}/events`; diff --git a/front/components/assistant/conversation/InputBar.tsx b/front/components/assistant/conversation/InputBar.tsx index cc81dd607d1a..305db1c76699 100644 --- a/front/components/assistant/conversation/InputBar.tsx +++ b/front/components/assistant/conversation/InputBar.tsx @@ -18,7 +18,7 @@ import { compareAgentsForSort } from "@app/lib/assistant"; import { useAgentConfigurations } from "@app/lib/swr"; import { classNames } from "@app/lib/utils"; import { AgentConfigurationType } from "@app/types/assistant/agent"; -import { MentionType } from "@app/types/assistant/conversation"; +import { AgentMention, MentionType } from "@app/types/assistant/conversation"; import { WorkspaceType } from "@app/types/user"; // AGENT MENTION @@ -183,9 +183,11 @@ const AgentList = forwardRef(AgentListImpl); export function AssistantInputBar({ owner, onSubmit, + stickyMentions, }: { owner: WorkspaceType; onSubmit: (input: string, mentions: MentionType[]) => void; + stickyMentions?: AgentMention[]; }) { const [agentListVisible, setAgentListVisible] = useState(false); const [agentListFilter, setAgentListFilter] = useState(""); @@ -262,6 +264,69 @@ export function AssistantInputBar({ } }, [animate, isAnimating]); + const stickyMentionsTextContent = useRef(null); + + useEffect(() => { + if (!stickyMentions) { + return; + } + + const mentionedAgentConfigurationIds = new Set( + stickyMentions?.map((m) => m.configurationId) + ); + + const contentEditable = document.getElementById("dust-input-bar"); + if (contentEditable) { + const textContent = contentEditable.textContent?.trim(); + + if (textContent?.length && !stickyMentionsTextContent.current) { + return; + } + + if ( + textContent?.length && + textContent !== stickyMentionsTextContent.current + ) { + // content has changed, we don't clear it (we preserve whatever the user typed) + return; + } + + // we clear the content of the input bar -- at this point, it's either already empty, + // or contains only the sticky mentions added by this hook + contentEditable.innerHTML = ""; + let lastTextNode = null; + for (const configurationId of mentionedAgentConfigurationIds) { + const agentConfiguration = agentConfigurations.find( + (agent) => agent.sId === configurationId + ); + if (!agentConfiguration) { + continue; + } + const mentionNode = getAgentMentionNode(agentConfiguration); + if (!mentionNode) { + continue; + } + contentEditable.appendChild(mentionNode); + lastTextNode = document.createTextNode(" "); + contentEditable.appendChild(lastTextNode); + + stickyMentionsTextContent.current = + contentEditable.textContent?.trim() || null; + } + // move the cursor to the end of the input bar + if (lastTextNode) { + const selection = window.getSelection(); + if (selection) { + const range = document.createRange(); + range.setStart(lastTextNode, lastTextNode.length); + range.setEnd(lastTextNode, lastTextNode.length); + selection.removeAllRanges(); + selection.addRange(range); + } + } + } + }, [stickyMentions, agentConfigurations, stickyMentionsTextContent]); + return ( <> - ); - const wrapper = document.createElement("div"); - wrapper.innerHTML = htmlString.trim(); - const mentionNode = wrapper.firstChild; + const mentionNode = getAgentMentionNode(selected); // This is mainly to please TypeScript. if (!mentionNode || !mentionSelectNode.parentNode) { @@ -594,12 +654,7 @@ export function AssistantInputBar({ onItemClick={(c) => { // We construct the HTML for an AgentMention and inject it in the content // editable with an extra space after it. - const htmlString = ReactDOMServer.renderToStaticMarkup( - - ); - const wrapper = document.createElement("div"); - wrapper.innerHTML = htmlString.trim(); - const mentionNode = wrapper.firstChild; + const mentionNode = getAgentMentionNode(c); const contentEditable = document.getElementById("dust-input-bar"); if (contentEditable && mentionNode) { @@ -631,17 +686,34 @@ export function AssistantInputBar({ export function FixedAssistantInputBar({ owner, onSubmit, + stickyMentions, }: { owner: WorkspaceType; onSubmit: (input: string, mentions: MentionType[]) => void; + stickyMentions?: AgentMention[]; }) { return (
- +
); } export const InputBarContext = createContext({ animate: false }); + +function getAgentMentionNode( + agentConfiguration: AgentConfigurationType +): ChildNode | null { + const htmlString = ReactDOMServer.renderToStaticMarkup( + + ); + const wrapper = document.createElement("div"); + wrapper.innerHTML = htmlString.trim(); + return wrapper.firstChild; +} diff --git a/front/pages/w/[wId]/assistant/[cId]/index.tsx b/front/pages/w/[wId]/assistant/[cId]/index.tsx index 332f1eacefd1..dc42e2aaa115 100644 --- a/front/pages/w/[wId]/assistant/[cId]/index.tsx +++ b/front/pages/w/[wId]/assistant/[cId]/index.tsx @@ -1,5 +1,6 @@ import { GetServerSideProps, InferGetServerSidePropsType } from "next"; import { useRouter } from "next/router"; +import { useState } from "react"; import Conversation from "@app/components/assistant/conversation/Conversation"; import { ConversationTitle } from "@app/components/assistant/conversation/ConversationTitle"; @@ -7,7 +8,7 @@ import { FixedAssistantInputBar } from "@app/components/assistant/conversation/I import { AssistantSidebarMenu } from "@app/components/assistant/conversation/SidebarMenu"; import AppLayout from "@app/components/sparkle/AppLayout"; import { Authenticator, getSession, getUserFromSession } from "@app/lib/auth"; -import { MentionType } from "@app/types/assistant/conversation"; +import { AgentMention, MentionType } from "@app/types/assistant/conversation"; import { UserType, WorkspaceType } from "@app/types/user"; const { URL = "", GA_TRACKING_ID = "" } = process.env; @@ -55,6 +56,7 @@ export default function AssistantConversation({ conversationId, }: InferGetServerSidePropsType) { const router = useRouter(); + const [stickyMentions, setStickyMentions] = useState([]); const handleSubmit = async (input: string, mentions: MentionType[]) => { // Create a new user message. @@ -121,8 +123,17 @@ export default function AssistantConversation({ } > - - + +
); } diff --git a/front/pages/w/[wId]/assistant/new.tsx b/front/pages/w/[wId]/assistant/new.tsx index 7eb3df6e027c..b32a2b542505 100644 --- a/front/pages/w/[wId]/assistant/new.tsx +++ b/front/pages/w/[wId]/assistant/new.tsx @@ -344,7 +344,11 @@ export default function AssistantNew({ ) : ( - + )} From 0f1e834e898d561c99a3f145a3a30411206c51ce Mon Sep 17 00:00:00 2001 From: Edouard Wautier <4435185+Duncid@users.noreply.github.com> Date: Fri, 29 Sep 2023 11:56:37 +0200 Subject: [PATCH 08/22] Trying larger gap on participants (#1860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: édouard wautier --- .../conversation/ConversationTitle.tsx | 133 +++++++++--------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/front/components/assistant/conversation/ConversationTitle.tsx b/front/components/assistant/conversation/ConversationTitle.tsx index d06e19b6f423..adc46e07bf52 100644 --- a/front/components/assistant/conversation/ConversationTitle.tsx +++ b/front/components/assistant/conversation/ConversationTitle.tsx @@ -49,7 +49,7 @@ export function ConversationTitle({ {conversation?.title || ""} -
+
))} @@ -85,83 +84,83 @@ export function ConversationTitle({ visual={user.pictureUrl} size="md" key={i} - isRounded /> ))}
-
- {onDelete && ( - - -
-
-
+ + +
-
-
- - - + + + ); From 6dbe604d35b132490c59960347bd3d2262379d07 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Fri, 29 Sep 2023 12:31:37 +0200 Subject: [PATCH 09/22] enh: add retrievedAt column on retrievalDocument (#1867) * enh: add retrievedAt column on retrievalDocument * tmp * feedback --- front/lib/api/assistant/actions/retrieval.ts | 1 + front/lib/models/assistant/actions/retrieval.ts | 5 +++++ .../20230929_retrieveal_docs_document_timestamp.sql | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 front/migrations/20230929_retrieveal_docs_document_timestamp.sql diff --git a/front/lib/api/assistant/actions/retrieval.ts b/front/lib/api/assistant/actions/retrieval.ts index 609d9dc2730d..426133efdf1c 100644 --- a/front/lib/api/assistant/actions/retrieval.ts +++ b/front/lib/api/assistant/actions/retrieval.ts @@ -625,6 +625,7 @@ export async function* runRetrieval( documentId: d.documentId, reference: d.reference, timestamp: d.timestamp, + documentTimestamp: new Date(d.timestamp), tags: d.tags, score: d.score, retrievalActionId: action.id, diff --git a/front/lib/models/assistant/actions/retrieval.ts b/front/lib/models/assistant/actions/retrieval.ts index c51c04766713..67bbf799e6d6 100644 --- a/front/lib/models/assistant/actions/retrieval.ts +++ b/front/lib/models/assistant/actions/retrieval.ts @@ -313,6 +313,7 @@ export class RetrievalDocument extends Model< declare documentId: string; declare reference: string; declare timestamp: number; + declare documentTimestamp: Date | null; declare tags: string[]; declare score: number; @@ -356,6 +357,10 @@ RetrievalDocument.init( type: DataTypes.BIGINT, allowNull: false, }, + documentTimestamp: { + type: DataTypes.DATE, + allowNull: true, + }, tags: { type: DataTypes.ARRAY(DataTypes.STRING), allowNull: false, diff --git a/front/migrations/20230929_retrieveal_docs_document_timestamp.sql b/front/migrations/20230929_retrieveal_docs_document_timestamp.sql new file mode 100644 index 000000000000..6c903bb9d75d --- /dev/null +++ b/front/migrations/20230929_retrieveal_docs_document_timestamp.sql @@ -0,0 +1,4 @@ +UPDATE + "retrieval_documents" +SET + "documentTimestamp" = to_timestamp("timestamp" / 1000); \ No newline at end of file From 36641924d210a42f9fe8fb9d5e2ad313adcaf804 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 12:32:27 +0200 Subject: [PATCH 10/22] Fix modal actions (#1878) --- sparkle/package-lock.json | 4 ++-- sparkle/package.json | 2 +- sparkle/src/components/Modal.tsx | 4 +++- sparkle/src/stories/Modal.stories.tsx | 6 ++++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sparkle/package-lock.json b/sparkle/package-lock.json index ac6bf8bdf590..bb5e70815139 100644 --- a/sparkle/package-lock.json +++ b/sparkle/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dust-tt/sparkle", - "version": "0.1.89", + "version": "0.1.92", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dust-tt/sparkle", - "version": "0.1.89", + "version": "0.1.92", "license": "ISC", "dependencies": { "@headlessui/react": "^1.7.17" diff --git a/sparkle/package.json b/sparkle/package.json index 183f76db7616..e8356d7fe414 100644 --- a/sparkle/package.json +++ b/sparkle/package.json @@ -1,6 +1,6 @@ { "name": "@dust-tt/sparkle", - "version": "0.1.91", + "version": "0.1.92", "scripts": { "build": "rm -rf dist && rollup -c", "build:with-tw-base": "rollup -c --environment INCLUDE_TW_BASE:true", diff --git a/sparkle/src/components/Modal.tsx b/sparkle/src/components/Modal.tsx index f9e0142b04a2..56c62e54e2d0 100644 --- a/sparkle/src/components/Modal.tsx +++ b/sparkle/src/components/Modal.tsx @@ -4,7 +4,7 @@ import React, { Fragment } from "react"; import { classNames } from "@sparkle/lib/utils"; import { BarHeader, BarHeaderButtonBarProps } from "./BarHeader"; -import { ButtonProps } from "./Button"; +import { Button, ButtonProps } from "./Button"; interface ModalProps { isOpen: boolean; @@ -20,6 +20,7 @@ interface ModalProps { export function Modal({ isOpen, onClose, + action, children, hasChanged, onSave, @@ -78,6 +79,7 @@ export function Modal({ > : undefined} rightActions={} />
{ setIsOpenWithActionAndChange(false)} + action={{ + labelVisible: true, + label: "An action", + variant: "tertiary", + size: "xs", + }} hasChanged={true} >
I'm the modal content
From f86afa2b3ee64568283323e4420572aceb88d6b7 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 12:42:38 +0200 Subject: [PATCH 11/22] Bump sparkle to fix modal (#1879) --- front/package-lock.json | 8 ++++---- front/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/front/package-lock.json b/front/package-lock.json index 8ce7d6686764..309bebcfc57e 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@dust-tt/sparkle": "0.1.91", + "@dust-tt/sparkle": "0.1.92", "@headlessui/react": "^1.7.7", "@heroicons/react": "^2.0.11", "@nangohq/frontend": "^0.16.1", @@ -722,9 +722,9 @@ "license": "Apache-2.0" }, "node_modules/@dust-tt/sparkle": { - "version": "0.1.91", - "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.1.91.tgz", - "integrity": "sha512-O5ZWHVEXtV/IOHBJdWeTk+jaDU+8hJWkREiBKfb7H4kkO1DHD+k2i6TuJnQB0YO6xzChV80GUzxmt0OvV1XUBQ==", + "version": "0.1.92", + "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.1.92.tgz", + "integrity": "sha512-Q+WWQdugcBknny3ntju3fXsf1TBiLV++02K0PBcLProIEH5wehzR/r9wBnDwe3NVtUHjMY/AbXrtUCGIjMWEtA==", "dependencies": { "@headlessui/react": "^1.7.17" }, diff --git a/front/package.json b/front/package.json index 4a970213e2ad..f51a4f421679 100644 --- a/front/package.json +++ b/front/package.json @@ -13,7 +13,7 @@ "initdb": "env $(cat .env.local) npx tsx admin/db.ts" }, "dependencies": { - "@dust-tt/sparkle": "0.1.91", + "@dust-tt/sparkle": "0.1.92", "@headlessui/react": "^1.7.7", "@heroicons/react": "^2.0.11", "@nangohq/frontend": "^0.16.1", From 6a7bd7cabdaec946f668421d1a1c79f5b5e52835 Mon Sep 17 00:00:00 2001 From: Henry Fontanier Date: Fri, 29 Sep 2023 12:47:44 +0200 Subject: [PATCH 12/22] use documentTimestamp instead of timeStamp (#1880) --- front/lib/api/assistant/actions/retrieval.ts | 3 +-- front/lib/models/assistant/actions/retrieval.ts | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/front/lib/api/assistant/actions/retrieval.ts b/front/lib/api/assistant/actions/retrieval.ts index 426133efdf1c..e80729be38a5 100644 --- a/front/lib/api/assistant/actions/retrieval.ts +++ b/front/lib/api/assistant/actions/retrieval.ts @@ -334,7 +334,7 @@ export async function renderRetrievalActionByModelId( sourceUrl: d.sourceUrl, documentId: d.documentId, reference: d.reference, - timestamp: d.timestamp, + timestamp: d.documentTimestamp.getTime(), tags: d.tags, score: d.score, chunks, @@ -624,7 +624,6 @@ export async function* runRetrieval( sourceUrl: d.sourceUrl, documentId: d.documentId, reference: d.reference, - timestamp: d.timestamp, documentTimestamp: new Date(d.timestamp), tags: d.tags, score: d.score, diff --git a/front/lib/models/assistant/actions/retrieval.ts b/front/lib/models/assistant/actions/retrieval.ts index 67bbf799e6d6..53b607d8f880 100644 --- a/front/lib/models/assistant/actions/retrieval.ts +++ b/front/lib/models/assistant/actions/retrieval.ts @@ -312,8 +312,7 @@ export class RetrievalDocument extends Model< declare sourceUrl: string | null; declare documentId: string; declare reference: string; - declare timestamp: number; - declare documentTimestamp: Date | null; + declare documentTimestamp: Date; declare tags: string[]; declare score: number; @@ -353,13 +352,14 @@ RetrievalDocument.init( type: DataTypes.STRING, allowNull: false, }, + // @ts-expect-error deprecated timestamp: { type: DataTypes.BIGINT, - allowNull: false, + allowNull: true, }, documentTimestamp: { type: DataTypes.DATE, - allowNull: true, + allowNull: false, }, tags: { type: DataTypes.ARRAY(DataTypes.STRING), From 6f19682ce3fa7209cbde143458a1df582a8c8453 Mon Sep 17 00:00:00 2001 From: Aric Lasry Date: Fri, 29 Sep 2023 13:58:02 +0200 Subject: [PATCH 13/22] =?UTF-8?q?Auto=20upgrading=20Google=20OAuth=20accou?= =?UTF-8?q?nts=20and=20allowing=20Google=20workspaces=20t=E2=80=A6=20(#188?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Auto upgrading Google OAuth accounts and allowing Google workspaces to see their documents * Clean up after @spolu's review --- front/pages/api/login.ts | 5 ++++- .../w/[wId]/builder/data-sources/[name]/index.tsx | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/front/pages/api/login.ts b/front/pages/api/login.ts index 5e5f8336805d..97d633085502 100644 --- a/front/pages/api/login.ts +++ b/front/pages/api/login.ts @@ -20,7 +20,10 @@ const { DUST_INVITE_TOKEN_SECRET = "" } = process.env; // List of emails for which all worksapces should be upgraded // at sign-up time. -const EMAILS_TO_AUTO_UPGRADE = ["oauthtest121@gmail.com"]; +const EMAILS_TO_AUTO_UPGRADE = [ + "oauthtest121@gmail.com", + "oauthtest222@gmail.com", +]; async function handler( req: NextApiRequest, diff --git a/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx b/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx index 22d12d4b4abd..569ed0f301d5 100644 --- a/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx +++ b/front/pages/w/[wId]/builder/data-sources/[name]/index.tsx @@ -44,6 +44,8 @@ const { GITHUB_APP_URL = "", } = process.env; +const GOOGLE_OAUTH_WORKSPACE_IDS = ["17fd918e1d", "2f151df544"]; + export const getServerSideProps: GetServerSideProps<{ user: UserType | null; owner: WorkspaceType; @@ -515,6 +517,17 @@ function ManagedDataSourceView({
+ {GOOGLE_OAUTH_WORKSPACE_IDS.includes(owner.sId) && ( +
- {isFullyUpgraded && workspaceHasManagedDataSources && ( + {workspace.upgradedAt && workspaceHasManagedDataSources && (

Delete managed data sources before downgrading. diff --git a/front/pages/w/[wId]/builder/data-sources/[name]/upsert.tsx b/front/pages/w/[wId]/builder/data-sources/[name]/upsert.tsx index 0df87e106ad3..434dc0d4f73c 100644 --- a/front/pages/w/[wId]/builder/data-sources/[name]/upsert.tsx +++ b/front/pages/w/[wId]/builder/data-sources/[name]/upsert.tsx @@ -116,10 +116,27 @@ export default function DataSourceUpsert({ } }, [dataSource.name, loadDocumentId, owner.sId]); + const alertDataSourcesLimit = () => { + window.alert( + "DataSource document upload size is limited to " + + `${owner.plan.limits.dataSources.documents.sizeMb}MB (of raw text)` + + ". Contact team@dust.tt if you want to increase this limit." + ); + }; + const handleFileLoadedText = (e: any) => { const content = e.target.result; - setText(content); setUploading(false); + + // Enforce plan limits: DataSource documents size. + if ( + owner.plan.limits.dataSources.documents.sizeMb != -1 && + text.length > 1024 * 1024 * owner.plan.limits.dataSources.documents.sizeMb + ) { + alertDataSourcesLimit(); + return; + } + setText(content); }; const handleFileLoadedPDF = async (e: any) => { @@ -133,21 +150,21 @@ export default function DataSourceUpsert({ const strings = content.items.map((item: any) => item.str); text += strings.join(" ") + "\n"; } - setText(text); + setUploading(false); - }; - const handleFileUpload = async (file: File) => { // Enforce plan limits: DataSource documents size. if ( owner.plan.limits.dataSources.documents.sizeMb != -1 && - file.size > 1024 * 1024 * owner.plan.limits.dataSources.documents.sizeMb + text.length > 1024 * 1024 * owner.plan.limits.dataSources.documents.sizeMb ) { - window.alert( - "DataSource document upload size is limited to 1MB on our free plan. Contact team@dust.tt if you want to increase this limit." - ); + alertDataSourcesLimit(); return; } + setText(text); + }; + + const handleFileUpload = async (file: File) => { setUploading(true); if (file.type === "application/pdf") { const fileReader = new FileReader(); From a9cf48fe06a9739cd56f3cb57e2d4cb4f90a182d Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 16:10:07 +0200 Subject: [PATCH 20/22] 4MB after all (#1896) --- front/lib/api/workspace.ts | 4 ++-- .../20230929_enforce_1mb_even_for_upgraded_workspaces.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/front/lib/api/workspace.ts b/front/lib/api/workspace.ts index ce31dd71566c..70b3f4a70427 100644 --- a/front/lib/api/workspace.ts +++ b/front/lib/api/workspace.ts @@ -127,8 +127,8 @@ export async function upgradeWorkspace(workspaceId: number) { plan.limits.dataSources.count = -1; plan.limits.dataSources.documents.count = -1; - // Enforce 1MB limitation even for upgraded workspaces. - plan.limits.dataSources.documents.sizeMb = 1; + // Enforce 4MB limitation even for upgraded workspaces. + plan.limits.dataSources.documents.sizeMb = 4; plan.limits.dataSources.managed = true; plan.limits.largeModels = true; diff --git a/front/migrations/20230929_enforce_1mb_even_for_upgraded_workspaces.ts b/front/migrations/20230929_enforce_1mb_even_for_upgraded_workspaces.ts index 7f4cd3f0b65a..e411660e7186 100644 --- a/front/migrations/20230929_enforce_1mb_even_for_upgraded_workspaces.ts +++ b/front/migrations/20230929_enforce_1mb_even_for_upgraded_workspaces.ts @@ -37,7 +37,7 @@ async function main() { async function set1MBLimit(live: boolean, workspace: Workspace) { const plan = planForWorkspace(workspace); - plan.limits.dataSources.documents.sizeMb = 1; + plan.limits.dataSources.documents.sizeMb = 4; if (live) { await workspace.update({ plan: JSON.stringify(plan), From 2a49ed8a68e321d04379ba2a4362fd3471539fec Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 16:52:43 +0200 Subject: [PATCH 21/22] Do await user message on create conversation + mode docs (#1897) --- docs/src/pages/conversations.mdx | 101 +++++++++++++++++- .../w/[wId]/assistant/conversations/index.ts | 24 +++-- 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/docs/src/pages/conversations.mdx b/docs/src/pages/conversations.mdx index bf0372a1664c..02b9425b3086 100644 --- a/docs/src/pages/conversations.mdx +++ b/docs/src/pages/conversations.mdx @@ -289,11 +289,8 @@ The `agent_error` event is sent whenever an error occured durint the AgentMessag - An initial user message object. See the curl command for an example of a message object - mentioning the `@dust` assistant. Available global assistant `configurationId` are: - `helper`, `dust`, `gpt-3.5-turbo`, `gpt-4`, `claude-2`, `claude-instant-1`, `slack`, - `google_drive`, `notion`, `github`. To mention custom assistants, you can find the assistant - `configurationId` in the URL of the assistant page. + An initial user message object. See "Create a New User Message" endpoint body attributes for + more details. @@ -343,6 +340,100 @@ The `agent_error` event is sent whenever an error occured durint the AgentMessag "unlisted", "content": [] } + "message": {...} + } + ``` + + + + +--- + +## Create a new User Message {{ tag: 'POST', label: '/v1/w/:workspace_id/assistant/conversations/:conversation_id/messages' }} + + + + + This endpoint allows you to post a new user message in a conversation, potentially triggering an assistant response. + + ### URL attributes + + + + The ID of the workspace to use (can be found in any of the workspace's URL) + + + The `sId` of the conversation object to retrieve. + + + + ### JSON body attributes + + + + The textual content of the message. Mentions to assistants in the message content should be + sent as markdown directives `:cite[assistantName]{configurationId}` so that they can be + properly rendered in the Dust interface. + + + Mentions are a way to trigger the response of an assistant in a message. They are an array + of objects with a single `configurationId` field which points the assistant being mentioned. + Available global assistant `configurationId` are: `helper`, `dust`, `gpt-3.5-turbo`, + `gpt-4`, `claude-2`, `claude-instant-1`, `slack`, `google_drive`, `notion`, `github`. To + mention custom assistants, you can find the assistant `configurationId` in the URL of the + assistant page. + + + An object with attributes about the user posting the message. Required attributes are + `timezone` (in the format of Javascript `Intl.DateTimeFormat().resolvedOptions().timeZone`, + eg: `Europe/Paris`), and `username`. Optional attributes are `email`, `fullName` and + `profilePictureUrl`. + + + + + + + + + ```bash {{ title: 'cURL' }} + curl https://dust.tt/api/v1/w/b809011d38/assistant/conversations/7b6396245c/messages \ + -H "Authorization: Bearer sk-..." \ + -H "Content-Type: application/json" \ + -d '{ + "content": "Hi :cite[dust]{dust}!", + "mentions": [{ + "configurationId": "dust" + }], + "context": { + "timezone": "Europe/Paris", + "username": "peter", + "email": null, + "fullName": "Peter Parker", + "profilePictureUrl": "https://dust.tt/static/systemavatar/helper_avatar_full.png" + } + }' + ``` + + + + ```json {{ title: 'Response' }} + { + "message": { + "sId": "e20e7b5aac", + "type": "user_message", + "visibility": "visible", + "version": 0,"user": null, + "mentions": [{ "configurationId":"dust" }], + "content": "Hi :cite[dust]{dust}!", + "context": { + "timezone": "Europe/Paris", + "username": "peter", + "fullName": "Peter Parker", + "email":null, + "profilePictureUrl": "https://dust.tt/static/systemavatar/helper_avatar_full.png" + } + } } ``` diff --git a/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts b/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts index 54fd6934f1ab..f3f74ec0f30b 100644 --- a/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts +++ b/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts @@ -9,7 +9,10 @@ import { Authenticator, getAPIKey } from "@app/lib/auth"; import { ReturnedAPIErrorType } from "@app/lib/error"; import { apiError, withLogging } from "@app/logger/withlogging"; import { PostMessagesRequestBodySchema } from "@app/pages/api/v1/w/[wId]/assistant/conversations/[cId]/messages"; -import { ConversationType } from "@app/types/assistant/conversation"; +import { + ConversationType, + UserMessageType, +} from "@app/types/assistant/conversation"; const PostConversationsRequestBodySchema = t.type({ title: t.union([t.string, t.null]), @@ -23,6 +26,7 @@ const PostConversationsRequestBodySchema = t.type({ export type PostConversationsResponseBody = { conversation: ConversationType; + message?: UserMessageType; }; async function handler( @@ -86,10 +90,9 @@ async function handler( }); if (message) { - // Not awaiting this promise on purpose. We want to answer "OK" to the client ASAP and - // process the events in the background. So that the client gets updated as soon as - // possible. - void postUserMessageWithPubSub(auth, { + // If a message was provided we do await for the message to be posted before returning the + // conversation along with the message. + const messageRes = await postUserMessageWithPubSub(auth, { conversation, content: message.content, mentions: message.mentions, @@ -101,9 +104,16 @@ async function handler( profilePictureUrl: message.context.profilePictureUrl, }, }); - } - res.status(200).json({ conversation }); + if (messageRes.isErr()) { + return apiError(req, res, messageRes.error); + } + + res.status(200).json({ conversation, message: messageRes.value }); + } else { + // Otherwise we simply return the conversation created. + res.status(200).json({ conversation }); + } return; default: From e449a83c1c6b61c5924551c1ea196043105c62b0 Mon Sep 17 00:00:00 2001 From: Stanislas Polu Date: Fri, 29 Sep 2023 17:10:29 +0200 Subject: [PATCH 22/22] Even more user-friendly Conversations API (#1898) * Make conversation creation even more user friendly * update to docs --- docs/src/pages/conversations.mdx | 35 +++++++++++++++++-- .../w/[wId]/assistant/conversations/index.ts | 18 ++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/src/pages/conversations.mdx b/docs/src/pages/conversations.mdx index 02b9425b3086..0785831fc850 100644 --- a/docs/src/pages/conversations.mdx +++ b/docs/src/pages/conversations.mdx @@ -259,10 +259,11 @@ The `agent_error` event is sent whenever an error occured durint the AgentMessag - This endpoint allows you to create a Conversation potentially posting an initial user message at the same time. If you specify an initial user message, the conversation objet returned will be - returned upon creation before posting the user message to it. + returned including the user message and potential assistant response messages as they got added + (`created` status). Knowing their `sId` will enable you to stream their events without having to + retrieve the conversation object again. ### URL attributes @@ -338,7 +339,35 @@ The `agent_error` event is sent whenever an error occured durint the AgentMessag "title":null, "visibility": "unlisted", - "content": [] + "content": [ + [{ + "sId": "1651e51da4", + "type": "user_message", + "visibility": "visible", + "version": 0, + "user": null, + "mentions": [{"configurationId":"dust"}], + "content": "Hi :cite[dust]{dust}!", + "context": { + "username": "peter", + "timezone": "Europe/Paris", + "fullName": "Peter Parker", + "email": null, + "profilePictureUrl": "https://dust.tt/static/systemavatar/helper_avatar_full.png" + } + }] , [{ + "sId": "fa72419067", + "type": "agent_message", + "visibility": "visible", + "version": 0, + "parentMessageId": "1651e51da4", + "status": "created", + "action": null, + "content": null, + "error":null, + "configuration":{...} + }] + ] } "message": {...} } diff --git a/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts b/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts index f3f74ec0f30b..c026f6aaa6f8 100644 --- a/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts +++ b/front/pages/api/v1/w/[wId]/assistant/conversations/index.ts @@ -3,7 +3,10 @@ import * as t from "io-ts"; import * as reporter from "io-ts-reporters"; import { NextApiRequest, NextApiResponse } from "next"; -import { createConversation } from "@app/lib/api/assistant/conversation"; +import { + createConversation, + getConversation, +} from "@app/lib/api/assistant/conversation"; import { postUserMessageWithPubSub } from "@app/lib/api/assistant/pubsub"; import { Authenticator, getAPIKey } from "@app/lib/auth"; import { ReturnedAPIErrorType } from "@app/lib/error"; @@ -109,7 +112,18 @@ async function handler( return apiError(req, res, messageRes.error); } - res.status(200).json({ conversation, message: messageRes.value }); + // If we got the user message we know that the agent messages have been created as well, so + // we pull the conversation again to have the created agent message included so that the + // user of the API can start streaming events from these agent messages directly. + const updated = await getConversation(auth, conversation.sId); + + if (!updated) { + throw `Conversation unexpectedly not found after creation: ${conversation.sId}`; + } + + res + .status(200) + .json({ conversation: updated, message: messageRes.value }); } else { // Otherwise we simply return the conversation created. res.status(200).json({ conversation });