email chat uses officerdev/chat app with session history and email context scoping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 23:29:13 +00:00
co-authored by Claude Opus 4.6
parent 13cfeac384
commit a8d3d1a423
6 changed files with 28 additions and 15 deletions
@@ -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<ChatSessionSelection | null>('chat:panel-session', null);
const [activeSessionId] = usePanelChannel<string | null>('chat:active-session', null);
const [open, setOpen] = useState(false);
@@ -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<ChatSessionSelection | null>('chat:panel-session', null);
const [, setActiveSession] = usePanelChannel<string | null>('chat:active-session', null);
@@ -45,6 +47,7 @@ export const ChatPanelWrapper = () => {
cwd={cwdParam}
sandboxed={sandboxed}
replaceUrl={false}
promptPrefix={promptPrefix}
{...chatContext}
/>
);
@@ -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;
@@ -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 (
<WorkspaceProvider value={{ workspaceId: workspaceId ?? null, cwd: cwd ?? '~', swapSourceId: null, setSwapSourceId: noop, onSwap: noop, dragSourceId: null, setDragSourceId: noop, onMove: noop, maximizedPanelId: null, setMaximizedPanelId: noop, transitioningPanelId: null, isMobile: isMobile ?? false, onMobileBack: onMobileBack ?? null }}>
<WorkspaceProvider value={{ workspaceId: workspaceId ?? null, cwd: cwd ?? '~', promptPrefix, swapSourceId: null, setSwapSourceId: noop, onSwap: noop, dragSourceId: null, setDragSourceId: noop, onMove: noop, maximizedPanelId: null, setMaximizedPanelId: noop, transitioningPanelId: null, isMobile: isMobile ?? false, onMobileBack: onMobileBack ?? null }}>
<WorkspaceRenderer
layout={layout}
registry={registry}