/* ┌──────────────────────────────────────────────────────────────────────────────┐ │ @author: Davidson Gomes │ │ @file: /app/documentation/components/StreamLabForm.tsx │ │ Developed by: Davidson Gomes │ │ Creation date: May 13, 2025 │ │ Contact: contato@evolution-api.com │ ├──────────────────────────────────────────────────────────────────────────────┤ │ @copyright © Evolution API 2025. All rights reserved. │ │ Licensed under the Apache License, Version 2.0 │ │ │ │ You may not use this file except in compliance with the License. │ │ You may obtain a copy of the License at │ │ │ │ http://www.apache.org/licenses/LICENSE-2.0 │ │ │ │ Unless required by applicable law or agreed to in writing, software │ │ distributed under the License is distributed on an "AS IS" BASIS, │ │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ │ See the License for the specific language governing permissions and │ │ limitations under the License. │ ├──────────────────────────────────────────────────────────────────────────────┤ │ @important │ │ For any future changes to the code in this file, it is recommended to │ │ include, together with the modification, the information of the developer │ │ who changed it and the date of modification. │ └──────────────────────────────────────────────────────────────────────────────┘ */ import { useRef, useState } from "react"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Separator } from "@/components/ui/separator"; import { Send, Paperclip, X, FileText, Image, File } from "lucide-react"; import { toast } from "@/hooks/use-toast"; interface AttachedFile { name: string; type: string; size: number; base64: string; } interface StreamLabFormProps { agentUrl: string; setAgentUrl: (url: string) => void; apiKey: string; setApiKey: (key: string) => void; message: string; setMessage: (message: string) => void; sessionId: string; setSessionId: (id: string) => void; taskId: string; setTaskId: (id: string) => void; callId: string; setCallId: (id: string) => void; sendStreamRequest: () => Promise; isStreaming: boolean; streamResponse: string; streamStatus: string; streamHistory: string[]; renderStatusIndicator: () => JSX.Element | null; renderTypingIndicator: () => JSX.Element | null; setFiles?: (files: AttachedFile[]) => void; authMethod: string; currentTaskId?: string | null; } export function StreamLabForm({ agentUrl, setAgentUrl, apiKey, setApiKey, message, setMessage, sessionId, setSessionId, taskId, setTaskId, callId, setCallId, sendStreamRequest, isStreaming, streamResponse, streamStatus, streamHistory, renderStatusIndicator, renderTypingIndicator, setFiles = () => {}, authMethod, currentTaskId }: StreamLabFormProps) { const [attachedFiles, setAttachedFiles] = useState([]); const fileInputRef = useRef(null); const clearAttachedFiles = () => { setAttachedFiles([]); }; const handleSendStreamRequest = async () => { await sendStreamRequest(); clearAttachedFiles(); }; const handleFileSelect = async (e: React.ChangeEvent) => { if (!e.target.files || e.target.files.length === 0) return; const maxFileSize = 5 * 1024 * 1024; // 5MB limit const newFiles = Array.from(e.target.files); if (attachedFiles.length + newFiles.length > 5) { toast({ title: "File limit exceeded", description: "You can only attach up to 5 files.", variant: "destructive" }); return; } const filesToAdd: AttachedFile[] = []; for (const file of newFiles) { if (file.size > maxFileSize) { toast({ title: "File too large", description: `The file ${file.name} exceeds the 5MB size limit.`, variant: "destructive" }); continue; } try { const base64 = await readFileAsBase64(file); filesToAdd.push({ name: file.name, type: file.type, size: file.size, base64: base64 }); } catch (error) { console.error("Failed to read file:", error); toast({ title: "Failed to read file", description: `Could not process ${file.name}.`, variant: "destructive" }); } } if (filesToAdd.length > 0) { const updatedFiles = [...attachedFiles, ...filesToAdd]; setAttachedFiles(updatedFiles); setFiles(updatedFiles); } // Reset file input if (fileInputRef.current) { fileInputRef.current.value = ""; } }; const readFileAsBase64 = (file: File): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const result = reader.result as string; const base64 = result.split(',')[1]; // Remove data URL prefix resolve(base64); }; reader.onerror = reject; reader.readAsDataURL(file); }); }; const removeFile = (index: number) => { const updatedFiles = attachedFiles.filter((_, i) => i !== index); setAttachedFiles(updatedFiles); setFiles(updatedFiles); }; const formatFileSize = (bytes: number): string => { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; }; const isImageFile = (type: string): boolean => { return type.startsWith('image/'); }; return (
{/* A2A Streaming Information */}
A2A Streaming Mode Method: message/stream
Authentication: {authMethod === "bearer" ? "Bearer Token" : "API Key"} header
{currentTaskId && (
Current Task ID: {currentTaskId}
)}
setAgentUrl(e.target.value)} placeholder="http://localhost:8000/api/v1/a2a/your-agent-id" className="bg-[#222] border-[#444] text-white" disabled={isStreaming} />
setApiKey(e.target.value)} placeholder={authMethod === "bearer" ? "Your Bearer token" : "Your API key"} className="bg-[#222] border-[#444] text-white" disabled={isStreaming} />