diff --git a/packages/app/src/components/archived-agent-callout.tsx b/packages/app/src/components/archived-agent-callout.tsx new file mode 100644 index 000000000..ccb64d5b8 --- /dev/null +++ b/packages/app/src/components/archived-agent-callout.tsx @@ -0,0 +1,99 @@ +import { useState } from 'react' +import { View, Text } from 'react-native' +import { StyleSheet } from 'react-native-unistyles' +import Animated from 'react-native-reanimated' +import { useSafeAreaInsets } from 'react-native-safe-area-context' +import { FOOTER_HEIGHT, MAX_CONTENT_WIDTH } from '@/constants/layout' +import { useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime' +import { useKeyboardShiftStyle } from '@/hooks/use-keyboard-shift-style' +import { Button } from '@/components/ui/button' +import type { Theme } from '@/styles/theme' + +interface ArchivedAgentCalloutProps { + serverId: string + agentId: string +} + +export function ArchivedAgentCallout({ serverId, agentId }: ArchivedAgentCalloutProps) { + const insets = useSafeAreaInsets() + const client = useHostRuntimeClient(serverId) + const isConnected = useHostRuntimeIsConnected(serverId) + const [isUnarchiving, setIsUnarchiving] = useState(false) + + const { style: keyboardAnimatedStyle } = useKeyboardShiftStyle({ mode: 'translate' }) + + async function handleUnarchive() { + if (!client || !isConnected || isUnarchiving) return + setIsUnarchiving(true) + try { + await client.refreshAgent(agentId) + } catch (error) { + console.error('[ArchivedAgentCallout] Failed to unarchive agent:', error) + setIsUnarchiving(false) + } + } + + return ( + + + + + This agent is archived + + + + + + ) +} + +const styles = StyleSheet.create(((theme: Theme) => ({ + container: { + flexDirection: 'column', + position: 'relative', + }, + inputAreaContainer: { + position: 'relative', + minHeight: FOOTER_HEIGHT, + marginHorizontal: 'auto', + alignItems: 'center', + width: '100%', + overflow: 'visible', + padding: theme.spacing[4], + }, + inputAreaContent: { + width: '100%', + maxWidth: MAX_CONTENT_WIDTH, + }, + callout: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: theme.spacing[3], + backgroundColor: theme.colors.surface1, + borderWidth: theme.borderWidth[1], + borderColor: theme.colors.borderAccent, + borderRadius: theme.borderRadius['2xl'], + paddingVertical: { + xs: theme.spacing[3], + md: theme.spacing[4], + }, + paddingHorizontal: { + xs: theme.spacing[4], + md: theme.spacing[6], + }, + }, + calloutText: { + color: theme.colors.foregroundMuted, + fontSize: theme.fontSize.base, + }, +})) as any) as Record diff --git a/packages/app/src/panels/agent-panel.tsx b/packages/app/src/panels/agent-panel.tsx index c1455c5c8..f9af408fe 100644 --- a/packages/app/src/panels/agent-panel.tsx +++ b/packages/app/src/panels/agent-panel.tsx @@ -6,6 +6,7 @@ import { Bot } from "lucide-react-native"; import invariant from "tiny-invariant"; import { AgentStreamView, type AgentStreamViewHandle } from "@/components/agent-stream-view"; import { AgentInputArea } from "@/components/agent-input-area"; +import { ArchivedAgentCallout } from "@/components/archived-agent-callout"; import { FileDropZone } from "@/components/file-drop-zone"; import type { ImageAttachment } from "@/components/message-input"; import { ToastViewport, useToastHost } from "@/components/toast-host"; @@ -825,6 +826,8 @@ function AgentPanelBody({ streamViewRef.current?.scrollToBottom("message-sent"); }} /> + ) : agentId && agent?.archivedAt ? ( + ) : null} {viewState.tag === "ready" &&