@@ -36,9 +36,15 @@ import {
3636 SelectTrigger ,
3737 SelectValue ,
3838} from "@/components/ui/select" ;
39- import { Loader2 , Plus , RefreshCw , Upload , X , ArrowLeft , FileText , Image as ImageIcon , Video , Music , File , Code , CheckCircle2 , ExternalLink , Brain , ShieldOff , HardDrive , StickyNote , Flag } from "lucide-react" ;
39+ import {
40+ DropdownMenu ,
41+ DropdownMenuContent ,
42+ DropdownMenuItem ,
43+ DropdownMenuTrigger ,
44+ } from "@/components/ui/dropdown-menu" ;
45+ import { Loader2 , Plus , RefreshCw , Upload , X , ArrowLeft , FileText , Image as ImageIcon , Video , Music , File , Code , CheckCircle2 , ExternalLink , Brain , ShieldOff , HardDrive , StickyNote , Flag , Download } from "lucide-react" ;
4046import Image from "next/image" ;
41- import { getMessages , storeMessage , getSessionConfigs } from "@/app/session/actions" ;
47+ import { getMessages , storeMessage , getSessionConfigs , downloadMessages } from "@/app/session/actions" ;
4248import {
4349 Message ,
4450 SessionEvent ,
@@ -470,6 +476,32 @@ export default function MessagesPage() {
470476 }
471477 } ;
472478
479+ const [ isDownloading , setIsDownloading ] = useState ( false ) ;
480+
481+ const handleDownload = async ( format : "acontext" | "openai" | "anthropic" | "gemini" ) => {
482+ setIsDownloading ( true ) ;
483+ try {
484+ const result = await downloadMessages ( sessionId , format ) ;
485+ if ( ! result . success || ! result . data ) {
486+ toast . error ( t ( "downloadFailed" ) ) ;
487+ return ;
488+ }
489+ const blob = new Blob ( [ result . data ] , { type : "application/json" } ) ;
490+ const url = URL . createObjectURL ( blob ) ;
491+ const a = document . createElement ( "a" ) ;
492+ a . href = url ;
493+ a . download = `messages-${ sessionId } -${ format } .json` ;
494+ a . click ( ) ;
495+ URL . revokeObjectURL ( url ) ;
496+ toast . success ( t ( "downloadSuccess" ) ) ;
497+ } catch ( error ) {
498+ console . error ( "Failed to download messages:" , error ) ;
499+ toast . error ( t ( "downloadFailed" ) ) ;
500+ } finally {
501+ setIsDownloading ( false ) ;
502+ }
503+ } ;
504+
473505 const handleGoBack = ( ) => {
474506 router . push ( "/session" ) ;
475507 } ;
@@ -504,6 +536,35 @@ export default function MessagesPage() {
504536 < Plus className = "h-4 w-4" />
505537 { t ( "createMessage" ) }
506538 </ Button >
539+ < DropdownMenu >
540+ < DropdownMenuTrigger asChild >
541+ < Button
542+ variant = "outline"
543+ disabled = { isLoadingMessages || isDownloading || allMessages . length === 0 }
544+ >
545+ { isDownloading ? (
546+ < Loader2 className = "h-4 w-4 animate-spin" />
547+ ) : (
548+ < Download className = "h-4 w-4" />
549+ ) }
550+ { t ( "download" ) }
551+ </ Button >
552+ </ DropdownMenuTrigger >
553+ < DropdownMenuContent align = "end" >
554+ < DropdownMenuItem onClick = { ( ) => handleDownload ( "openai" ) } >
555+ OpenAI
556+ </ DropdownMenuItem >
557+ < DropdownMenuItem onClick = { ( ) => handleDownload ( "anthropic" ) } >
558+ Anthropic
559+ </ DropdownMenuItem >
560+ < DropdownMenuItem onClick = { ( ) => handleDownload ( "gemini" ) } >
561+ Gemini
562+ </ DropdownMenuItem >
563+ < DropdownMenuItem onClick = { ( ) => handleDownload ( "acontext" ) } >
564+ Acontext
565+ </ DropdownMenuItem >
566+ </ DropdownMenuContent >
567+ </ DropdownMenu >
507568 < Button
508569 variant = "outline"
509570 onClick = { handleRefreshMessages }
0 commit comments