diff --git a/src/apps/officer-web/Screens/Dashboard/Email/EmailScreen.tsx b/src/apps/officer-web/Screens/Dashboard/Email/EmailScreen.tsx index e19be403..d67eb369 100644 --- a/src/apps/officer-web/Screens/Dashboard/Email/EmailScreen.tsx +++ b/src/apps/officer-web/Screens/Dashboard/Email/EmailScreen.tsx @@ -6,7 +6,8 @@ import { useGlobal } from 'hooks/useGlobal'; import { defaultLayout } from './defaultLayout'; import { EmailList } from './EmailList'; import { EmailReader } from './EmailReader'; -import { EmailChat } from './EmailChat'; + +const PROMPT_PREFIX = `You are an email assistant. The user has a local SQLite email database available via the "email-db" tool — use it for all email queries (search, count, stats, aggregations, deletions) unless the user explicitly asks you to use Gmail. Do not use the Gmail integration for questions about existing emails.`; export const EmailScreen = () => { const isMobile = useIsMobile(); @@ -16,7 +17,6 @@ export const EmailScreen = () => { () => ({ 'email-list': EmailList, 'email-reader': EmailReader, - 'email-chat': EmailChat, }), [], ); @@ -30,6 +30,8 @@ export const EmailScreen = () => { layout={defaultLayout} onLayoutChange={() => {}} components={components} + workspaceId="email" + promptPrefix={PROMPT_PREFIX} isMobile={isMobile} mobilePanelId={mobilePanelId} onMobileBack={mobilePanelId ? onMobileBack : null} diff --git a/src/apps/officer-web/Screens/Dashboard/Email/defaultLayout.ts b/src/apps/officer-web/Screens/Dashboard/Email/defaultLayout.ts index 77ae4863..5fcdc180 100644 --- a/src/apps/officer-web/Screens/Dashboard/Email/defaultLayout.ts +++ b/src/apps/officer-web/Screens/Dashboard/Email/defaultLayout.ts @@ -13,7 +13,7 @@ export const defaultLayout: LayoutNode = { direction: 'vertical', children: [ { node: { type: 'panel', id: 'email-reader', appType: null }, size: 60 }, - { node: { type: 'panel', id: 'email-chat', appType: null }, size: 40 }, + { node: { type: 'panel', id: 'email-chat', appType: 'officerdev/chat' }, size: 40 }, ], }, size: 75, diff --git a/src/workspaces/officerdev/src/apps/Chat/ChatHeader.tsx b/src/workspaces/officerdev/src/apps/Chat/ChatHeader.tsx index 093c4ea3..03778552 100644 --- a/src/workspaces/officerdev/src/apps/Chat/ChatHeader.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/ChatHeader.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import { MessageSquare, History, Plus } from 'lucide-react'; import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover'; import { useWorkspace } from '../../components/Workspace/WorkspaceContext'; -import { useChatSessions } from './useChatSessions'; +import { useChatSessions } from 'state/useChatSessions'; import { usePanelChannel } from 'hooks/usePanelChannel'; import { getProviderDisplayName } from 'state/useModels'; @@ -21,9 +21,15 @@ function formatModel(model: string): string { } export const ChatHeader = () => { - const { cwd, root } = useWorkspace(); - const scoped = cwd !== '~'; - const { sessions } = useChatSessions(scoped ? { cwd, cwdRoot: root } : {}); + const { workspaceId } = useWorkspace(); + const contextFilter = workspaceId === 'email' + ? { context: 'email' as const } + : workspaceId?.startsWith('proj-layout-') + ? { context: 'project' as const, contextId: workspaceId.replace('proj-layout-', '') } + : workspaceId && !workspaceId.startsWith('screens/') + ? { context: 'workspace' as const, contextId: workspaceId } + : undefined; + const { sessions } = useChatSessions(contextFilter); const [selection, setSelection] = usePanelChannel('chat:panel-session', null); const [activeSessionId] = usePanelChannel('chat:active-session', null); const [open, setOpen] = useState(false); diff --git a/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx index af5bbf89..757e24e1 100644 --- a/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/ChatPanelWrapper.tsx @@ -10,16 +10,18 @@ type ChatSessionSelection = { }; export const ChatPanelWrapper = () => { - const { workspaceId, cwd, root } = useWorkspace(); + const { workspaceId, cwd, root, promptPrefix } = useWorkspace(); const scoped = cwd !== '~'; const hostRoot = root === '~' || root === 'officer.dev'; const sandboxed = !hostRoot; - const chatContext = workspaceId?.startsWith('proj-layout-') - ? { context: 'project' as const, contextId: workspaceId.replace('proj-layout-', '') } - : workspaceId && !workspaceId.startsWith('screens/') - ? { context: 'workspace' as const, contextId: workspaceId } - : {}; + const chatContext = workspaceId === 'email' + ? { context: 'email' as const } + : workspaceId?.startsWith('proj-layout-') + ? { context: 'project' as const, contextId: workspaceId.replace('proj-layout-', '') } + : workspaceId && !workspaceId.startsWith('screens/') + ? { context: 'workspace' as const, contextId: workspaceId } + : {}; const [selection] = usePanelChannel('chat:panel-session', null); const [, setActiveSession] = usePanelChannel('chat:active-session', null); @@ -45,6 +47,7 @@ export const ChatPanelWrapper = () => { cwd={cwdParam} sandboxed={sandboxed} replaceUrl={false} + promptPrefix={promptPrefix} {...chatContext} /> ); diff --git a/src/workspaces/officerdev/src/components/Workspace/WorkspaceContext.ts b/src/workspaces/officerdev/src/components/Workspace/WorkspaceContext.ts index 241a4428..c4ed9c43 100644 --- a/src/workspaces/officerdev/src/components/Workspace/WorkspaceContext.ts +++ b/src/workspaces/officerdev/src/components/Workspace/WorkspaceContext.ts @@ -13,6 +13,7 @@ type WorkspaceContextValue = { root?: string; initialFilePath?: string; defaultFileSort?: DefaultFileSort; + promptPrefix?: string; swapSourceId: string | null; setSwapSourceId: (id: string | null) => void; onSwap: (sourceId: string, targetId: string) => void; diff --git a/src/workspaces/officerdev/src/components/Workspace/WorkspaceLayout.tsx b/src/workspaces/officerdev/src/components/Workspace/WorkspaceLayout.tsx index ed20943b..cf3af3a9 100644 --- a/src/workspaces/officerdev/src/components/Workspace/WorkspaceLayout.tsx +++ b/src/workspaces/officerdev/src/components/Workspace/WorkspaceLayout.tsx @@ -12,6 +12,7 @@ type WorkspaceLayoutProps = { components?: PanelComponents; workspaceId?: string; cwd?: string; + promptPrefix?: string; noHeader?: boolean; isMobile?: boolean; mobilePanelId?: string; @@ -20,7 +21,7 @@ type WorkspaceLayoutProps = { const noop = () => {}; -export const WorkspaceLayout = ({ layout, onLayoutChange, registry: registryProp, components, workspaceId, cwd, noHeader, isMobile, mobilePanelId, onMobileBack }: WorkspaceLayoutProps) => { +export const WorkspaceLayout = ({ layout, onLayoutChange, registry: registryProp, components, workspaceId, cwd, promptPrefix, noHeader, isMobile, mobilePanelId, onMobileBack }: WorkspaceLayoutProps) => { const { registry: globalRegistry } = useAppRegistry(); const registry = registryProp ?? globalRegistry; @@ -32,7 +33,7 @@ export const WorkspaceLayout = ({ layout, onLayoutChange, registry: registryProp ); return ( - +