From 53422d385631f27823aefea2028a8f1e6fbd6064 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 18 Jul 2025 17:36:14 +0000 Subject: [PATCH] feat: Replace image-only attachment with general file attachment support - Add comprehensive file processing system with MIME type detection - Support multiple file categories (images, documents, code, data, archives, config) - Implement 10MB file size limit and intelligent text/binary handling - Replace camera icon with paperclip icon in chat interface - Add selectFiles message types and handlers - Update translations for attachFiles across all languages - Maintain backward compatibility with existing image functionality Resolves #5532 --- src/core/webview/webviewMessageHandler.ts | 10 + src/integrations/misc/process-files.ts | 246 ++++++++++++++++++ src/shared/ExtensionMessage.ts | 2 + src/shared/WebviewMessage.ts | 1 + .../src/components/chat/ChatTextArea.tsx | 12 +- webview-ui/src/components/chat/ChatView.tsx | 2 + webview-ui/src/i18n/locales/ca/chat.json | 1 + webview-ui/src/i18n/locales/de/chat.json | 1 + webview-ui/src/i18n/locales/en/chat.json | 1 + webview-ui/src/i18n/locales/es/chat.json | 1 + webview-ui/src/i18n/locales/fr/chat.json | 1 + webview-ui/src/i18n/locales/hi/chat.json | 1 + webview-ui/src/i18n/locales/id/chat.json | 1 + webview-ui/src/i18n/locales/it/chat.json | 1 + webview-ui/src/i18n/locales/ja/chat.json | 1 + webview-ui/src/i18n/locales/ko/chat.json | 1 + webview-ui/src/i18n/locales/nl/chat.json | 1 + webview-ui/src/i18n/locales/pl/chat.json | 1 + webview-ui/src/i18n/locales/pt-BR/chat.json | 1 + webview-ui/src/i18n/locales/ru/chat.json | 1 + webview-ui/src/i18n/locales/tr/chat.json | 1 + webview-ui/src/i18n/locales/vi/chat.json | 1 + webview-ui/src/i18n/locales/zh-CN/chat.json | 1 + webview-ui/src/i18n/locales/zh-TW/chat.json | 1 + 24 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 src/integrations/misc/process-files.ts diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 2efb2cbdff..16aabb5054 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -30,6 +30,7 @@ import { Terminal } from "../../integrations/terminal/Terminal" import { openFile } from "../../integrations/misc/open-file" import { openImage, saveImage } from "../../integrations/misc/image-handler" import { selectImages } from "../../integrations/misc/process-images" +import { selectFiles } from "../../integrations/misc/process-files" import { getTheme } from "../../integrations/theme/getTheme" import { discoverChromeHostUrl, tryChromeHostUrl } from "../../services/browser/browserDiscovery" import { searchWorkspaceFiles } from "../../services/search/file-search" @@ -381,6 +382,15 @@ export const webviewMessageHandler = async ( messageTs: message.messageTs, }) break + case "selectFiles": + const files = await selectFiles() + await provider.postMessageToWebview({ + type: "selectedFiles", + files, + context: message.context, + messageTs: message.messageTs, + }) + break case "exportCurrentTask": const currentTaskId = provider.getCurrentCline()?.taskId if (currentTaskId) { diff --git a/src/integrations/misc/process-files.ts b/src/integrations/misc/process-files.ts new file mode 100644 index 0000000000..5a7cc17517 --- /dev/null +++ b/src/integrations/misc/process-files.ts @@ -0,0 +1,246 @@ +import * as vscode from "vscode" +import fs from "fs/promises" +import * as path from "path" + +// File size limit: 10MB +const MAX_FILE_SIZE = 10 * 1024 * 1024 + +// Supported file types with their MIME types +const FILE_TYPE_CATEGORIES = { + images: ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"], + documents: ["pdf", "doc", "docx", "txt", "rtf", "odt", "md"], + code: ["js", "ts", "py", "java", "cpp", "c", "h", "hpp", "html", "css", "json", "xml", "yaml", "yml", "php", "rb", "go", "rs", "swift", "kt", "scala", "sh", "bat", "ps1"], + data: ["csv", "xls", "xlsx", "sql", "db", "sqlite"], + archives: ["zip", "rar", "tar", "gz", "7z"], + config: ["ini", "conf", "config", "env", "properties"], +} + +// Text file extensions that should be read as content +const TEXT_FILE_EXTENSIONS = [ + ...FILE_TYPE_CATEGORIES.code, + ...FILE_TYPE_CATEGORIES.documents.filter(ext => ["txt", "md"].includes(ext)), + ...FILE_TYPE_CATEGORIES.config, + ...FILE_TYPE_CATEGORIES.data.filter(ext => ["csv", "sql"].includes(ext)), +] + +export interface ProcessedFile { + name: string + path: string + size: number + type: string + category: string + content?: string // For text files + dataUrl?: string // For images and binary files + error?: string +} + +export async function selectFiles(): Promise { + const options: vscode.OpenDialogOptions = { + canSelectMany: true, + openLabel: "Select", + filters: { + "All Files": ["*"], + "Images": FILE_TYPE_CATEGORIES.images, + "Documents": FILE_TYPE_CATEGORIES.documents, + "Code Files": FILE_TYPE_CATEGORIES.code, + "Data Files": FILE_TYPE_CATEGORIES.data, + "Archives": FILE_TYPE_CATEGORIES.archives, + "Config Files": FILE_TYPE_CATEGORIES.config, + }, + } + + const fileUris = await vscode.window.showOpenDialog(options) + + if (!fileUris || fileUris.length === 0) { + return [] + } + + return await Promise.all( + fileUris.map(async (uri: vscode.Uri) => { + try { + return await processFile(uri.fsPath) + } catch (error) { + const fileName = path.basename(uri.fsPath) + return { + name: fileName, + path: uri.fsPath, + size: 0, + type: "unknown", + category: "unknown", + error: error instanceof Error ? error.message : String(error), + } + } + }), + ) +} + +export async function processFile(filePath: string): Promise { + const fileName = path.basename(filePath) + const fileExt = path.extname(filePath).toLowerCase().slice(1) + + // Check file size + const stats = await fs.stat(filePath) + if (stats.size > MAX_FILE_SIZE) { + throw new Error(`File size (${formatFileSize(stats.size)}) exceeds the 10MB limit`) + } + + const mimeType = getMimeType(filePath) + const category = getFileCategory(fileExt) + + const processedFile: ProcessedFile = { + name: fileName, + path: filePath, + size: stats.size, + type: mimeType, + category, + } + + // Handle different file types + if (category === "images") { + // Process images as data URLs (existing behavior) + const buffer = await fs.readFile(filePath) + const base64 = buffer.toString("base64") + processedFile.dataUrl = `data:${mimeType};base64,${base64}` + } else if (isTextFile(fileExt)) { + // Read text files as content + try { + processedFile.content = await fs.readFile(filePath, "utf-8") + } catch (error) { + // If UTF-8 reading fails, treat as binary + const buffer = await fs.readFile(filePath) + const base64 = buffer.toString("base64") + processedFile.dataUrl = `data:${mimeType};base64,${base64}` + } + } else { + // Handle binary files as base64 + const buffer = await fs.readFile(filePath) + const base64 = buffer.toString("base64") + processedFile.dataUrl = `data:${mimeType};base64,${base64}` + } + + return processedFile +} + +// Backward compatibility function for existing image functionality +export async function selectImages(): Promise { + const options: vscode.OpenDialogOptions = { + canSelectMany: true, + openLabel: "Select", + filters: { + Images: FILE_TYPE_CATEGORIES.images, + }, + } + + const fileUris = await vscode.window.showOpenDialog(options) + + if (!fileUris || fileUris.length === 0) { + return [] + } + + return await Promise.all( + fileUris.map(async (uri: vscode.Uri) => { + const filePath = uri.fsPath + const buffer = await fs.readFile(filePath) + const base64 = buffer.toString("base64") + const mimeType = getMimeType(filePath) + return `data:${mimeType};base64,${base64}` + }), + ) +} + +function getMimeType(filePath: string): string { + const ext = path.extname(filePath).toLowerCase() + + // Image types + switch (ext) { + case ".png": return "image/png" + case ".jpeg": + case ".jpg": return "image/jpeg" + case ".gif": return "image/gif" + case ".bmp": return "image/bmp" + case ".webp": return "image/webp" + case ".svg": return "image/svg+xml" + + // Document types + case ".pdf": return "application/pdf" + case ".doc": return "application/msword" + case ".docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + case ".txt": return "text/plain" + case ".rtf": return "application/rtf" + case ".odt": return "application/vnd.oasis.opendocument.text" + case ".md": return "text/markdown" + + // Code types + case ".js": return "text/javascript" + case ".ts": return "text/typescript" + case ".py": return "text/x-python" + case ".java": return "text/x-java-source" + case ".cpp": + case ".c": return "text/x-c" + case ".h": + case ".hpp": return "text/x-c" + case ".html": return "text/html" + case ".css": return "text/css" + case ".json": return "application/json" + case ".xml": return "application/xml" + case ".yaml": + case ".yml": return "application/x-yaml" + case ".php": return "text/x-php" + case ".rb": return "text/x-ruby" + case ".go": return "text/x-go" + case ".rs": return "text/x-rust" + case ".swift": return "text/x-swift" + case ".kt": return "text/x-kotlin" + case ".scala": return "text/x-scala" + case ".sh": return "text/x-shellscript" + case ".bat": return "text/x-msdos-batch" + case ".ps1": return "text/x-powershell" + + // Data types + case ".csv": return "text/csv" + case ".xls": return "application/vnd.ms-excel" + case ".xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + case ".sql": return "text/x-sql" + case ".db": + case ".sqlite": return "application/x-sqlite3" + + // Archive types + case ".zip": return "application/zip" + case ".rar": return "application/x-rar-compressed" + case ".tar": return "application/x-tar" + case ".gz": return "application/gzip" + case ".7z": return "application/x-7z-compressed" + + // Config types + case ".ini": return "text/plain" + case ".conf": + case ".config": return "text/plain" + case ".env": return "text/plain" + case ".properties": return "text/plain" + + default: return "application/octet-stream" + } +} + +function getFileCategory(extension: string): string { + for (const [category, extensions] of Object.entries(FILE_TYPE_CATEGORIES)) { + if (extensions.includes(extension)) { + return category + } + } + return "other" +} + +function isTextFile(extension: string): boolean { + return TEXT_FILE_EXTENSIONS.includes(extension) +} + +function formatFileSize(bytes: number): string { + if (bytes === 0) return "0 Bytes" + + const k = 1024 + const sizes = ["Bytes", "KB", "MB", "GB"] + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i] +} \ No newline at end of file diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 98f3aa7d29..bdddecd435 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -54,6 +54,7 @@ export interface ExtensionMessage { | "action" | "state" | "selectedImages" + | "selectedFiles" | "theme" | "workspaceUpdated" | "invoke" @@ -123,6 +124,7 @@ export interface ExtensionMessage { invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage" state?: ExtensionState images?: string[] + files?: any[] // ProcessedFile array from process-files.ts filePaths?: string[] openedTabs?: Array<{ label: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 5d6ec0f41c..a2a55c0e4d 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -53,6 +53,7 @@ export interface WebviewMessage { | "clearTask" | "didShowAnnouncement" | "selectImages" + | "selectFiles" | "exportCurrentTask" | "shareCurrentTask" | "showTaskWithId" diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 6c541353eb..57149fc728 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -25,7 +25,7 @@ import Thumbnails from "../common/Thumbnails" import ModeSelector from "./ModeSelector" import { MAX_IMAGES_PER_MESSAGE } from "./ChatView" import ContextMenu from "./ContextMenu" -import { VolumeX, Pin, Check, Image, WandSparkles, SendHorizontal } from "lucide-react" +import { VolumeX, Pin, Check, Image, WandSparkles, SendHorizontal, Paperclip } from "lucide-react" import { IndexingStatusBadge } from "./IndexingStatusBadge" import { cn } from "@/lib/utils" import { usePromptHistory } from "./hooks/usePromptHistory" @@ -41,6 +41,7 @@ interface ChatTextAreaProps { setSelectedImages: React.Dispatch> onSend: () => void onSelectImages: () => void + onSelectFiles?: () => void shouldDisableImages: boolean onHeightChange?: (height: number) => void mode: Mode @@ -63,6 +64,7 @@ const ChatTextArea = forwardRef( setSelectedImages, onSend, onSelectImages, + onSelectFiles, shouldDisableImages, onHeightChange, mode, @@ -984,11 +986,11 @@ const ChatTextArea = forwardRef( )} - + diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index f804f7b61e..ecdada8cef 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -701,6 +701,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction vscode.postMessage({ type: "selectImages" }), []) + const selectFiles = useCallback(() => vscode.postMessage({ type: "selectFiles" }), []) const shouldDisableImages = !model?.supportsImages || sendingDisabled || selectedImages.length >= MAX_IMAGES_PER_MESSAGE @@ -1858,6 +1859,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction handleSendMessage(inputValue, selectedImages)} onSelectImages={selectImages} + onSelectFiles={selectFiles} shouldDisableImages={shouldDisableImages} onHeightChange={() => { if (isAtBottom) { diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 10f7ad3dba..f984ef95dc 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Seleccioneu la configuració de l'API", "enhancePrompt": "Millora la sol·licitud amb context addicional", "addImages": "Afegeix imatges al missatge", + "attachFiles": "Attach files to message", "sendMessage": "Envia el missatge", "stopTts": "Atura la síntesi de veu", "typeMessage": "Escriu un missatge...", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 95620eefdf..68ceb9f221 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "API-Konfiguration auswählen", "enhancePrompt": "Prompt mit zusätzlichem Kontext verbessern", "addImages": "Bilder zur Nachricht hinzufügen", + "attachFiles": "Attach files to message", "sendMessage": "Nachricht senden", "stopTts": "Text-in-Sprache beenden", "typeMessage": "Nachricht eingeben...", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index aed3bcfdc5..a17cbec406 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -122,6 +122,7 @@ }, "enhancePromptDescription": "The 'Enhance Prompt' button helps improve your prompt by providing additional context, clarification, or rephrasing. Try typing a prompt in here and clicking the button again to see how it works.", "addImages": "Add images to message", + "attachFiles": "Attach files to message", "sendMessage": "Send message", "stopTts": "Stop text-to-speech", "typeMessage": "Type a message...", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index a091aed1a6..e358497094 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Seleccionar configuración de API", "enhancePrompt": "Mejorar el mensaje con contexto adicional", "addImages": "Agregar imágenes al mensaje", + "attachFiles": "Attach files to message", "sendMessage": "Enviar mensaje", "stopTts": "Detener texto a voz", "typeMessage": "Escribe un mensaje...", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 59b22149fb..7ca7557ed4 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Sélectionner la configuration de l'API", "enhancePrompt": "Améliorer la requête avec un contexte supplémentaire", "addImages": "Ajouter des images au message", + "attachFiles": "Attach files to message", "sendMessage": "Envoyer le message", "stopTts": "Arrêter la synthèse vocale", "typeMessage": "Écrivez un message...", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 08c7cc030a..5c3022eb59 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "एपीआई कॉन्फ़िगरेशन का चयन करें", "enhancePrompt": "अतिरिक्त संदर्भ के साथ प्रॉम्प्ट बढ़ाएँ", "addImages": "संदेश में चित्र जोड़ें", + "attachFiles": "Attach files to message", "sendMessage": "संदेश भेजें", "stopTts": "टेक्स्ट-टू-स्पीच बंद करें", "typeMessage": "एक संदेश लिखें...", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index e242ebcf6c..577773052f 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -125,6 +125,7 @@ "description": "Persona khusus yang menyesuaikan perilaku Roo." }, "addImages": "Tambahkan gambar ke pesan", + "attachFiles": "Attach files to message", "sendMessage": "Kirim pesan", "stopTts": "Hentikan text-to-speech", "typeMessage": "Ketik pesan...", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 9f2d1b523a..cdbbde0cb1 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Seleziona la configurazione API", "enhancePrompt": "Migliora prompt con contesto aggiuntivo", "addImages": "Aggiungi immagini al messaggio", + "attachFiles": "Attach files to message", "sendMessage": "Invia messaggio", "stopTts": "Interrompi sintesi vocale", "typeMessage": "Scrivi un messaggio...", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 986b1d48bf..9abf8e0f37 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "API構成を選択", "enhancePrompt": "追加コンテキストでプロンプトを強化", "addImages": "メッセージに画像を追加", + "attachFiles": "Attach files to message", "sendMessage": "メッセージを送信", "stopTts": "テキスト読み上げを停止", "typeMessage": "メッセージを入力...", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 295f11584c..009be4bb48 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "API 구성 선택", "enhancePrompt": "추가 컨텍스트로 프롬프트 향상", "addImages": "메시지에 이미지 추가", + "attachFiles": "Attach files to message", "sendMessage": "메시지 보내기", "stopTts": "텍스트 음성 변환 중지", "typeMessage": "메시지 입력...", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 9d8bd6b202..4555aa2490 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -111,6 +111,7 @@ "description": "Gespecialiseerde persona's die het gedrag van Roo aanpassen." }, "addImages": "Afbeeldingen toevoegen aan bericht", + "attachFiles": "Attach files to message", "sendMessage": "Bericht verzenden", "stopTts": "Stop tekst-naar-spraak", "typeMessage": "Typ een bericht...", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index a5460909fb..8a8534fcff 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Wybierz konfigurację API", "enhancePrompt": "Ulepsz podpowiedź dodatkowym kontekstem", "addImages": "Dodaj obrazy do wiadomości", + "attachFiles": "Attach files to message", "sendMessage": "Wyślij wiadomość", "stopTts": "Zatrzymaj syntezę mowy", "typeMessage": "Wpisz wiadomość...", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 96cb0c7660..22add37bf1 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Selecionar configuração da API", "enhancePrompt": "Aprimorar prompt com contexto adicional", "addImages": "Adicionar imagens à mensagem", + "attachFiles": "Attach files to message", "sendMessage": "Enviar mensagem", "stopTts": "Parar conversão de texto em fala", "typeMessage": "Digite uma mensagem...", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 90387a620c..3ef89dbc55 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -111,6 +111,7 @@ "description": "Специализированные персоны, которые настраивают поведение Roo." }, "addImages": "Добавить изображения к сообщению", + "attachFiles": "Attach files to message", "sendMessage": "Отправить сообщение", "stopTts": "Остановить синтез речи", "typeMessage": "Введите сообщение...", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 2188756f7f..cd53be243e 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "API yapılandırmasını seçin", "enhancePrompt": "Ek bağlamla istemi geliştir", "addImages": "Mesaja resim ekle", + "attachFiles": "Attach files to message", "sendMessage": "Mesaj gönder", "stopTts": "Metin okumayı durdur", "typeMessage": "Bir mesaj yazın...", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index cdab5bf1e5..6503bf66a2 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "Chọn cấu hình API", "enhancePrompt": "Nâng cao yêu cầu với ngữ cảnh bổ sung", "addImages": "Thêm hình ảnh vào tin nhắn", + "attachFiles": "Attach files to message", "sendMessage": "Gửi tin nhắn", "stopTts": "Dừng chuyển văn bản thành giọng nói", "typeMessage": "Nhập tin nhắn...", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 58945ddf12..f87be73554 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "选择 API 配置", "enhancePrompt": "增强提示词", "addImages": "添加图片到消息", + "attachFiles": "Attach files to message", "sendMessage": "发送消息", "stopTts": "停止文本转语音", "typeMessage": "输入消息...", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index fab99e69ae..c56e5c82a0 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -104,6 +104,7 @@ "selectApiConfig": "選取 API 設定", "enhancePrompt": "使用額外內容增強提示", "addImages": "新增圖片到訊息中", + "attachFiles": "Attach files to message", "sendMessage": "傳送訊息", "stopTts": "停止文字轉語音", "typeMessage": "輸入訊息...",