diff --git a/packages/twenty-front/src/modules/ai/components/AgentChatPrepromptEffect.tsx b/packages/twenty-front/src/modules/ai/components/AgentChatPrepromptEffect.tsx
new file mode 100644
index 0000000000..88060d153d
--- /dev/null
+++ b/packages/twenty-front/src/modules/ai/components/AgentChatPrepromptEffect.tsx
@@ -0,0 +1,41 @@
+import { useEffect } from 'react';
+import { isDefined } from 'twenty-shared/utils';
+
+import { AGENT_CHAT_RESTORE_EDITOR_CONTENT_EVENT_NAME } from '@/ai/constants/AgentChatRestoreEditorContentEventName';
+import { agentChatPrepromptState } from '@/ai/states/agentChatPrepromptState';
+import { dispatchAgentChatSendMessageEvent } from '@/ai/utils/dispatchAgentChatSendMessageEvent';
+import { dispatchBrowserEvent } from '@/browser-event/utils/dispatchBrowserEvent';
+import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
+
+export const AgentChatPrepromptEffect = () => {
+ const [agentChatPreprompt, setAgentChatPreprompt] = useAtomState(
+ agentChatPrepromptState,
+ );
+
+ useEffect(() => {
+ if (!isDefined(agentChatPreprompt)) {
+ return;
+ }
+
+ const { text, mode } = agentChatPreprompt;
+
+ const timeoutId = setTimeout(() => {
+ if (mode === 'SEND') {
+ dispatchAgentChatSendMessageEvent();
+ dispatchBrowserEvent(AGENT_CHAT_RESTORE_EDITOR_CONTENT_EVENT_NAME, {
+ content: '',
+ });
+ } else {
+ dispatchBrowserEvent(AGENT_CHAT_RESTORE_EDITOR_CONTENT_EVENT_NAME, {
+ content: text,
+ });
+ }
+
+ setAgentChatPreprompt(null);
+ }, 0);
+
+ return () => clearTimeout(timeoutId);
+ }, [agentChatPreprompt, setAgentChatPreprompt]);
+
+ return null;
+};
diff --git a/packages/twenty-front/src/modules/ai/components/AgentChatRuntimeEffects.tsx b/packages/twenty-front/src/modules/ai/components/AgentChatRuntimeEffects.tsx
index dc351447c1..a74d632ef9 100644
--- a/packages/twenty-front/src/modules/ai/components/AgentChatRuntimeEffects.tsx
+++ b/packages/twenty-front/src/modules/ai/components/AgentChatRuntimeEffects.tsx
@@ -1,4 +1,5 @@
import { AgentChatMessagesFetchEffect } from '@/ai/components/AgentChatMessagesFetchEffect';
+import { AgentChatPrepromptEffect } from '@/ai/components/AgentChatPrepromptEffect';
import { AgentChatSessionStartTimeEffect } from '@/ai/components/AgentChatSessionStartTimeEffect';
import { AgentChatStreamKeepAliveEffect } from '@/ai/components/AgentChatStreamKeepAliveEffect';
import { AgentChatStreamSubscriptionEffect } from '@/ai/components/AgentChatStreamSubscriptionEffect';
@@ -37,6 +38,7 @@ export const AgentChatRuntimeEffects = () => {
<>
+
{isAgentChatOpen && (
diff --git a/packages/twenty-front/src/modules/ai/hooks/useOpenAskAiPageWithPreprompt.ts b/packages/twenty-front/src/modules/ai/hooks/useOpenAskAiPageWithPreprompt.ts
new file mode 100644
index 0000000000..1d0ed5790e
--- /dev/null
+++ b/packages/twenty-front/src/modules/ai/hooks/useOpenAskAiPageWithPreprompt.ts
@@ -0,0 +1,35 @@
+import { useSwitchToNewAiChat } from '@/ai/hooks/useSwitchToNewAiChat';
+import {
+ AGENT_CHAT_NEW_THREAD_DRAFT_KEY,
+ agentChatDraftsByThreadIdState,
+} from '@/ai/states/agentChatDraftsByThreadIdState';
+import {
+ type AgentChatPrepromptMode,
+ agentChatPrepromptState,
+} from '@/ai/states/agentChatPrepromptState';
+import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
+
+export const useOpenAskAiPageWithPreprompt = () => {
+ const { switchToNewChat } = useSwitchToNewAiChat();
+ const setAgentChatDraftsByThreadId = useSetAtomState(
+ agentChatDraftsByThreadIdState,
+ );
+ const setAgentChatPreprompt = useSetAtomState(agentChatPrepromptState);
+
+ const openAskAiPageWithPreprompt = ({
+ text,
+ mode = 'PREFILL',
+ }: {
+ text: string;
+ mode?: AgentChatPrepromptMode;
+ }) => {
+ switchToNewChat();
+ setAgentChatDraftsByThreadId((prev) => ({
+ ...prev,
+ [AGENT_CHAT_NEW_THREAD_DRAFT_KEY]: text,
+ }));
+ setAgentChatPreprompt({ text, mode });
+ };
+
+ return { openAskAiPageWithPreprompt };
+};
diff --git a/packages/twenty-front/src/modules/ai/states/agentChatPrepromptState.ts b/packages/twenty-front/src/modules/ai/states/agentChatPrepromptState.ts
new file mode 100644
index 0000000000..8edfa3297a
--- /dev/null
+++ b/packages/twenty-front/src/modules/ai/states/agentChatPrepromptState.ts
@@ -0,0 +1,14 @@
+import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
+
+export type AgentChatPrepromptMode = 'PREFILL' | 'SEND';
+
+export type AgentChatPreprompt = {
+ text: string;
+ mode: AgentChatPrepromptMode;
+};
+
+export const agentChatPrepromptState =
+ createAtomState({
+ key: 'ai/agentChatPrepromptState',
+ defaultValue: null,
+ });
diff --git a/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts b/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts
index 56c3712ad5..8b2c4fdb76 100644
--- a/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts
+++ b/packages/twenty-front/src/modules/front-components/hooks/useFrontComponentExecutionContext.ts
@@ -13,6 +13,7 @@ import {
} from 'twenty-shared/types';
import { type AppLocale } from 'twenty-shared/translations';
+import { useOpenAskAiPageWithPreprompt } from '@/ai/hooks/useOpenAskAiPageWithPreprompt';
import { currentUserState } from '@/auth/states/currentUserState';
import { useCommandMenuConfirmationModal } from '@/command-menu-item/confirmation-modal/hooks/useCommandMenuConfirmationModal';
import { useUnmountCommand } from '@/command-menu-item/engine-command/hooks/useUnmountEngineCommand';
@@ -63,6 +64,7 @@ export const useFrontComponentExecutionContext = ({
frontComponentId,
});
const { openConfirmationModal } = useCommandMenuConfirmationModal();
+ const { openAskAiPageWithPreprompt } = useOpenAskAiPageWithPreprompt();
const { navigateSidePanel } = useNavigateSidePanel();
const { openRecordInSidePanel: openRecordInSidePanelInternal } =
useOpenRecordInSidePanel();
@@ -193,6 +195,23 @@ export const useFrontComponentExecutionContext = ({
return;
}
+ if (
+ params.page === SidePanelPages.AskAI &&
+ isDefined(params.preprompt) &&
+ isNonEmptyString(params.preprompt.text)
+ ) {
+ openAskAiPageWithPreprompt({
+ text: params.preprompt.text,
+ mode: params.preprompt.mode,
+ });
+
+ if (params.shouldResetSearchState === true) {
+ setSidePanelSearch('');
+ }
+
+ return;
+ }
+
navigateSidePanel({
page: params.page,
pageTitle: params.pageTitle,
diff --git a/packages/twenty-sdk/src/sdk/front-component/globals/frontComponentHostCommunicationApi.ts b/packages/twenty-sdk/src/sdk/front-component/globals/frontComponentHostCommunicationApi.ts
index 7472752e00..15189a50a2 100644
--- a/packages/twenty-sdk/src/sdk/front-component/globals/frontComponentHostCommunicationApi.ts
+++ b/packages/twenty-sdk/src/sdk/front-component/globals/frontComponentHostCommunicationApi.ts
@@ -45,6 +45,16 @@ export type OpenSidePanelPageParams =
pageIcon?: string;
resetNavigationStack?: boolean;
}
+ | {
+ page: SidePanelPages.AskAI;
+ pageTitle: string;
+ pageIcon?: string;
+ shouldResetSearchState?: boolean;
+ preprompt?: {
+ text: string;
+ mode?: 'PREFILL' | 'SEND';
+ };
+ }
| {
page: Exclude<
SidePanelPages,
@@ -52,6 +62,7 @@ export type OpenSidePanelPageParams =
| SidePanelPages.EditRichText
| SidePanelPages.ComposeEmail
| SidePanelPages.ViewFrontComponent
+ | SidePanelPages.AskAI
>;
pageTitle: string;
pageIcon?: string;