import { useState } from "react"; import { View, Text, Pressable } from "react-native"; import { StyleSheet } from "react-native-unistyles"; import { Fonts } from "@/constants/theme"; import type { AgentActivity, GroupedTextMessage, MergedToolCall, SessionUpdate, } from "@/types/agent-activity"; interface AgentActivityItemProps { item: GroupedTextMessage | MergedToolCall | AgentActivity; } function formatTimestamp(date: Date): string { return new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit", second: "2-digit", hour12: true, }).format(date); } function getToolIcon(toolKind?: string): string { switch (toolKind) { case "read": return "📖"; case "edit": return "✏️"; case "delete": return "🗑️"; case "move": return "📦"; case "search": return "🔍"; case "execute": return "▶️"; case "think": return "💭"; case "fetch": return "🌐"; case "switch_mode": return "🔄"; default: return "🔧"; } } function getStatusColor(status?: string): string { switch (status) { case "pending": return "#9ca3af"; case "in_progress": return "#fbbf24"; case "completed": return "#22c55e"; case "failed": return "#ef4444"; default: return "#6b7280"; } } function GroupedTextItem({ item }: { item: GroupedTextMessage }) { const isThought = item.messageType === "thought"; return ( {formatTimestamp(item.startTimestamp)} {isThought && 💭 Thinking} {item.text} ); } function MergedToolCallItem({ item }: { item: MergedToolCall }) { const [isExpanded, setIsExpanded] = useState(false); return ( setIsExpanded(!isExpanded)} style={stylesheet.toolHeader}> {formatTimestamp(item.startTimestamp)} {getToolIcon(item.toolKind)} {item.title} {item.status} {isExpanded ? "▼" : "▶"} {isExpanded && ( {item.input && ( Input: {JSON.stringify(item.input, null, 2)} )} {item.output && ( Output: {JSON.stringify(item.output, null, 2)} )} {!item.input && !item.output && ( No details available )} )} ); } function PlanItem({ update, timestamp }: { update: SessionUpdate; timestamp: Date }) { const [isExpanded, setIsExpanded] = useState(true); if (update.kind !== "plan") { return null; } return ( setIsExpanded(!isExpanded)} style={stylesheet.planHeader}> {formatTimestamp(timestamp)} 📋 Tasks ({update.entries.length}) {isExpanded ? "▼" : "▶"} {isExpanded && ( {update.entries.map((entry, idx) => ( {entry.status === "completed" ? "✓" : entry.status === "in_progress" ? "⏳" : "○"} {entry.content} ))} )} ); } function UnknownActivityItem({ update, timestamp }: { update: SessionUpdate; timestamp: Date }) { const [showDrawer, setShowDrawer] = useState(false); return ( setShowDrawer(!showDrawer)} style={stylesheet.unknownHeader}> {formatTimestamp(timestamp)} {update.kind} {showDrawer && ( {JSON.stringify(update, null, 2)} )} ); } export function AgentActivityItem({ item }: AgentActivityItemProps) { // Grouped text message if ("kind" in item && item.kind === "grouped_text") { return ; } // Merged tool call if ("kind" in item && item.kind === "merged_tool_call") { return ; } // Individual activity const activity = item as AgentActivity; const update = activity.update; // Tasks if (update.kind === "plan") { return ; } // Available commands update if (update.kind === "available_commands_update") { return ( {formatTimestamp(activity.timestamp)} Commands updated ({update.availableCommands.length} available) ); } // Current mode update if (update.kind === "current_mode_update") { return ( {formatTimestamp(activity.timestamp)} Mode changed to: {update.currentModeId} ); } // Unknown activity type return ; } const stylesheet = StyleSheet.create((theme) => ({ card: { backgroundColor: theme.colors.surface2, borderRadius: theme.borderRadius.lg, padding: theme.spacing[3], marginBottom: theme.spacing[2], }, thoughtCard: { backgroundColor: theme.colors.surface2, borderLeftWidth: 3, borderLeftColor: theme.colors.palette.purple[500], paddingVertical: theme.spacing[2], }, timestamp: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, marginBottom: theme.spacing[1], }, thoughtTimestamp: { marginBottom: theme.spacing[0], }, thoughtLabel: { color: theme.colors.palette.purple[500], fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.semibold, marginBottom: theme.spacing[0], }, text: { color: theme.colors.foreground, fontSize: theme.fontSize.sm, lineHeight: 20, }, thoughtText: { color: theme.colors.foregroundMuted, fontStyle: "italic", }, toolCard: { backgroundColor: theme.colors.surface2, borderRadius: theme.borderRadius.lg, marginBottom: theme.spacing[2], overflow: "hidden", }, toolHeader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", padding: theme.spacing[3], }, toolHeaderLeft: { flex: 1, }, toolTitleRow: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], marginTop: theme.spacing[1], }, toolIcon: { fontSize: theme.fontSize.base, }, toolTitle: { color: theme.colors.palette.blue[400], fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.semibold, flex: 1, }, statusBadge: { paddingHorizontal: theme.spacing[2], paddingVertical: theme.spacing[1], borderRadius: theme.borderRadius.md, }, statusText: { color: theme.colors.foreground, fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.semibold, }, expandIcon: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, }, toolContent: { borderTopWidth: theme.borderWidth[1], borderTopColor: theme.colors.border, padding: theme.spacing[3], }, section: { marginBottom: theme.spacing[3], }, sectionTitle: { color: theme.colors.foreground, fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.semibold, marginBottom: theme.spacing[1], }, code: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, fontFamily: Fonts.mono, backgroundColor: theme.colors.surface2, padding: theme.spacing[2], borderRadius: theme.borderRadius.md, }, emptyText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, fontStyle: "italic", }, planCard: { backgroundColor: theme.colors.surface2, borderRadius: theme.borderRadius.lg, marginBottom: theme.spacing[2], overflow: "hidden", }, planHeader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", padding: theme.spacing[3], }, planHeaderLeft: { flex: 1, }, planTitle: { color: theme.colors.palette.green[400], fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.semibold, marginTop: theme.spacing[1], }, planContent: { borderTopWidth: theme.borderWidth[1], borderTopColor: theme.colors.border, padding: theme.spacing[3], }, planEntry: { flexDirection: "row", alignItems: "flex-start", gap: theme.spacing[2], marginBottom: theme.spacing[2], }, planEntryStatus: { fontSize: theme.fontSize.sm, marginTop: 2, }, planEntryText: { color: theme.colors.foreground, fontSize: theme.fontSize.sm, flex: 1, }, infoText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, }, unknownCard: { backgroundColor: theme.colors.surface2, borderRadius: theme.borderRadius.lg, marginBottom: theme.spacing[2], overflow: "hidden", }, unknownHeader: { padding: theme.spacing[3], }, unknownBadge: { backgroundColor: theme.colors.palette.orange[600], paddingHorizontal: theme.spacing[3], paddingVertical: theme.spacing[2], borderRadius: theme.borderRadius.md, marginTop: theme.spacing[2], alignSelf: "flex-start", }, unknownBadgeText: { color: theme.colors.foreground, fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.semibold, }, drawerContent: { borderTopWidth: theme.borderWidth[1], borderTopColor: theme.colors.border, padding: theme.spacing[3], backgroundColor: theme.colors.surface2, }, }));