From f0d5636ce392917331bd8e3c81d3ec1fa94770b5 Mon Sep 17 00:00:00 2001 From: zerob13 Date: Wed, 3 Dec 2025 23:16:43 +0800 Subject: [PATCH 1/7] feat: Hebrew (he-IL) Translation --- src/main/presenter/configPresenter/index.ts | 3 +- .../settings/components/DisplaySettings.vue | 3 +- src/renderer/src/i18n/he-IL/about.json | 19 + src/renderer/src/i18n/he-IL/artifacts.json | 52 + src/renderer/src/i18n/he-IL/chat.json | 97 ++ src/renderer/src/i18n/he-IL/common.json | 82 ++ src/renderer/src/i18n/he-IL/components.json | 41 + src/renderer/src/i18n/he-IL/contextMenu.json | 17 + src/renderer/src/i18n/he-IL/dialog.json | 44 + src/renderer/src/i18n/he-IL/index.ts | 58 ++ src/renderer/src/i18n/he-IL/mcp.json | 316 ++++++ src/renderer/src/i18n/he-IL/model.json | 30 + src/renderer/src/i18n/he-IL/newThread.json | 4 + src/renderer/src/i18n/he-IL/plan.json | 4 + .../src/i18n/he-IL/promptSetting.json | 95 ++ src/renderer/src/i18n/he-IL/routes.json | 17 + src/renderer/src/i18n/he-IL/settings.json | 964 ++++++++++++++++++ src/renderer/src/i18n/he-IL/sync.json | 17 + src/renderer/src/i18n/he-IL/thread.json | 46 + src/renderer/src/i18n/he-IL/toolCall.json | 19 + src/renderer/src/i18n/he-IL/traceDialog.json | 17 + src/renderer/src/i18n/he-IL/update.json | 16 + src/renderer/src/i18n/he-IL/welcome.json | 37 + src/renderer/src/i18n/index.ts | 5 +- src/renderer/src/stores/language.ts | 2 +- 25 files changed, 2001 insertions(+), 4 deletions(-) create mode 100644 src/renderer/src/i18n/he-IL/about.json create mode 100644 src/renderer/src/i18n/he-IL/artifacts.json create mode 100644 src/renderer/src/i18n/he-IL/chat.json create mode 100644 src/renderer/src/i18n/he-IL/common.json create mode 100644 src/renderer/src/i18n/he-IL/components.json create mode 100644 src/renderer/src/i18n/he-IL/contextMenu.json create mode 100644 src/renderer/src/i18n/he-IL/dialog.json create mode 100644 src/renderer/src/i18n/he-IL/index.ts create mode 100644 src/renderer/src/i18n/he-IL/mcp.json create mode 100644 src/renderer/src/i18n/he-IL/model.json create mode 100644 src/renderer/src/i18n/he-IL/newThread.json create mode 100644 src/renderer/src/i18n/he-IL/plan.json create mode 100644 src/renderer/src/i18n/he-IL/promptSetting.json create mode 100644 src/renderer/src/i18n/he-IL/routes.json create mode 100644 src/renderer/src/i18n/he-IL/settings.json create mode 100644 src/renderer/src/i18n/he-IL/sync.json create mode 100644 src/renderer/src/i18n/he-IL/thread.json create mode 100644 src/renderer/src/i18n/he-IL/toolCall.json create mode 100644 src/renderer/src/i18n/he-IL/traceDialog.json create mode 100644 src/renderer/src/i18n/he-IL/update.json create mode 100644 src/renderer/src/i18n/he-IL/welcome.json diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index c98b549fa..5c87742cd 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -686,7 +686,8 @@ export class ConfigPresenter implements IConfigPresenter { 'fr-FR', 'fa-IR', 'pt-BR', - 'da-DK' + 'da-DK', + 'he-IL' ] // Exact match diff --git a/src/renderer/settings/components/DisplaySettings.vue b/src/renderer/settings/components/DisplaySettings.vue index 6b6008092..2f84dfd52 100644 --- a/src/renderer/settings/components/DisplaySettings.vue +++ b/src/renderer/settings/components/DisplaySettings.vue @@ -340,7 +340,8 @@ const languageOptions = [ { value: 'fr-FR', label: 'Français' }, { value: 'fa-IR', label: 'فارسی (ایران)' }, { value: 'pt-BR', label: 'Português (Brasil)' }, - { value: 'da-DK', label: 'Dansk' } + { value: 'da-DK', label: 'Dansk' }, + { value: 'he-IL', label: 'עברית (ישראל)' } ] watch(selectedLanguage, async (newValue) => { diff --git a/src/renderer/src/i18n/he-IL/about.json b/src/renderer/src/i18n/he-IL/about.json new file mode 100644 index 000000000..03e17c5bb --- /dev/null +++ b/src/renderer/src/i18n/he-IL/about.json @@ -0,0 +1,19 @@ +{ + "title": "DeepChat", + "description": "DeepChat הוא לקוח AI חוצה-פלטפורמות, המוקדש להנגשת הבינה המלאכותית ליותר אנשים.", + "website": "בקר באתר שלנו", + "deviceInfo": { + "title": "מידע על המכשיר", + "platform": "פלטפורמה", + "arch": "ארכיטקטורה", + "cpuModel": "דגם מעבד", + "totalMemory": "זיכרון כולל", + "osVersion": "גרסת מערכת" + }, + "disclaimerButton": "כתב ויתור", + "disclaimerTitle": "הצהרת תנאי שימוש", + "checkUpdateButton": "בדוק עדכונים", + "updateChannel": "ערוץ עדכון", + "stableChannel": "יציב (Stable)", + "canaryChannel": "קנרית (Canary)" +} diff --git a/src/renderer/src/i18n/he-IL/artifacts.json b/src/renderer/src/i18n/he-IL/artifacts.json new file mode 100644 index 000000000..28dc8fb98 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/artifacts.json @@ -0,0 +1,52 @@ +{ + "clickToOpen": "לחץ לפתיחה", + "codeSnippet": "קטע קוד", + "function": "פונקציה", + "class": "מחלקה (Class)", + "reactComponent": "רכיב React", + "moduleImport": "ייבוא מודול", + "variableDefinition": "הגדרת משתנה {name}", + "markdownDocument": "מסמך Markdown", + "htmlDocument": "מסמך HTML", + "svgImage": "תמונת SVG", + "flowchart": "תרשים זרימה", + "sequenceDiagram": "דיאגרמת רצף", + "classDiagram": "דיאגרמת מחלקות", + "stateDiagram": "דיאגרמת מצבים", + "erDiagram": "דיאגרמת ER", + "ganttChart": "תרשים גאנט", + "pieChart": "תרשים עוגה", + "mermaidDiagram": "דיאגרמת Mermaid", + "flowchartOf": "תרשים זרימה של {name}", + "sequenceDiagramBetween": "דיאגרמת רצף בין {participants}", + "classDiagramOf": "דיאגרמת מחלקות של {name}", + "stateDiagramOf": "דיאגרמת מצבים של {name}", + "erDiagramOf": "דיאגרמת ER של {name}", + "pieChartOf": "תרשים עוגה של {name}", + "unknownDocument": "מסמך לא ידוע", + "preview": "תצוגה מקדימה", + "code": "קוד", + "export": "ייצוא", + "htmlPreviewTitle": "תצוגה מקדימה של HTML", + "svgPreviewTitle": "תצוגה מקדימה של SVG", + "copy": "העתק", + "copySuccess": "הועתק", + "copySuccessDesc": "התוכן הועתק ללוח", + "copyFailed": "העתקה נכשלה", + "copyFailedDesc": "נכשל בהעתקת התוכן ללוח", + "copyAsImage": "העתק כתמונה", + "copyImageSuccessDesc": "התמונה הועתקה ללוח", + "copyImageFailedDesc": "לא ניתן היה להעתיק את התמונה ללוח.", + "desktop": "שולחן עבודה", + "tablet": "טאבלט", + "mobile": "נייד", + "responsive": "רספונסיבי", + "width": "רוחב", + "height": "גובה", + "sanitizingSvg": "מנקה תוכן SVG...", + "svgSanitizationFailed": "תוכן ה-SVG נכשל באימות אבטחה", + "noSvgContent": "אין תוכן SVG זמין", + "mermaid": { + "renderError": "עיבוד נכשל: {message}" + } +} diff --git a/src/renderer/src/i18n/he-IL/chat.json b/src/renderer/src/i18n/he-IL/chat.json new file mode 100644 index 000000000..2a4cbd650 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/chat.json @@ -0,0 +1,97 @@ +{ + "input": { + "placeholder": "שאל משהו? ניתן לצטט כלים, קבצים ומשאבים באמצעות {'@'}...", + "fileArea": "אזור קבצים", + "inputArea": "אזור קלט", + "functionSwitch": "מתג פונקציות", + "fileSelect": "בחר קובץ", + "pasteFiles": "הדבק קבצים מהלוח", + "dropFiles": "גרור קבצים לכאן", + "promptFilesAdded": "קבצי הנחיה (Prompt) נוספו", + "promptFilesAddedDesc": "נוספו בהצלחה {count} קבצים", + "promptFilesError": "שגיאה בעיבוד קבצים", + "promptFilesErrorDesc": "{count} קבצים נכשלו בעיבוד", + "historyPlaceholder": "(לחץ Tab להשלמה אוטומטית)", + "rateLimitQueue": "תור {count}", + "rateLimitWait": "המתן {seconds} שניות", + "rateLimitQueueTooltip": "{count} בקשות בתור, מרווח של {interval} שניות", + "rateLimitReadyTooltip": "מוכן לשליחה, מרווח של {interval} שניות", + "rateLimitWaitingTooltip": "המתן {seconds} שניות נוספות, מרווח של {interval} שניות", + "acpWorkdir": "תיקיית עבודה ACP", + "acpWorkdirTooltip": "הגדר תיקיית עבודה ל-ACP", + "acpWorkdirSelect": "בחר תיקייה שתשמש כתיקיית העבודה של ACP", + "acpWorkdirCurrent": "תיקיית עבודה נוכחית: {path}", + "acpMode": "דֶגֶם", + "acpModeAcceptEdits": "קבל באופן אוטומטי עריכות", + "acpModeBypassPermissions": "דילוג על הרשאות", + "acpModeDefault": "תמיד לשאול", + "acpModePlan": "מצב תכנון", + "acpModeSwitched": "עבר ל-{mode}", + "acpModeTooltip": "מצב נוכחי: {mode}" + }, + "features": { + "webSearch": "חיפוש אינטרנט", + "thoughtForSeconds": "חשב במשך {seconds} שניות", + "thoughtForSecondsLoading": "חושב במשך {seconds} שניות...", + "artifactThinking": "חשיבת תוצר (Artifact Thinking)", + "modeChanged": "המצב הועבר ל: {mode}" + }, + "search": { + "results": "נמצאו {0} דפי אינטרנט", + "searching": "מחפש...", + "title": "תוצאות חיפוש", + "description": "נמצאו {0} תוצאות קשורות", + "optimizing": "ממטב את שאילתת החיפוש...", + "reading": "מחפש וקורא דפי אינטרנט...", + "error": "החיפוש נכשל" + }, + "messages": { + "thinking": "חושב...", + "rateLimitWaiting": "הגעת למגבלת הקצב, ממתין בתור...", + "rateLimitTitle": "מגבלת קצב פעילה", + "rateLimitQueue": "מיקום בתור", + "rateLimitEstimated": "המתנה משוערת", + "rateLimitQuickSettings": "התאם מגבלה", + "rateLimitSwitchProvider": "החלף ספק", + "rateLimitImmediately": "עכשיו", + "rateLimitSeconds": "שניות", + "rateLimitMinutes": "דקות" + }, + "rateLimit": { + "queueTooltip": "{count} בקשות בתור, מרווח של {interval} שניות", + "readyTooltip": "מוכן לשליחה, מרווח של {interval} שניות", + "waitingTooltip": "המתן {seconds} שניות נוספות, מרווח של {interval} שניות" + }, + "notify": { + "generationComplete": "היצירה הושלמה", + "generationError": "היצירה נכשלה" + }, + "navigation": { + "title": "ניווט בהודעות", + "searchPlaceholder": "חפש הודעות...", + "noResults": "לא נמצאו הודעות תואמות", + "noMessages": "אין הודעות עדיין", + "totalMessages": "{count} הודעות סה\"כ", + "searchResults": "נמצאו {count} תוצאות בתוך {total} הודעות", + "userMessage": "הודעת משתמש", + "assistantMessage": "תשובת עוזר", + "unknownMessage": "הודעה לא ידועה" + }, + "mcpUi": { + "title": "ממשק MCP", + "badge": "UI", + "expand": "הרחב", + "collapse": "צמצם" + }, + "toolCall": { + "title": "קריאה לכלי", + "calling": "קריאה לכלי בתהליך", + "response": "תגובת כלי", + "end": "קריאה לכלי הסתיימה", + "error": "שגיאה בקריאה לכלי", + "clickToView": "לחץ לצפייה בפרטים", + "functionName": "פונקציה", + "params": "פרמטרים", + "responseData": "נתוני תגובה" + } +} diff --git a/src/renderer/src/i18n/he-IL/common.json b/src/renderer/src/i18n/he-IL/common.json new file mode 100644 index 000000000..87684afe2 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/common.json @@ -0,0 +1,82 @@ +{ + "enabled": "מופעל", + "disabled": "מושבת", + "loading": "טוען...", + "copySuccess": "הועתק בהצלחה", + "copySuccessDesc": "התוכן הועתק ללוח", + "copyImageSuccess": "הועתק בהצלחה", + "copyImageSuccessDesc": "התמונה הועתקה ללוח", + "copyFailed": "העתקה נכשלה", + "copyFailedDesc": "נכשל בהעתקת התוכן ללוח", + "copyCode": "העתק קוד", + "copy": "העתק", + "copied": "הועתק", + "paste": "הדבק", + "export": "ייצוא", + "newChat": "צ'אט חדש", + "newTopic": "נושא חדש", + "cancel": "ביטול", + "confirm": "אישור", + "close": "סגור", + "error": { + "requestFailed": "הבקשה נכשלה...", + "createChatFailed": "יצירת הצ'אט נכשלה", + "selectChatFailed": "בחירת הצ'אט נכשלה", + "renameChatFailed": "שינוי שם הצ'אט נכשל", + "deleteChatFailed": "מחיקת הצ'אט נכשלה", + "cleanMessagesFailed": "ניקוי ההודעות נכשל", + "userCanceledGeneration": "המשתמש ביטל את היצירה", + "sessionInterrupted": "ההפעלה הופסקה באופן בלתי צפוי, היצירה לא הושלמה", + "noModelResponse": "המודל לא החזיר תוכן, ייתכן שעבר הזמן הקצוב", + "invalidJson": "פורמט JSON לא חוקי", + "maximumToolCallsReached": "הגעת למספר המקסימלי של קריאות לכלים", + "causeOfError": "סיבות אפשריות לשגיאה:", + "error400": "בקשה שגויה, ייתכן שיש בעיה בפרמטרים או בתאימות", + "error401": "אימות נכשל, ייתכן שמפתח ה-API או הדומיין שגויים", + "error403": "הגישה למודל נאסרה, ייתכן שהיתרה אינה מספקת או שאין הרשאה", + "error404": "כתובת ה-URL המבוקשת לא נמצאה, ייתכן שהדומיין או שם המודל שגויים", + "error429": "יותר מדי בקשות, ייתכן שהשירות הגביל את הקצב (Rate Limit)", + "error500": "שגיאת שרת, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error502": "שגיאת Gateway, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error503": "השירות אינו זמין, ייתכן שהשירות אינו יציב, אנא נסה שוב מאוחר יותר", + "error504": "הבקשה הסתיימה (Timeout), ייתכן שהשירות אינו יציב או שיש בעיות רשת, אנא בדוק את הגדרות הפרוקסי ונסה שוב", + "operationFailed": "הפעולה נכשלה" + }, + "resetDataConfirmTitle": "לאפס את כל הנתונים?", + "resetDataConfirmDescription": "פעולה זו תאפס את כל הנתונים שלך להגדרות ברירת המחדל. לא ניתן לבטל פעולה זו.", + "proxyMode": "מצב פרוקסי", + "proxyModeSelect": "בחר מצב פרוקסי", + "proxyModeSystem": "פרוקסי מערכת", + "proxyModeNone": "ללא פרוקסי", + "proxyModeCustom": "פרוקסי מותאם אישית", + "customProxyUrl": "כתובת URL לפרוקסי מותאם", + "customProxyUrlPlaceholder": "דוגמה: http://127.0.0.1:7890", + "invalidProxyUrl": "כתובת פרוקסי לא חוקית, אנא הזן כתובת http/https תקינה", + "disclaimer": "כתב ויתור", + "resetData": "אפס נתונים", + "searchAssistantModel": "מודל עוזר", + "searchEngine": "מנוע חיפוש", + "searchEngineSelect": "בחר מנוע חיפוש", + "searchPreview": "תצוגה מקדימה של חיפוש", + "language": "שפה", + "languageSelect": "בחר שפה", + "selectModel": "בחר מודל", + "title": "הגדרות כלליות", + "languageSystem": "עקוב אחר המערכת", + "watermarkTip": "נוצר על ידי AI", + "collapse": "צמצם", + "expand": "הרחב", + "image": "תמונה", + "add": "הוסף", + "reset": "אפס", + "format": "פורמט", + "edit": "ערוך", + "delete": "מחק", + "save": "שמור", + "clear": "נקה", + "saved": "נשמר", + "newTab": "כרטיסייה חדשה", + "unknownError": "שגיאה לא ידועה", + "testing": "בדיקה בתהליך", + "saving": "שומר" +} diff --git a/src/renderer/src/i18n/he-IL/components.json b/src/renderer/src/i18n/he-IL/components.json new file mode 100644 index 000000000..ba813f421 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/components.json @@ -0,0 +1,41 @@ +{ + "emojiPicker": { + "search": "חפש אימוג'י", + "smileys": "סמיילים ורגשות", + "people": "אנשים וגוף", + "animals": "בעלי חיים וטבע", + "food": "אוכל ושתייה", + "travel": "נסיעות ומקומות", + "activities": "פעילויות", + "objects": "חפצים", + "symbols": "סמלים", + "flags": "דגלים" + }, + "messageBlockAction": { + "continue": "המשך", + "continued": "המשך" + }, + "messageBlockPermissionRequest": { + "title": "נדרשת הרשאה", + "allow": "אפשר", + "deny": "דחה", + "rememberChoice": "זכור בחירה זו", + "granted": "הרשאה ניתנה", + "denied": "הרשאה נדחתה", + "type": { + "read": "גישת קריאה", + "write": "גישת כתיבה", + "all": "גישה מלאה" + }, + "description": { + "read": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות קריאה?", + "write": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות כתיבה?", + "all": "האם לאפשר ל-'{toolName}' מ-'{serverName}' לבצע פעולות קריאה וכתיבה?" + } + }, + "promptParamsDialog": { + "title": "הגדרות פרמטרים עבור {name}", + "description": "אנא מלא את הפרמטרים למטה. שדות המסומנים ב-* הם שדות חובה.", + "required": "שדה זה הוא חובה." + } +} diff --git a/src/renderer/src/i18n/he-IL/contextMenu.json b/src/renderer/src/i18n/he-IL/contextMenu.json new file mode 100644 index 000000000..151bccdbc --- /dev/null +++ b/src/renderer/src/i18n/he-IL/contextMenu.json @@ -0,0 +1,17 @@ +{ + "translate": { + "title": "תרגם", + "original": "מקור", + "translated": "תרגום", + "error": "התרגום נכשל" + }, + "askAI": { + "title": "שאל את ה-AI", + "question": "שאלה", + "answer": "תשובה", + "error": "תגובת ה-AI נכשלה" + }, + "copy": "העתק", + "paste": "הדבק", + "cut": "גזור" +} diff --git a/src/renderer/src/i18n/he-IL/dialog.json b/src/renderer/src/i18n/he-IL/dialog.json new file mode 100644 index 000000000..5e6a87302 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/dialog.json @@ -0,0 +1,44 @@ +{ + "cancel": "ביטול", + "confirm": "אישור", + "close": "סגור", + "ok": "אישור", + "delete": { + "title": "האם אתה בטוח שברצונך למחוק שיחה זו?", + "description": "לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "rename": { + "title": "שנה שם שיחה", + "description": "אנא הזן שם חדש לשיחה." + }, + "cleanMessages": { + "title": "נקה את כל ההודעות", + "description": "פעולה זו תמחק את כל ההודעות והקבצים בשיחה זו. האם אתה בטוח שברצונך להמשיך?", + "confirm": "נקה" + }, + "fork": { + "title": "צור ענף (Branch)", + "description": "פעולה זו תעתיק את כל ההודעות מההודעה הראשונה ועד להודעה הנוכחית לתוך שיחה חדשה בה תוכל להמשיך את הדו-שיח.", + "confirm": "צור ענף", + "tag": "ענף" + }, + "error": { + "title": "שגיאה" + }, + "mutualExclusive": { + "title": { + "reasoning": "אשר הפעלת חשיבה (Reasoning)", + "functionCall": "אשר הפעלת קריאה לפונקציות (Function Calling)" + }, + "message": { + "reasoning": "הפעלת חשיבה תשבית אוטומטית את הקריאה לפונקציות. זוהי מגבלה של מודלי DeepSeek-V3.1, ולא ניתן להשתמש בשתי התכונות בו-זמנית. להמשיך?", + "functionCall": "הפעלת קריאה לפונקציות תשבית אוטומטית את החשיבה. זוהי מגבלה של מודלי DeepSeek-V3.1, ולא ניתן להשתמש בשתי התכונות בו-זמנית. להמשיך?" + }, + "warningText": { + "reasoning": "שים לב: הפעלת חשיבה תשבית אוטומטית את הקריאה לפונקציות, שכן זו דרישה של מודלי DeepSeek-V3.1.", + "functionCall": "שים לב: הפעלת קריאה לפונקציות תשבית אוטומטית את החשיבה, שכן זו דרישה של מודלי DeepSeek-V3.1." + }, + "confirmEnable": "אשר הפעלה" + } +} diff --git a/src/renderer/src/i18n/he-IL/index.ts b/src/renderer/src/i18n/he-IL/index.ts new file mode 100644 index 000000000..9bca15c47 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/index.ts @@ -0,0 +1,58 @@ +import common from './common.json' +import update from './update.json' +import routes from './routes.json' +import chat from './chat.json' +import model from './model.json' +import thread from './thread.json' +import dialog from './dialog.json' +import settings from './settings.json' +import mcp from './mcp.json' +import welcome from './welcome.json' +import artifacts from './artifacts.json' +import sync from './sync.json' +import toolCall from './toolCall.json' +import components from './components.json' +import newThread from './newThread.json' +import about from './about.json' +import contextMenu from './contextMenu.json' +import promptSetting from './promptSetting.json' +import traceDialog from './traceDialog.json' +import plan from './plan.json' + +// Individual top-level keys +const others = { + Silicon: 'SiliconFlow', + Qiniu: 'Qiniu', + QwenLM: 'Qwen Model', + Doubao: 'Doubao', + PPIO: 'PPIO Cloud', + Moonshot: 'Moonshot AI', + DashScope: 'Alibaba Bailian', + Hunyuan: 'Hunyuan', + searchDisclaimer: + 'DeepChat הוא כלי עזר בלבד המארגן ומסכם נתונים ציבוריים המוחזרים על ידי מנועי חיפוש כאשר משתמשים יוזמים חיפושים באופן פעיל, ומסייע למשתמשים לצפות ולהבין את תוצאות החיפוש בצורה נוחה יותר.\n1. שימוש בנתונים ציבוריים\nתוכנה זו מעבדת רק נתונים הזמינים באופן ציבורי באתרי היעד או במנועי החיפוש ללא צורך בהתחברות. לפני השימוש, אנא הקפד לעיין ולציית לתנאי השירות של אתר היעד או מנוע החיפוש כדי להבטיח שהשימוש שלך חוקי ותואם לכללים.\n2. דיוק המידע ואחריות\nהתוכן המאורגן והנוצר על ידי תוכנה זו הוא לעיון בלבד ואינו מהווה כל צורה של ייעוץ משפטי, עסקי או אחר. המפתחים אינם מספקים ערובות לגבי הדיוק, השלמות, העדכניות או החוקיות של תוצאות החיפוש, וכל תוצאה הנובעת משימוש בתוכנה זו הינה באחריות המשתמש בלבד.\n3. סעיף ויתור (Disclaimer)\nתוכנה זו מסופקת "כפי שהיא" (as is), והמפתחים אינם נושאים באחריות מפורשת או משתמעת לביצועיה, יציבותה או התאמתה. במהלך השימוש בתוכנה זו, המפתחים אינם נושאים באחריות לכל מחלוקת, אובדן או חבות משפטית הנובעים מהפרות של חוקים ותקנות רלוונטיים או כללי אתר היעד.\n4. משמעת עצמית של המשתמש\nלפני השימוש בתוכנה זו, על המשתמשים להבין היטב ולאשר שהשימוש שלהם לא יפגע בזכויות קניין רוחני, סודות מסחריים או זכויות לגיטימיות אחרות של אחרים. כל מחלוקת משפטית ותוצאות הנובעות משימוש לא נאות בתוכנה זו על ידי משתמשים הינן באחריות המשתמשים בלבד.\nהשימוש בתוכנה זו מציין שהמשתמש קרא, הבין והסכים לכל תנאי כתב ויתור זה. אם יש לך שאלות, אנא התייעץ עם יועץ משפטי מקצועי.' +} + +export default { + common, + update, + routes, + chat, + model, + thread, + dialog, + settings, + mcp, + welcome, + artifacts, + sync, + toolCall, + components, + newThread, + about, + contextMenu, + promptSetting, + traceDialog, + plan, + ...others +} diff --git a/src/renderer/src/i18n/he-IL/mcp.json b/src/renderer/src/i18n/he-IL/mcp.json new file mode 100644 index 000000000..49b73af67 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/mcp.json @@ -0,0 +1,316 @@ +{ + "tools": { + "searchPlaceholder": "חפש כלים...", + "noToolsAvailable": "אין כלים זמינים", + "selectToolToDebug": "בחר כלי לניפוי באגים", + "dialogDescription": "ניפוי באגים ובדיקת כלים המסופקים על ידי שרתי MCP", + "toolsCount": "{count} כלים", + "availableTools": "כלים זמינים", + "toolList": "רשימת כלים", + "functionDescription": "תיאור פונקציה", + "invalidJson": "פורמט JSON לא חוקי", + "inputHint": "אנא הזן פרמטרים בפורמט JSON", + "required": "נדרש", + "noDescription": "אין תיאור", + "input": "ארגומנטים", + "path": "נתיב", + "pathPlaceholder": "הזן נתיב קובץ", + "searchPattern": "תבנית חיפוש", + "searchPatternPlaceholder": "הזן ביטוי רגולרי (Regex)", + "filePattern": "תבנית קובץ", + "filePatternPlaceholder": "הזן תבנית קובץ, למשל: *.md", + "executeButton": "הפעל כלי", + "resultTitle": "תוצאה", + "runningTool": "מבצע כלי...", + "loading": "טוען...", + "error": "טעינה נכשלה", + "available": "{count} זמינים", + "none": "אין כלים זמינים", + "title": "כלי MCP", + "description": "כלים המסופקים על ידי שרת ה-MCP", + "loadError": "טעינת הכלים נכשלה", + "parameters": "פרמטרים", + "refresh": "רענן", + "disabled": "MCP מושבת", + "enableToUse": "אנא הפעל את MCP כדי להשתמש בכלים", + "enabled": "הפעל את MCP", + "enabledDescription": "הפעל את פונקציונליות MCP כדי להשתמש בקריאות לכלים", + "empty": "ריק", + "jsonInputPlaceholder": "הזן את הפרמטרים בפורמט JSON", + "type": "סוג", + "annotations": "הערות (Annotations)", + "invalidJsonFormat": "פורמט ה-JSON שגוי", + "allowedValues": "ערכים מותרים", + "arrayItemValues": "ערכי פריט במערך" + }, + "addServer": "הוסף שרת", + "addServerDialog": { + "description": "הגדר שרת MCP חדש", + "title": "הוסף שרת" + }, + "confirmDelete": { + "cancel": "ביטול", + "confirm": "מחק", + "description": "האם אתה בטוח שברצונך למחוק את השרת {name}? \nלא ניתן לבטל פעולה זו.", + "title": "אשר מחיקה" + }, + "confirmRemoveServer": "האם אתה בטוח שברצונך למחוק את השרת {name}? \nלא ניתן לבטל פעולה זו.", + "default": "ברירת מחדל", + "deleteServer": "מחק שרת", + "description": "ניהול והגדרה של שרתי וכלים של MCP (Model Context Protocol)", + "editServer": "ערוך שרת", + "editServerDialog": { + "description": "ערוך תצורת שרת MCP", + "title": "ערוך שרת" + }, + "enableToAccess": "אנא הפעל את MCP כדי לגשת לאפשרויות התצורה.", + "enabledDescription": "הפעל או השבת פונקציונליות וכלים של MCP.", + "enabledTitle": "הפעל את MCP", + "isDefault": "שרת ברירת מחדל", + "noServersFound": "שרת לא נמצא", + "removeDefault": "הסר ברירת מחדל", + "removeServer": "הסר שרת", + "removeServerDialog": { + "title": "מחק שרת" + }, + "resetConfirm": "שחזר", + "resetConfirmDescription": "פעולה זו משחזרת את כל שרתי ברירת המחדל תוך שמירה על השרתים המותאמים אישית שלך. \nכל שינוי בשרת ברירת המחדל יאבד.", + "resetConfirmTitle": "שחזר שירות ברירת מחדל", + "resetToDefault": "שחזר שירות ברירת מחדל", + "running": "פועל", + "serverForm": { + "add": "הוסף", + "args": "ארגומנטים", + "argsPlaceholder": "הזן ארגומנט אחד בכל שורה", + "addArg": "הוסף ארגומנט", + "argPlaceholder": "הזן ערך ארגומנט", + "argsRequired": "הפרמטרים לא יכולים להיות ריקים", + "autoApprove": "אישור אוטומטי", + "autoApproveAll": "הכל", + "autoApproveHelp": "בחר את סוג הפעולה הדורש אישור אוטומטי ובצע ללא אישור משתמש", + "autoApproveRead": "קריאה", + "autoApproveWrite": "כתיבה", + "baseUrl": "כתובת בסיס (Base URL)", + "baseUrlPlaceholder": "הזן את כתובת הבסיס של השרת (לדוגמה: http://localhost:3000)", + "cancel": "ביטול", + "command": "פקודה", + "commandPlaceholder": "הזן פקודה", + "commandRequired": "הפקודה לא יכולה להיות ריקה", + "configImported": "ייבוא התצורה הצליח", + "description": "תיאור", + "descriptionPlaceholder": "הזן את תיאור השרת", + "descriptions": "תיאור", + "descriptionsPlaceholder": "הזן את תיאור השרת", + "env": "משתני סביבה", + "envInvalid": "משתני סביבה חייבים להיות בפורמט JSON חוקי", + "envPlaceholder": "הזן משתני סביבה בפורמט JSON", + "icon": "אייקון", + "iconPlaceholder": "הזן אייקון", + "icons": "אייקונים", + "iconsPlaceholder": "הזן אייקונים", + "jsonConfig": "תצורת JSON", + "jsonConfigExample": "דוגמה לתצורת JSON", + "jsonConfigIntro": "ניתן להדביק ישירות את תצורת ה-JSON או לבחור להגדיר את השרת ידנית.", + "jsonConfigPlaceholder": "אנא הדבק את תצורת השרת MCP בפורמט JSON", + "name": "שם השרת", + "namePlaceholder": "הזן את שם השרת", + "nameRequired": "שם השרת לא יכול להיות ריק", + "parseAndContinue": "נתח והמשך", + "parseError": "שגיאת ניתוח", + "parseSuccess": "התצורה נותחה בהצלחה", + "skipToManual": "דלג להגדרה ידנית", + "submit": "שלח", + "folders": "רשימת תיקיות", + "addFolder": "הוסף תיקייה", + "selectFolder": "בחר תיקייה", + "selectFolderError": "בחירת התיקייה נכשלה", + "noFoldersSelected": "לא נבחרו תיקיות", + "type": "סוג שרת", + "typeInMemory": "זיכרון (Memory)", + "typePlaceholder": "בחר סוג שרת", + "typeSse": "אירועים הנשלחים מהשרת (SSE)", + "typeStdio": "קלט ופלט סטנדרטי (Stdio)", + "update": "עדכן" + }, + "serverList": "רשימת שרתים", + "setAsDefault": "הגדר כשרת ברירת המחדל", + "setDefault": "הגדר כברירת מחדל", + "startServer": "התחל את השרת", + "stopServer": "עצור את השרת", + "stopped": "נעצר", + "sampling": { + "title": "דגימת בקשה מ-{server}", + "unknownServer": "שרת לא ידוע", + "description": "סקור את ההקשר המשותף על ידי שרת ה-MCP ובחר האם ליצור תגובה.", + "systemPrompt": "הנחיית מערכת (System prompt)", + "messagesTitle": "הקשר שיחה", + "preferencesTitle": "העדפות מודל", + "approve": "אשר", + "reject": "דחה", + "confirm": "שלח תגובה", + "confirming": "מאשר...", + "sendResponse": "שלח תגובה", + "selectModel": "בחר מודל", + "respondWith": "הגב באמצעות:", + "maxTokensInfo": "אורך תגובה מקסימלי: {maxTokens} טוקנים", + "visionWarning": "המודל שנבחר אינו תומך בקלט חזותי. אנא בחר מודל בעל יכולות ראייה לפני שתמשיך.", + "selectedModelLabel": "מגיב עם {model} ({provider})", + "unsupportedMessage": "סוג תוכן זה אינו נתמך.", + "noVisionModels": "לא מופעלים מודלים בעלי יכולת ראייה. הפעל מודל ראייה בהגדרות כדי להמשיך.", + "noModels": "לא מופעלים מודלים מתאימים. הפעל מודל ישים בהגדרות כדי להמשיך.", + "imageAlt": "תמונה {index}", + "unknownMime": "סוג MIME לא ידוע", + "unknownHint": "רמז ללא שם", + "autoApproving": "בקשת דגימת MCP מאת {server}", + "autoApproveIn": "מאשר אוטומטית בעוד {seconds} שניות באמצעות {model}", + "reviewRequest": "סקירה", + "sessionActive": "הפעלה פעילה - בקשות יאושרו אוטומטית", + "contentType": { + "text": "טקסט", + "image": "תמונה", + "audio": "שמע" + }, + "preference": { + "cost": "עדיפות עלות", + "speed": "עדיפות מהירות", + "intelligence": "עדיפות אינטליגנציה", + "hints": "רמזי מודל" + } + }, + "tabs": { + "servers": "שרתים", + "tools": "כלים" + }, + "title": "הגדרות MCP", + "inmemory": { + "Artifacts": { + "desc": "צור תוצרים (Artifacts) עשירים יותר ב-DeepChat", + "name": "תוצרים (Artifacts)" + }, + "bochaSearch": { + "desc": "Bocha Search API https://open.bochaai.com/", + "name": "Bocha Search" + }, + "buildInFileSystem": { + "desc": "אפשר ל-DeepChat אינטראקציה עם מערכת הקבצים המקומית.", + "name": "מערכת קבצים" + }, + "imageServer": { + "desc": "אפשר לכל מודל ב-DeepChat להבין וליצור תמונות.", + "name": "שירות תמונות" + }, + "braveSearch": { + "desc": "Brave Search API https://brave.com/search/api/", + "name": "Brave Search" + }, + "powerpack": { + "desc": "ספק למודלים שאילתות זמן, גלישה באינטרנט והרצת קוד מאובטחת.", + "name": "Power Pack" + }, + "difyKnowledge": { + "desc": "שירות חיפוש בסיס ידע של Dify, המסוגל לאחזר תוכן מתוך Dify Knowledge Base", + "name": "חיפוש בסיס ידע Dify" + }, + "ragflowKnowledge": { + "name": "חיפוש בסיס ידע RAGFlow", + "desc": "שירות חיפוש בסיס ידע של RAGFlow, יכול לחפש בתוכן בסיס הידע של RAGFlow" + }, + "fastGptKnowledge": { + "name": "חיפוש בסיס ידע FastGPT", + "desc": "שירות חיפוש בסיס ידע של FastGPT, יכול לחפש בתוכן בסיס הידע של FastGPT" + }, + "deepchat-inmemory/custom-prompts-server": { + "desc": "שירות הנחיות מותאמות אישית מובנה של DeepChat", + "name": "הנחיות מותאמות אישית" + }, + "deepchat-inmemory/deep-research-server": { + "desc": "מחקר עמוק מובנה ב-DeepChat המופעל על ידי Bocha Search. מומלץ להשתמש במודלים בעלי הקשר ארוך (Long-context).", + "name": "מחקר עמוק (DeepResearch)" + }, + "deepchat-inmemory/auto-prompting-server": { + "name": "הנחיה אוטומטית לפי תבנית", + "desc": "בחר אוטומטית את ההנחיה המותאמת הטובה ביותר בהתבסס על הקלט ומלא את התבנית בצורה חכמה." + }, + "deepchat-inmemory/conversation-search-server": { + "name": "חיפוש היסטוריית שיחות", + "desc": "חיפוש היסטוריית שיחות מובנה של DeepChat עבור צ'אטים והודעות עבר." + }, + "builtinKnowledge": { + "desc": "חיפוש בסיס ידע מובנה של DeepChat עבור מסמכים ומדריכים של DeepChat.", + "name": "חיפוש בסיס ידע מובנה" + }, + "deepchat-inmemory/meeting-server": { + "name": "פגישות מרובות סוכנים (Multi-Agent)", + "desc": "פגישות מובנות ב-DeepChat לאירוח דיונים מרובי סוכנים." + }, + "deepchat/apple-server": { + "desc": "אפשר למודלים להפעיל אפליקציות macOS כמו יומן, אנשי קשר, דואר, מפות, פתקים ותזכורות.", + "name": "עוזר מערכת macOS" + } + }, + "prompts": { + "noPromptsAvailable": "אין הנחיות (Prompts) זמינות", + "noDescription": "אין תיאור עדיין", + "selectPrompt": "פרטים עבור ההנחיה שנבחרה יוצגו כאן.", + "parameters": "פרמטרים", + "input": "פרמטרים", + "runningPrompt": "מביא הנחיה...", + "executeButton": "קבל הנחיה", + "resultTitle": "פרטי הנחיה", + "invalidJson": "פורמט JSON לא חוקי", + "parametersHint": "אנא הזן את הפרמטרים בפורמט JSON, תומך בעיצוב אוטומטי", + "resetToDefault": "אפס לפרמטרים ברירת מחדל", + "dialogDescription": "ניפוי באגים ובדיקת הנחיות המסופקות על ידי שרתי MCP" + }, + "resources": { + "noResourcesAvailable": "אין משאבים זמינים", + "selectResource": "בחר משאב לצפייה בתוכנו.", + "loading": "טוען...", + "loadContent": "טען תוכן", + "pleaseSelect": "לחץ לצפייה בפרטי המשאב.", + "dialogDescription": "עיין וצפה במשאבים המסופקים על ידי שרתי MCP" + }, + "errors": { + "loadConfigFailed": "טעינת תצורת MCP נכשלה", + "setEnabledFailed": "הגדרת מצב הפעלה של MCP נכשלה", + "getServerStatusFailed": "קבלת סטטוס עבור השרת {serverName} נכשלה", + "addServerFailed": "הוספת השרת נכשלה", + "updateServerFailed": "עדכון השרת נכשל", + "removeServerFailed": "הסרת השרת נכשלה", + "maxDefaultServersReached": "הגעת למספר המקסימלי של שרתי ברירת מחדל (30)", + "toggleDefaultServerFailed": "שינוי סטטוס שרת ברירת המחדל נכשל", + "resetToDefaultFailed": "שחזור לשרתי ברירת מחדל נכשל", + "toggleServerFailed": "שינוי מצב השרת {serverName} נכשל", + "loadToolsFailed": "טעינת הכלים נכשלה", + "loadPromptsFailed": "טעינת ההנחיות נכשלה", + "loadResourcesFailed": "טעינת המשאבים נכשלה", + "callToolFailed": "הקריאה לכלי {toolName} נכשלה", + "toolCallError": "שגיאה בקריאה לכלי: {error}", + "mcpDisabled": "MCP מושבת", + "getPromptFailed": "קבלת ההנחיה נכשלה", + "readResourceFailed": "קריאת המשאב נכשלה", + "promptNotFound": "הנחיה '{name}' לא נמצאה", + "emptyPromptContent": "להנחיה '{name}' אין תוכן", + "missingParameters": "חסרים פרמטרים נדרשים: {params}", + "invalidParameters": "פרמטרים לא חוקיים עבור: {params}" + }, + "market": { + "browseBuiltin": "עיין בחנות ה-MCP המובנית", + "builtinTitle": "חנות MCP", + "poweredBy": "מופעל על ידי MCPRouter", + "keyGuide": "קבל מפתח API", + "keyHelpText": "אנא עבור אל", + "keyHelpEnd": "כדי להגיש בקשה למפתח API ומלא אותו בתיבת הקלט למעלה", + "apiKeyPlaceholder": "הזן מפתח API של MCPRouter", + "apiKeyRequiredTitle": "נדרש מפתח API", + "apiKeyRequiredDesc": "אנא מלא את מפתח ה-API של MCPRouter לפני ההתקנה", + "install": "התקן", + "installed": "מותקן", + "installSuccess": "ההתקנה הצליחה", + "installFailed": "ההתקנה נכשלה", + "noMore": "אין עוד", + "empty": "אין שירותים", + "loadMore": "טען עוד", + "pullDownToLoad": "המשך למשוך למטה כדי לטעון עוד" + } +} diff --git a/src/renderer/src/i18n/he-IL/model.json b/src/renderer/src/i18n/he-IL/model.json new file mode 100644 index 000000000..f3d32b26c --- /dev/null +++ b/src/renderer/src/i18n/he-IL/model.json @@ -0,0 +1,30 @@ +{ + "search": { + "placeholder": "חפש מודלים..." + }, + "error": { + "loadFailed": "טעינת המודלים נכשלה" + }, + "type": { + "custom": "מודל מותאם אישית", + "official": "מודל רשמי" + }, + "add": { + "namePlaceholder": "שם המודל", + "idPlaceholder": "מזהה מודל (ID)", + "contextLengthPlaceholder": "אורך הקשר (Context)", + "maxTokensPlaceholder": "מקסימום טוקנים" + }, + "actions": { + "add": "הוסף מודל", + "enableAll": "הפעל הכל", + "disableAll": "השבת הכל" + }, + "tags": { + "reasoning": "חשיבה (Reasoning)", + "chat": "צ'אט", + "code": "קוד", + "writing": "כתיבה", + "analysis": "ניתוח" + } +} diff --git a/src/renderer/src/i18n/he-IL/newThread.json b/src/renderer/src/i18n/he-IL/newThread.json new file mode 100644 index 000000000..0c5c81044 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/newThread.json @@ -0,0 +1,4 @@ +{ + "greeting": "שלום!", + "prompt": "על מה תרצה לדבר?" +} diff --git a/src/renderer/src/i18n/he-IL/plan.json b/src/renderer/src/i18n/he-IL/plan.json new file mode 100644 index 000000000..d46fe794b --- /dev/null +++ b/src/renderer/src/i18n/he-IL/plan.json @@ -0,0 +1,4 @@ +{ + "completed": "הושלם", + "title": "תכנון משימה" +} diff --git a/src/renderer/src/i18n/he-IL/promptSetting.json b/src/renderer/src/i18n/he-IL/promptSetting.json new file mode 100644 index 000000000..287113a5c --- /dev/null +++ b/src/renderer/src/i18n/he-IL/promptSetting.json @@ -0,0 +1,95 @@ +{ + "title": "ניהול הנחיות (Prompt Management)", + "addTitle": "הוסף הנחיה", + "addDescription": "צור תבנית הנחיה מותאמת אישית חדשה", + "editTitle": "ערוך הנחיה", + "editDescription": "שנה את תבנית ההנחיה שנבחרה", + "name": "שם", + "namePlaceholder": "הזן שם עבור ההנחיה שלך", + "description": "תיאור", + "descriptionPlaceholder": "אנא הזן תיאור (אופציונלי)", + "promptContent": "הנחיה (Prompt)", + "contentPlaceholder": "אנא הזן את תוכן ההנחיה", + "basicInfo": "מידע בסיסי", + "contentTip": "תומך במצייני מקום של משתנים כמו {openBrace}{openBrace}variable{closeBrace}{closeBrace}, ניתן להגדיר פרמטרים מתאימים בסעיף הפרמטרים", + "noPrompt": "אין הנחיות עדיין", + "noPromptDesc": "לחץ על כפתור \"+\" בפינה העליונה כדי ליצור את ההנחיה הראשונה שלך.", + "active": "פעיל", + "noDescription": "אין תיאור", + "customDate": "מותאם אישית", + "showMore": "הצג עוד", + "showLess": "הצג פחות", + "export": "ייצוא", + "import": "ייבוא", + "exportSuccess": "הייצוא הושלם בהצלחה", + "exportFailed": "הייצוא נכשל", + "importSuccess": "הייבוא הושלם בהצלחה", + "importFailed": "הייבוא נכשל", + "importStats": "נוספו {added}, עודכנו {updated} הנחיות", + "parameters": "פרמטרים", + "addParameter": "הוסף פרמטר", + "noParameters": "אין פרמטרים", + "noParametersDesc": "לחץ על הכפתור למעלה כדי להוסיף פרמטרים, שבהם ניתן להשתמש ליצירת מצייני מקום למשתנים בהנחיות", + "parameterName": "שם הפרמטר", + "parameterDescription": "תיאור הפרמטר", + "parameterNamePlaceholder": "אנא הזן שם פרמטר", + "parameterDescriptionPlaceholder": "אנא הזן תיאור פרמטר", + "required": "נדרש", + "characters": "תווים", + "fileManagement": "ניהול קבצים", + "uploadFromDevice": "העלה מהמכשיר", + "uploadFromDeviceDesc": "תומך בטקסט, מסמכים, CSV ועוד.", + "uploadedFiles": "קבצים שהועלו", + "noFiles": "אין קבצים", + "noFilesUploadDesc": "לחץ למעלה להעלאת קבצים", + "uploadSuccess": "ההעלאה הושלמה", + "uploadedCount": "הועלו {count} קבצים", + "confirmDelete": "האם אתה בטוח שברצונך למחוק את ההנחיה \"{name}\"?", + "confirmDeleteDescription": "לא ניתן לבטל פעולה זו. ההנחיה תימחק לצמיתות.", + "confirmDeleteSystemPrompt": "האם אתה בטוח שברצונך למחוק את הנחיית המערכת \"{name}\"?", + "confirmDeleteSystemPromptDescription": "לא ניתן לבטל פעולה זו. הנחיית המערכת תימחק לצמיתות.", + "deleteSuccess": "ההנחיה נמחקה", + "deleteFailed": "מחיקת ההנחיה נכשלה", + "inactive": "לא פעיל", + "clickToEnable": "לחץ להפעלה", + "clickToDisable": "לחץ להשבתה", + "enableSuccess": "הנחיה הופעלה", + "disableSuccess": "הנחיה הושבתה", + "toggleFailed": "שינוי הסטטוס נכשל", + "enablePrompt": "הפעל הנחיה זו", + "sourceLocal": "מקומי", + "sourceImported": "מיובא", + "sourceBuiltin": "מובנה", + "defaultSystemPrompt": "הנחיית מערכת ברירת מחדל", + "defaultSystemPromptPlaceholder": "הזן את הנחיית המערכת שתשמש כברירת מחדל לכל השיחות החדשות...", + "defaultSystemPromptDescription": "הנחיה זו תחול על כל השיחות החדשות. ניתן לשנות אותה בעת יצירת שיחה. שים לב שהגדרה זו תיכנס לתוקף בפעם הבאה שתיצור שיחה חדשה.", + "typing": "מקליד...", + "saving": "שומר...", + "saved": "נשמר", + "saveDefaultPromptFailed": "שמירת הנחיית מערכת ברירת המחדל נכשלה", + "systemPrompts": "הנחיות מערכת", + "customPrompts": "הנחיות מותאמות אישית", + "addSystemPrompt": "הוסף הנחיית מערכת", + "addCustomPrompt": "הוסף הנחיה מותאמת אישית", + "editSystemPrompt": "ערוך הנחיית מערכת", + "addSystemPromptDesc": "צור הנחיית מערכת חדשה", + "editSystemPromptDesc": "שנה את הנחיית המערכת שנבחרה", + "selectSystemPrompt": "בחר הנחיית מערכת", + "systemPromptDescription": "הנחיית המערכת שנבחרה תשמש כברירת מחדל לשיחות חדשות", + "emptySystemPromptOption": "ללא הנחיית מערכת", + "emptySystemPromptDescription": "כאשר אפשרות זו נבחרה, שיחות חדשות יתחילו ללא הנחיית מערכת.", + "preview": "תצוגה מקדימה", + "systemPromptChanged": "הנחיית המערכת שונתה בהצלחה", + "systemPromptChangeFailed": "שינוי הנחיית המערכת נכשל", + "systemPromptAdded": "הנחיית מערכת נוספה בהצלחה", + "systemPromptAddedAndSwitched": "הנחיית מערכת נוספה והוגדרה אוטומטית כברירת מחדל", + "systemPromptUpdated": "הנחיית מערכת עודכנה בהצלחה", + "systemPromptSaveFailed": "שמירת הנחיית המערכת נכשלה", + "systemPromptDeleted": "הנחיית המערכת נמחקה בהצלחה", + "systemPromptDeleteFailed": "מחיקת הנחיית המערכת נכשלה", + "systemPromptEditTip": "שמירה אוטומטית בעת אובדן פוקוס לאחר עריכה", + "resetToDefault": "אפס לברירת מחדל", + "resetToDefaultSuccess": "אופס לתוכן ברירת המחדל בהצלחה", + "resetToDefaultFailed": "האיפוס לברירת המחדל נכשל", + "parameterRequired": "פרמטרים נדרשים" +} diff --git a/src/renderer/src/i18n/he-IL/routes.json b/src/renderer/src/i18n/he-IL/routes.json new file mode 100644 index 000000000..fa3db69b0 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/routes.json @@ -0,0 +1,17 @@ +{ + "chat": "צ'אט", + "welcome": "ברוכים הבאים", + "playground": "אזור ניסויים (Playground)", + "settings": "הגדרות", + "settings-common": "הגדרות כלליות", + "settings-provider": "ספקים", + "settings-mcp": "הגדרות MCP", + "settings-database": "נתונים", + "settings-about": "אודות", + "settings-shortcut": "קיצורי מקשים", + "settings-display": "תצוגה", + "settings-knowledge-base": "בסיס ידע", + "settings-prompt": "הנחיות (Prompts)", + "settings-mcp-market": "חנות MCP", + "settings-acp": "סוכני ACP" +} diff --git a/src/renderer/src/i18n/he-IL/settings.json b/src/renderer/src/i18n/he-IL/settings.json new file mode 100644 index 000000000..4084f2e65 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/settings.json @@ -0,0 +1,964 @@ +{ + "title": "הגדרות", + "common": { + "title": "הגדרות כלליות", + "resetData": "אפס נתונים", + "language": "שפה", + "languageSelect": "בחר שפה", + "searchEngine": "מנוע חיפוש", + "searchEngineSelect": "בחר מנוע חיפוש", + "searchPreview": "תצוגה מקדימה של חיפוש", + "searchAssistantModel": "מודל עוזר", + "selectModel": "בחר מודל", + "proxyMode": "מצב פרוקסי", + "proxyModeSelect": "בחר מצב פרוקסי", + "proxyModeSystem": "פרוקסי מערכת", + "proxyModeNone": "ללא פרוקסי", + "proxyModeCustom": "פרוקסי מותאם אישית", + "customProxyUrl": "כתובת URL לפרוקסי מותאם", + "customProxyUrlPlaceholder": "דוגמה: http://127.0.0.1:7890", + "invalidProxyUrl": "כתובת פרוקסי לא חוקית, אנא הזן כתובת http/https תקינה", + "addCustomSearchEngine": "הוסף מנוע חיפוש מותאם", + "addCustomSearchEngineDesc": "הוסף מנוע חיפוש חדש על ידי מתן שם וכתובת URL לחיפוש. הכתובת חייבת לכלול את {query} כמציין מקום לשאילתה.", + "searchEngineName": "שם מנוע החיפוש", + "searchEngineNamePlaceholder": "הזן את שם מנוע החיפוש", + "searchEngineUrl": "כתובת URL לחיפוש", + "searchEngineUrlPlaceholder": "דוגמה: https://a.com/search?q={'{'}query{'}'}", + "searchEngineUrlError": "הכתובת חייבת לכלול את {'{'}query{'}'} כמציין מקום לשאילתה", + "deleteCustomSearchEngine": "מחק מנוע חיפוש מותאם", + "deleteCustomSearchEngineDesc": "האם אתה בטוח שברצונך למחוק את מנוע החיפוש המותאם \"{name}\"? לא ניתן לבטל פעולה זו.", + "testSearchEngine": "בדוק מנוע חיפוש", + "testSearchEngineDesc": "חיפוש בדיקה עבור \"weather\" יבוצע באמצעות מנוע החיפוש {engine}.", + "testSearchEngineNote": "אם דף החיפוש דורש התחברות או פעולות אחרות, ניתן לבצע אותן בחלון הבדיקה. אנא סגור את חלון הבדיקה בסיום.", + "theme": "ערכת נושא", + "themeSelect": "בחר ערכת נושא", + "themeLight": "בהיר", + "themeDark": "כהה", + "themeSystem": "עקוב אחר המערכת", + "closeToQuit": "צא מהאפליקציה בעת סגירת החלון", + "contentProtectionDialogTitle": "אשר שינוי הגנת מסך", + "contentProtectionEnableDesc": "מנע מיישומי שיתוף מסך ללכוד את חלון DeepChat כדי לעזור להגן על פרטיותך. לא כל האפליקציות מכבדות הגדרה זו; בסביבות מסוימות עשוי להופיע חלון שחור.", + "contentProtectionDisableDesc": "אפשר ליישומי שיתוף מסך ללכוד את חלון DeepChat.", + "contentProtectionRestartNotice": "שינוי הגדרה זו יגרום להפעלה מחדש של האפליקציה. האם להמשיך?", + "soundEnabled": "הפעל אפקטים קוליים", + "copyWithCotEnabled": "העתק פרטי COT (שרשרת מחשבה)", + "traceDebugEnabled": "מעקב אחר קריאה (Trace Call)", + "loggingEnabled": "הפעל רישום לוגים", + "loggingDialogTitle": "אשר שינוי הגדרת רישום לוגים", + "loggingEnableDesc": "הפעלת רישום לוגים תעזור לנו לאבחן בעיות ולשפר את האפליקציה. קבצי הלוג עשויים להכיל מידע רגיש.", + "loggingDisableDesc": "השבתת רישום לוגים תפסיק את איסוף יומני האפליקציה.", + "webContentLengthLimit": "מגבלת אורך תוכן אינטרנט", + "webContentLengthLimitHint": "(הגדר ל-0 ללא הגבלה)", + "charactersUnit": "תווים", + "webContentLengthLimitTooltip": "הגדר את האורך המקסימלי של טקסט המופק מדפי אינטרנט (מספר תווים), טווח: 0-50000. הגדרה ל-0 משמעותה ללא הגבלה ושליפת תוכן האינטרנט המלא; ערכים גבוהים יותר מספקים תוכן שלם יותר אך עשויים להגדיל את זמן העיבוד ואת השימוש בטוקנים.", + "loggingRestartNotice": "שינוי הגדרה זו יגרום להפעלה מחדש של האפליקציה. האם להמשיך?", + "openLogFolder": "פתח תיקיית לוגים", + "shortcut": { + "newChat": "צור צ'אט חדש", + "title": "הגדרות קיצורי מקשים" + }, + "notifications": "התראות מערכת", + "notificationsDesc": "כאשר DeepChat אינו בחזית, אם נוצרת תשובה, תישלח התראת מערכת", + "contentProtection": "הגנה מפני לכידת מסך", + "fileMaxSize": "גודל קובץ מקסימלי", + "fileMaxSizeHint": "מגביל את הגודל המקסימלי של קובץ בודד המועלה" + }, + "data": { + "title": "הגדרות נתונים", + "syncEnable": "הפעל סנכרון נתונים", + "syncFolder": "תיקיית סנכרון", + "openSyncFolder": "פתח תיקיית סנכרון", + "lastSyncTime": "זמן סנכרון אחרון", + "never": "מעולם לא", + "startBackup": "גבה כעת", + "backingUp": "מגבה...", + "importData": "ייבוא נתונים", + "incrementImport": "ייבוא מצטבר (Incremental)", + "overwriteImport": "ייבוא דורס (Overwrite)", + "backupSelectLabel": "בחר גיבוי", + "backupSelectDescription": "בחר את תמונת המצב של הגיבוי לייבוא.", + "selectBackupPlaceholder": "בחר גיבוי", + "noBackupsAvailable": "אין גיבויים זמינים. בצע גיבוי תחילה.", + "importConfirmTitle": "אשר ייבוא נתונים", + "importConfirmDescription": "הייבוא ידרוס את כל הנתונים הנוכחיים, כולל היסטוריית צ'אט והגדרות. ודא שגיבית נתונים חשובים. יהיה עליך להפעיל מחדש את האפליקציה לאחר הייבוא.", + "importing": "מייבא...", + "confirmImport": "אשר ייבוא", + "importSuccessTitle": "הייבוא הושלם בהצלחה", + "importErrorTitle": "הייבוא נכשל", + "resetData": "אפס נתונים", + "resetConfirmTitle": "אשר איפוס נתונים", + "resetConfirmDescription": "אנא בחר את סוג הנתונים לאיפוס. לא ניתן לבטל פעולה זו והאפליקציה תופעל מחדש אוטומטית לאחר האיפוס.", + "resetChatData": "אפס נתוני צ'אט", + "resetChatDataDesc": "מחק את כל היסטוריית הצ'אט ורשומות השיחות", + "resetKnowledgeData": "אפס נתוני בסיס ידע", + "resetKnowledgeDataDesc": "מחק את כל קבצי בסיס הידע ונתוני הוקטורים", + "resetConfig": "אפס תצורה", + "resetConfigDesc": "מחק את כל הגדרות האפליקציה, תצורות המודלים והנחיות מותאמות אישית", + "resetAll": "איפוס מלא", + "resetAllDesc": "מחק את כל הנתונים כולל היסטוריית צ'אט, תצורות וקבצי מטמון", + "resetting": "מאפס...", + "confirmReset": "אשר איפוס", + "resetCompleteDevTitle": "איפוס הנתונים הושלם", + "resetCompleteDevMessage": "אנא הפעל מחדש ידנית את האפליקציה במצב פיתוח. עצור את התהליך הנוכחי והרץ שוב pnpm run dev", + "toast": { + "backupSuccessTitle": "גיבוי הושלם בהצלחה", + "backupSuccessMessage": "הנתונים גובו בהצלחה" + } + }, + "model": { + "title": "הגדרות מודל", + "systemPrompt": { + "label": "הנחיית מערכת", + "placeholder": "אנא הזן את הנחיית המערכת...", + "description": "הגדר את הנחיית המערכת עבור עוזר ה-AI כדי להגדיר את התנהגותו ותפקידו" + }, + "temperature": { + "label": "טמפרטורת מודל", + "description": "שולט באקראיות של הפלט; ערכים גבוהים יותר מייצרים תשובות יצירתיות יותר" + }, + "contextLength": { + "label": "אורך הקשר (Context)", + "description": "הגדר את האורך המקסימלי של הקשר השיחה" + }, + "responseLength": { + "label": "אורך תגובה", + "description": "הגדר את האורך המקסימלי של תגובת ה-AI" + }, + "artifacts": { + "description": "הפעלת תכונת ה-Artifacts (תוצרים) מאפשרת ל-AI ליצור תוכן עשיר יותר", + "title": "תוצרים (Artifacts)" + }, + "addModel": "הוסף מודל", + "configureModel": "הגדר מודל", + "modelList": "רשימת מודלים", + "provider": "ספק שירות", + "providerSetting": "הגדרות ספק שירות", + "selectModel": "בחר מודל", + "modelConfig": { + "cancel": "ביטול", + "contextLength": { + "description": "הגדר את אורך ההקשר שהמודל יכול לטפל בו", + "label": "אורך הקשר" + }, + "description": "שים לב שתצורה זו תקפה רק למודל הנוכחי ולא תשפיע על מודלים אחרים. אנא שנה אותה בזהירות. פרמטרים שגויים עלולים לגרום למודל לא לפעול כראוי.", + "name": { + "label": "שם המודל", + "description": "השם המוצג של המודל", + "placeholder": "הזן שם מודל", + "required": "שם המודל נדרש", + "readonly": "שם המודל (קריאה בלבד)" + }, + "id": { + "label": "מזהה מודל (ID)", + "description": "המזהה הייחודי של המודל", + "placeholder": "הזן מזהה מודל", + "required": "מזהה מודל נדרש", + "readonly": "מזהה מודל (קריאה בלבד)", + "duplicate": "מודל עם מזהה זה כבר קיים" + }, + "createTitle": "הוסף מודל מותאם אישית", + "editTitle": "ערוך תצורת מודל - {name}", + "functionCall": { + "description": "האם המודל תומך בקריאות לפונקציות באופן טבעי (DeepChat יסמלץ אוטומטית קריאות לפונקציות לאחר כיבוי אפשרות זו)", + "label": "קריאות לפונקציות" + }, + "maxTokens": { + "description": "הגדר את המספר המקסימלי של טוקנים לפלט יחיד של המודל", + "label": "אורך פלט מקסימלי" + }, + "reasoning": { + "description": "האם המודל תומך ביכולת חשיבה (Reasoning)?", + "label": "יכולת חשיבה" + }, + "enableSearch": { + "label": "חיפוש אינטרנט", + "description": "אפשר למודל לחפש באינטרנט מידע עדכני" + }, + "forcedSearch": { + "label": "חיפוש כפוי", + "description": "כפה על המודל לבצע חיפוש באינטרנט; כשמושבת, המודל מחליט אוטומטית" + }, + "searchStrategy": { + "label": "אסטרטגיית חיפוש", + "description": "בחר מצב ביצועי חיפוש: turbo מאזן מהירות ויעילות, max מספק תוצאות חיפוש אופטימליות", + "placeholder": "בחר אסטרטגיית חיפוש", + "options": { + "turbo": "Turbo - איזון בין מהירות תגובה ליעילות חיפוש (מומלץ)", + "max": "Max - מצב ביצועים גבוהים, מספק תוצאות חיפוש אופטימליות" + } + }, + "thinkingBudget": { + "label": "תקציב חשיבה", + "description": "הגדר את אורך הטוקנים המקסימלי לתהליך החשיבה כדי לשלוט בעומק החשיבה", + "placeholder": "הזן ערך תקציב חשיבה", + "range": "טווח: {min} - {max}", + "validation": { + "required": "אנא הזן ערך תקציב חשיבה", + "minValue": "ערך תקציב החשיבה נמוך מהמינימום", + "maxValue": "ערך תקציב החשיבה אינו יכול לעלות על {max}" + } + }, + "resetConfirm": { + "confirm": "אשר איפוס", + "message": "האם אתה בטוח שברצונך לאפס את תצורת המודל הזה לברירת המחדל? \nפעולה זו בלתי הפיכה.", + "title": "אשר איפוס" + }, + "reasoningEffort": { + "label": "מאמץ חשיבה", + "description": "שולט בעומק החשיבה של המודל; מאמץ גבוה יותר מפיק תוצאות טובות יותר אך תגובות איטיות יותר", + "placeholder": "בחר מאמץ חשיבה", + "options": { + "minimal": "מינימלי - התגובה המהירה ביותר", + "low": "נמוך - מאמץ נמוך", + "medium": "בינוני - מאמץ בינוני", + "high": "גבוה - מאמץ גבוה" + } + }, + "verbosity": { + "label": "רמת פירוט", + "description": "שולט ברמת הפרטים ואורך תשובות המודל", + "placeholder": "בחר רמת פירוט", + "options": { + "low": "נמוכה - תשובות תמציתיות", + "medium": "בינונית - פירוט מאוזן", + "high": "גבוהה - תשובות מפורטות" + } + }, + "resetToDefault": "אפס לברירת מחדל", + "saveConfig": "שמור תצורה", + "useModelDefault": "השתמש בתצורת ברירת המחדל של המודל", + "currentUsingModelDefault": "משתמש כעת בתצורת ברירת המחדל של המודל", + "temperature": { + "description": "שלוט באקראיות הפלט. רוב המודלים הם 0-1, וחלקם תומכים בין 0-2. ערכים גבוהים יותר מגבירים את האקראיות.", + "label": "טמפרטורה" + }, + "title": "פרמטרים מותאמים למודל", + "type": { + "description": "בחר את סוג המודל", + "label": "סוג מודל", + "options": { + "chat": "מודל שפה (Chat)", + "embedding": "מודל הטמעה (Embedding)", + "imageGeneration": "מודל יצירת תמונות", + "rerank": "מודל דירוג מחדש (Rerank)" + } + }, + "validation": { + "contextLengthMax": "אורך ההקשר אינו יכול לעלות על 10000000", + "contextLengthMin": "אורך ההקשר חייב להיות גדול מ-0", + "contextLengthRequired": "אורך ההקשר אינו יכול להיות ריק", + "maxTokensMax": "אורך הפלט המקסימלי אינו יכול לעלות על 1000000", + "maxTokensMin": "אורך הפלט המקסימלי חייב להיות גדול מ-0", + "maxTokensRequired": "אורך הפלט המקסימלי אינו יכול להיות ריק", + "temperatureMax": "הטמפרטורה חייבת להיות קטנה או שווה ל-2", + "temperatureMin": "הטמפרטורה חייבת להיות גדולה או שווה ל-0", + "temperatureRequired": "הטמפרטורה אינה יכולה להיות ריקה" + }, + "vision": { + "description": "האם המודל תומך ביכולת חזותית?", + "label": "יכולת חזותית" + }, + "searchLimit": { + "label": "מגבלת חיפוש", + "description": "מגבלת מודל: הפעלת חיפוש באינטרנט תשבית קריאות לפונקציות כלים" + } + } + }, + "provider": { + "search": "חפש פלטפורמות ספקים...", + "enable": "הפעל שירות", + "enabled": "מופעל", + "disabled": "מושבת", + "urlPlaceholder": "אנא הזן כתובת API", + "keyPlaceholder": "אנא הזן מפתח API", + "accessKeyIdPlaceholder": "אנא הזן AWS Access Key ID", + "secretAccessKeyPlaceholder": "אנא הזן AWS Secret Access Key", + "regionPlaceholder": "אנא הזן אזור AWS", + "vertexProjectId": "מזהה פרויקט (Project ID)", + "vertexProjectIdPlaceholder": "אנא הזן את מזהה הפרויקט שלך ב-Google Cloud", + "vertexLocation": "אזור", + "vertexLocationPlaceholder": "אנא הזן אזור (למשל us-central1)", + "vertexServiceEmail": "אימייל חשבון שירות", + "vertexServiceEmailPlaceholder": "אנא הזן את אימייל חשבון השירות", + "vertexPrivateKey": "מפתח פרטי של חשבון שירות", + "vertexPrivateKeyPlaceholder": "הדבק את המפתח הפרטי (תומך בשורה אחת \\n)", + "vertexApiVersion": "גרסת API", + "vertexEndpointMode": "מצב נקודת קצה", + "vertexEndpointStandard": "סטנדרטי (נקודת קצה אזורית)", + "vertexEndpointExpress": "אקספרס (נקודת קצה גלובלית)", + "verifyKey": "אמת מפתח", + "howToGet": "כיצד להשיג", + "getKeyTip": "אנא בקר ב", + "getKeyTipEnd": "כדי לקבל מפתח API", + "urlFormat": "דוגמת API: {defaultUrl}", + "modelList": "רשימת מודלים", + "enableModels": "הפעל מודלים", + "disableAllModels": "השבת את כל המודלים", + "modelsEnabled": "מודלים הופעלו", + "noModelsEnabled": { + "title": "אין מודלים מופעלים", + "description": "אנא לחץ על כפתור \"הפעל מודלים\" כדי לבחור ידנית את המודלים שברצונך להשתמש בהם." + }, + "verifyLink": "אמת קישור", + "syncModelsFailed": "סנכרון המודלים נכשל...", + "addCustomProvider": "הוסף ספק מותאם אישית", + "delete": "מחק", + "stopModel": "עצור מודל", + "pulling": "מושך...", + "runModel": "הרץ מודל", + "dialog": { + "disableModel": { + "title": "אשר השבתת מודל", + "content": "האם אתה בטוח שברצונך להשבית את המודל \"{name}\"?", + "confirm": "השבת" + }, + "disableAllModels": { + "title": "אשר השבתת כל המודלים", + "content": "האם אתה בטוח שברצונך להשבית את כל המודלים?", + "confirm": "השבת הכל" + }, + "configModels": { + "title": "הגדר רשימת מודלים", + "description": "בחר מודלים להפעלה או השבתה" + }, + "verify": { + "missingFields": "אנא הזן מפתח API וכתובת API", + "failed": "האימות נכשל", + "success": "האימות עבר בהצלחה", + "failedDesc": "אימות מפתח ה-API או התצורה נכשל, אנא בדוק את ההגדרות שלך", + "successDesc": "מפתח ה-API והתצורה אומתו בהצלחה, מוכן לשימוש", + "connectionError": "שגיאת חיבור, אנא בדוק את חיבור הרשת ואת כתובת ה-API", + "serverError": "שגיאת שרת, אנא נסה שוב מאוחר יותר", + "unauthorized": "האימות נכשל, מפתח ה-API אינו חוקי או פג תוקף" + }, + "addCustomProvider": { + "title": "הוסף ספק מותאם אישית", + "description": "אנא מלא את המידע הדרוש עבור הספק", + "name": "שם", + "namePlaceholder": "אנא הזן את שם הספק", + "apiType": "סוג API", + "apiTypePlaceholder": "אנא בחר את סוג ה-API", + "apiKey": "מפתח API", + "apiKeyPlaceholder": "אנא הזן את מפתח ה-API", + "baseUrl": "כתובת בסיס ל-API", + "baseUrlPlaceholder": "אנא הזן את כתובת הבסיס ל-API", + "enable": "הפעל ספק" + }, + "deleteProvider": { + "title": "אשר מחיקת ספק", + "content": "האם אתה בטוח שברצונך למחוק את הספק \"{name}\"? לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "deleteModel": { + "title": "אשר מחיקת מודל", + "content": "האם אתה בטוח שברצונך למחוק את המודל \"{name}\"? לא ניתן לבטל פעולה זו.", + "confirm": "מחק" + }, + "pullModel": { + "title": "משיכת מודל (Pull)", + "description": "בחר מודלים להורדה מקומית", + "pull": "משוך" + }, + "modelCheck": { + "title": "בדיקת מודל", + "description": "בחר מודל לבדיקת קישוריות וזמינות", + "model": "בחר מודל", + "modelPlaceholder": "אנא בחר מודל לבדיקה", + "test": "התחל בדיקה", + "checking": "בודק...", + "success": "בדיקת המודל הצליחה", + "failed": "בדיקת המודל נכשלה", + "noModels": "אין מודלים זמינים עבור ספק זה" + } + }, + "pullModels": "משוך מודלים", + "refreshModels": "רענן מודלים", + "modelsRunning": "מודלים רצים", + "runningModels": "מודלים רצים", + "noRunningModels": "אין מודלים רצים", + "deleteModel": "מחק מודל", + "deleteModelConfirm": "האם אתה בטוח שברצונך למחוק את המודל \"{name}\"? לא ניתן לבטל פעולה זו.", + "noLocalModels": "אין מודלים מקומיים", + "localModels": "מודלים מקומיים", + "azureApiVersion": "גרסת API", + "safety": { + "title": "הגדרות בטיחות", + "blockHighest": "חסום סיכון גבוה", + "blockMost": "חסום סיכון בינוני", + "blockNone": "לא נחסם", + "blockSome": "חסום סיכון נמוך" + }, + "serverList": "רשימת שרתים", + "totalServers": "סה\"כ שרתים", + "addServer": "הוסף שרת", + "autoStart": "הפעלה אוטומטית", + "githubCopilotAuth": "אימות GitHub Copilot", + "githubCopilotConnected": "GitHub Copilot מחובר", + "githubCopilotNotConnected": "GitHub Copilot אינו מחובר", + "loginWithGitHub": "התחבר עם GitHub", + "loggingIn": "מתחבר...", + "githubCopilotLoginTip": "אשר ל-DeepChat לגשת למנוי GitHub Copilot שלך. ההרשאות 'read:user' ו-'read:org' נדרשות כדי לגשת ל-API של Copilot.", + "loginSuccess": "ההתחברות הצליחה", + "loginFailed": "ההתחברות נכשלה", + "tokenValid": "הטוקן תקין", + "tokenInvalid": "הטוקן אינו תקין", + "disconnect": "התנתק", + "disconnected": "נותק בהצלחה", + "disconnectFailed": "הניתוק נכשל", + "keyStatus": { + "remaining": "מכסה נותרת", + "usage": "בשימוש" + }, + "refreshingModels": "מרענן...", + "toast": { + "modelRunning": "המודל פועל", + "modelRunningDesc": "אנא עצור את המודל {model} תחילה ואז מחק אותו.", + "backupSuccessTitle": "הגיבוי הושלם", + "backupSuccessMessage": "הגיבוי נשמר ב-{time} ({size})", + "importSuccessTitle": "הייבוא הושלם", + "importSuccessMessage": "יובאו בהצלחה {count} שיחות" + }, + "modelscope": { + "mcpSync": { + "title": "סנכרן שירותי MCP", + "description": "סנכרן שרתי MCP מ-ModelScope לתצורה המקומית, מה שמאפשר הוספה מהירה של כלי MCP נפוצים.", + "sync": "התחל סנכרון", + "syncing": "מסנכרן...", + "pageSize": "גודל עמוד", + "imported": "יובאו {count} שירותים", + "skipped": "דולגו {count} שירותים", + "errors": "{count} שגיאות", + "errorDetails": "פרטי שגיאה", + "noApiKey": "אנא הגדר מפתח API של ModelScope תחילה", + "noServersFound": "לא נמצאו שירותי MCP זמינים", + "authenticationFailed": "האימות נכשל, אנא בדוק את מפתח ה-API", + "convertingServers": "ממיר תצורת שרת...", + "fetchingServers": "מקבל את רשימת שרתי ה-MCP...", + "importingServers": "מייבא תצורת שרת...", + "noOperationalUrls": "לא נמצאה כתובת הפעלה זמינה", + "pageNumber": "מספר עמוד", + "pageNumberPlaceholder": "אנא הזן את מספר העמוד", + "serverAlreadyExists": "השרת כבר קיים, מדלג על ייבוא", + "syncComplete": "הסנכרון הושלם", + "invalidServerData": "נתוני שרת לא חוקיים" + }, + "apiKey": "מפתח API", + "apiKeyHelper": "קבל את מפתח ה-API שלך במסוף ModelScope", + "apiKeyPlaceholder": "אנא הזן מפתח API של ModelScope", + "baseUrl": "כתובת API", + "baseUrlHelper": "כתובת שירות ה-API של ModelScope", + "connected": "מחובר", + "connecting": "מתחבר...", + "description": "ModelScope היא פלטפורמת שיתוף מודל-כשירות שהושקה על ידי Alibaba Damo Academy", + "details": { + "apiConfig": "תצורת API", + "mcpSync": "סנכרון MCP", + "modelManagement": "ניהול מודלים", + "operationalDescription": "סנכרן שרתי MCP שניתן להשתמש בהם ישירות בפלטפורמת ModelScope", + "operationalServers": "שרתים פועלים", + "rateLimitConfig": "תצורת מגבלת קצב", + "safetySettings": "הגדרות אבטחה", + "specialConfig": "תצורה מיוחדת", + "syncFromModelScope": "סנכרן מ-ModelScope", + "title": "פרטי הגדרות ספק" + }, + "invalidKey": "מפתח API לא חוקי", + "keyRequired": "אנא הזן מפתח API", + "name": "ModelScope", + "networkError": "שגיאת חיבור רשת", + "notConnected": "לא מחובר", + "verifyFailed": "האימות נכשל", + "verifySuccess": "האימות הצליח" + }, + "anthropicApiKeyTip": "אנא עבור למסוף Anthropic כדי לקבל את מפתח ה-API שלך", + "anthropicConnected": "Anthropic מחובר", + "anthropicNotConnected": "Anthropic אינו מחובר", + "anthropicOAuthTip": "לחץ כדי לאשר ל-DeepChat לגשת לחשבון Anthropic שלך", + "oauthLogin": "התחברות OAuth", + "authMethod": "שיטת אימות", + "authMethodPlaceholder": "בחר שיטת אימות", + "apiKeyLabel": "מפתח API", + "apiUrlLabel": "כתובת API", + "anthropicOAuthFlowTip": "המערכת תפתח אוטומטית את חלון האישור. אנא חזור והזן את קוד האישור לאחר האישור.", + "anthropicBrowserOpened": "הדפדפן החיצוני פתוח", + "anthropicCodeInstruction": "אנא השלם את האישור בדפדפן החיצוני והדבק את קוד האישור שהתקבל בתיבת הקלט למטה", + "browserOpenedSuccess": "הדפדפן החיצוני נפתח, אנא השלם את האישור", + "codeRequired": "אנא הזן את קוד האישור", + "inputOAuthCode": "הזן את קוד האישור", + "codeExchangeFailed": "החלפת קוד האישור נכשלה", + "invalidCode": "קוד אישור לא חוקי", + "oauthCodeHint": "אנא הדבק את קוד האישור כאן לאחר השלמת האישור בדפדפן חיצוני", + "oauthCodePlaceholder": "אנא הזן את קוד האישור...", + "verifyConnection": "אמת חיבור", + "manageModels": "נהל מודלים", + "anthropicOAuthActiveTip": "אימות OAuth מופעל, ניתן להשתמש בשירותי Anthropic ישירות", + "oauthVerifySuccess": "חיבור OAuth אומת בהצלחה", + "oauthVerifyFailed": "אימות חיבור OAuth נכשל", + "configurationSaved": "התצורה נשמרה", + "configurationUpdated": "התצורה עודכנה", + "dataRefreshed": "הנתונים רועננו", + "operationFailed": "הפעולה נכשלה", + "operationSuccess": "הפעולה הצליחה", + "settingsApplied": "ההגדרות הוחלו", + "bedrockLimitTip": "* נתמך רק עבור Anthropic Claude (כולל מודלי Opus, Sonnet, Haiku)", + "bedrockVerifyTip": "DeepChat משתמש ב-Claude 3.5 Sonnet לאימות. אם אין לך הרשאה להפעיל אותו, האימות ייכשל. זה לא ישפיע על השימוש במודלים אחרים." + }, + "knowledgeBase": { + "title": "הגדרות בסיס ידע", + "addKnowledgeBase": "הוסף בסיס ידע", + "selectKnowledgeBaseType": "אנא בחר את סוג בסיס הידע להוספה", + "difyDescription": "בסיס ידע Dify עוזר לך לנהל ולהשתמש בנתוני מסמכים", + "comingSoon": "בקרוב", + "featureNotAvailable": "תכונה זו אינה זמינה עדיין", + "addDifyConfig": "הוסף תצורת Dify", + "apiKey": "מפתח API", + "datasetId": "מזהה ערכת נתונים (Dataset ID)", + "endpoint": "נקודת קצה (API Endpoint)", + "configAdded": "תצורה נוספה", + "configAddedDesc": "תצורת {name} נוספה בהצלחה", + "addConfig": "הוסף תצורה", + "moreComingSoon": "סוגי בסיסי ידע נוספים יגיעו בקרוב", + "configUpdated": "תצורה עודכנה", + "configUpdatedDesc": "תצורת {name} עודכנה בהצלחה", + "descriptionPlaceholder": "דוגמה: בסיס ידע לתיעוד מוצרי החברה", + "ragflowTitle": "בסיס ידע RAGFlow", + "ragflowDescription": "RAGFlow היא מערכת ניהול בסיס ידע חזקה התומכת בשיטות אחזור מרובות ותכונות ניהול מסמכים.", + "addRagflowConfig": "הוסף תצורת RAGFlow", + "editRagflowConfig": "ערוך תצורת RAGFlow", + "dify": "בסיס ידע Dify", + "editDifyConfig": "שנה את תצורת Dify", + "fastgptTitle": "בסיס ידע FastGPT", + "fastgptDescription": "FastGPT היא מערכת ניהול בסיס ידע חזקה התומכת בשיטות אחזור מרובות ותכונות ניהול מסמכים.", + "addFastGptConfig": "הוסף תצורת FastGPT", + "editFastGptConfig": "ערוך תצורת FastGPT", + "builtInKnowledgeDescription": "בסיס הידע המובנה מספק יישומים פשוטים המאפשרים פונקציות בסיסיות בסביבה לא מקוונת.", + "builtInKnowledgeTitle": "בסיס ידע מובנה", + "addBuiltinKnowledgeConfig": "הוסף תצורת בסיס ידע מובנה", + "editBuiltinKnowledgeConfig": "ערוך את תצורת בסיס הידע המובנה", + "chunkSize": "גודל מקטע (Chunk)", + "chunkSizeHelper": "חתוך את המסמך למקטעים, גודל כל מקטע לא יכול לעלות על מגבלת ההקשר של המודל", + "chunkOverlap": "גודל חפיפה", + "chunkOverlapHelper": "כמות התוכן החוזר בין מקטעי טקסט סמוכים מבטיחה שעדיין קיים הקשר בין מקטעי טקסט מפוצלים, ומשפרת את האפקט הכולל של עיבוד המודל לטקסטים ארוכים", + "selectEmbeddingModel": "בחר מודל הטמעה (Embedding)", + "modelNotFound": "ספק השירות {provider} או המודל {model} לא נמצאו", + "modelNotFoundDesc": "ודא שהמודל מוגדר כראוי ושמודל זה מופעל. \nתוכל לבדוק את תצורת המודל בהגדרות ספק השירות.", + "removeBuiltinKnowledgeConfirmDesc": "מחיקת תצורת בסיס הידע המובנה תמחק את כל הנתונים הרלוונטיים ולא ניתן לשחזרם. אנא היזהר.", + "removeBuiltinKnowledgeConfirmTitle": "האם לאשר את מחיקת בסיס הידע המובנה {name}?", + "descriptionDesc": "תיאור בסיס הידע כך שה-AI יחליט אם לאחזר בסיס ידע זה", + "advanced": "אפשרויות מתקדמות", + "autoDetectDimensions": "זהה אוטומטית ממדים מוטמעים", + "autoDetectHelper": "מזהה אוטומטית ממדים מוטמעים, צורך כמות קטנה של טוקנים", + "chunkOverlapPlaceholder": "ערך ברירת מחדל, לא מומלץ לשנות", + "chunkSizePlaceholder": "ערך ברירת מחדל, לא מומלץ לשנות", + "dimensions": "ממדי הטמעה (Embed dimensions)", + "dimensionsPlaceholder": "גודל ממד הטמעה, כגון 1024", + "selectEmbeddingModelHelper": "מודלי הטמעה אסורים לשינוי לאחר יצירת בסיס הידע", + "dimensionsHelper": "ודא שהמודל תומך בגודל ממד ההטמעה שהוגדר", + "autoDetectDimensionsError": "זיהוי אוטומטי של ממד מוטמע נכשל", + "fragmentsNumber": "מספר מקטעי מסמך מבוקשים", + "fragmentsNumberHelper": "ככל שמבוקשים יותר מקטעי מסמך, כך מתקבל יותר מידע, אך נדרשים יותר טוקנים לצריכה", + "selectRerankModel": "בחר את מודל הדירוג מחדש (Rerank)", + "rerankModel": "מודל דירוג מחדש", + "embeddingModel": "מודל הטמעה", + "return": "חזור", + "uploadHelper": "לחץ להעלאה או גרור את הקובץ לכאן", + "fileSupport": "תומך ב-{accept} וב-{count} פורמטים נוספים", + "searchKnowledge": "חפש בבסיס הידע", + "searchKnowledgePlaceholder": "אנא הזן את תוכן השאילתה", + "noData": "אין נתונים עדיין", + "file": "מסמך", + "uploadProcessing": "מעלה", + "uploadCompleted": "ההעלאה הושלמה", + "reAdd": "העלה מחדש", + "uploadError": "ההעלאה נכשלה", + "delete": "מחק", + "reason": "סיבה", + "deleteSuccess": "נמחק בהצלחה", + "copy": "העתק", + "copySuccess": "הועתק בהצלחה", + "source": "מקור", + "normalized": "נרמול L2", + "normalizedHelper": "אנא ודא שהמודל תומך בנרמול L2 של וקטורי פלט", + "dialog": { + "beforequit": { + "cancel": "ביטול", + "confirm": "אשר", + "title": "אישור יציאה", + "description": "ישנה משימת בסיס ידע שפועלת. האם אתה בטוח שברצונך לצאת מהתוכנה? \nניתן לשחזר משימות שהופסקו לאחר הפעלת התוכנה מחדש." + } + }, + "searchError": "השאילתה נכשלה", + "processing": "מעלה", + "paused": "העלאה מושהית", + "unknown": "סטטוס לא ידוע", + "reAddFile": { + "title": "אישור העלאה מחדש", + "content": "האם אתה בטוח שברצונך להעלות מחדש את הקובץ \"{fileName}\"?" + }, + "nowledgeMem": { + "title": "ייצוא ל-Nowledge Mem", + "description": "ייצוא שיחות לשירות Nowledge Mem.", + "testConnection": "בדוק חיבור", + "configuration": "תצורה", + "baseUrl": "כתובת בסיס (Base URL)", + "apiKey": "מפתח API", + "apiKeyHint": "אופציונלי. אם השירות שלך דורש מפתח API, הזן אותו כאן.", + "timeout": "פסק זמן (Timeout)", + "saveConfig": "שמור", + "resetConfig": "אפס", + "seconds": "שניות" + }, + "deleteFile": { + "title": "אישור מחיקת קובץ", + "content": "האם אתה בטוח שברצונך למחוק את הקובץ \"{fileName}\"? \nפעולה זו אינה ניתנת לשחזור." + }, + "resumeAllPausedTasks": "שחזור בלחיצה אחת", + "pauseAllRunningTasks": "השהייה בלחיצה אחת", + "separators": "מפריד מקטעים", + "separatorsHelper": "מפריד פיצול מסמכים, מפריד בודד מוקף במרכאות כפולות (\"\"), ומפרידים מופרדים בפסיקים (,)", + "invalidSeparators": "מפריד לא חוקי", + "selectLanguage": "בחר הגדרה מוגדרת מראש", + "separatorsPreset": "טוען הגדרות מוגדרות מראש" + }, + "mcp": { + "title": "הגדרות MCP", + "description": "ניהול והגדרה של שרתי וכלים של MCP (Model Context Protocol)", + "enabledTitle": "הפעל את MCP", + "enabledDescription": "הפעל או השבת פונקציונליות וכלים של MCP", + "enableToAccess": "אנא הפעל את MCP כדי לגשת לאפשרויות התצורה", + "marketplace": "עבור לחנות MCP להתקנה בלחיצה אחת", + "technicalDetails": "פרטים טכניים", + "httpServer": "שרת HTTP", + "localProcess": "תהליך מקומי", + "restartServer": "הפעל מחדש שרת", + "viewLogs": "צפה בלוגים", + "starting": "מתחיל", + "error": "שגיאה", + "tabs": { + "servers": "שרתים", + "tools": "כלים", + "prompts": "הנחיות (Prompts)", + "resources": "משאבים" + }, + "serverList": "רשימת שרתים", + "totalServers": "סה\"כ שרתים", + "addServer": "הוסף שרת", + "running": "פועל", + "stopped": "נעצר", + "stopServer": "עצור שרת", + "startServer": "התחל שרת", + "noServersFound": "לא נמצאו שרתים", + "addServerDialog": { + "title": "הוסף שרת", + "description": "הגדר שרת MCP חדש" + }, + "editServerDialog": { + "title": "ערוך שרת", + "description": "ערוך תצורת שרת MCP" + }, + "serverForm": { + "name": "שם השרת", + "namePlaceholder": "הזן את שם השרת", + "nameRequired": "שם השרת נדרש", + "type": "סוג שרת", + "typePlaceholder": "בחר סוג שרת", + "typeStdio": "קלט ופלט סטנדרטי (Stdio)", + "typeSse": "אירועים הנשלחים מהשרת (SSE)", + "typeInMemory": "בזיכרון (In-Memory)", + "typeHttp": "בקשות HTTP זורמות (HTTP)", + "baseUrl": "כתובת בסיס (Base URL)", + "baseUrlPlaceholder": "הזן את כתובת הבסיס של השרת (לדוגמה: http://localhost:3000)", + "command": "פקודה", + "commandPlaceholder": "הזן פקודה", + "commandRequired": "פקודה נדרשת", + "args": "ארגומנטים", + "argsPlaceholder": "הזן ארגומנט אחד בכל שורה", + "addArg": "הוסף ארגומנט", + "argPlaceholder": "הזן ערך ארגומנט", + "argsRequired": "ארגומנטים נדרשים", + "env": "משתני סביבה", + "envPlaceholder": "הזן משתני סביבה בפורמט JSON", + "envInvalid": "משתני סביבה חייבים להיות JSON חוקי", + "description": "תיאור", + "descriptionPlaceholder": "הזן את תיאור השרת", + "descriptions": "תיאור", + "descriptionsPlaceholder": "הזן את תיאור השרת", + "icon": "אייקון", + "iconPlaceholder": "הזן אייקון", + "icons": "אייקון", + "iconsPlaceholder": "הזן אייקון", + "autoApprove": "אישור אוטומטי", + "autoApproveAll": "הכל", + "autoApproveRead": "קריאה", + "autoApproveWrite": "כתיבה", + "autoApproveHelp": "בחר סוגי פעולות לאישור אוטומטי ללא אישור המשתמש", + "submit": "שלח", + "add": "הוסף", + "update": "עדכן", + "cancel": "ביטול", + "jsonConfigIntro": "אתה יכול להדביק תצורת JSON ישירות או לבחור להגדיר את השרת באופן ידני.", + "jsonConfig": "תצורת JSON", + "jsonConfigPlaceholder": "הדבק את תצורת שרת MCP שלך בפורמט JSON", + "jsonConfigExample": "דוגמה לתצורת JSON", + "parseSuccess": "התצורה פוענחה", + "configImported": "התצורה יובאה בהצלחה", + "parseError": "שגיאת פענוח", + "skipToManual": "דלג להגדרה ידנית", + "parseAndContinue": "פענח והמשך", + "jsonParseError": "פענוח JSON נכשל", + "browseMarketplace": "עיין בחנות MCP", + "imageModel": "בחר מודל ראייה", + "customHeadersParseError": "פענוח כותרות מותאמות אישית נכשל", + "customHeaders": "כותרות בקשה מותאמות אישית", + "clickToEdit": "לחץ לעריכה וצפייה בתוכן המלא", + "invalidKeyValueFormat": "פורמט כותרת בקשה שגוי, אנא בדוק אם הקלט תקין.", + "npmRegistry": "NPM Registry מותאם אישית", + "npmRegistryPlaceholder": "הגדר NPM Registry מותאם אישית, השאר ריק כדי שהמערכת תבחר אוטומטית את המהיר ביותר", + "browseHigress": "צפה בחנות Higress MCP", + "selectFolderError": "שגיאה בבחירת תיקייה", + "folders": "תיקיות מותרות", + "addFolder": "הוסף תיקייה", + "noFoldersSelected": "לא נבחרו תיקיות", + "useE2B": "הפעל ארגז חול E2B", + "e2bDescription": "הרץ קוד Python באמצעות ארגז החול של E2B", + "e2bApiKey": "E2B ApiKey", + "e2bApiKeyPlaceholder": "הזן את מפתחות ה-API של E2B כאן, למשל e2b_1111xx*******", + "e2bApiKeyHelp": "עבור ל-e2b.dev כדי לקבל את ה-ApiKey שלך", + "e2bApiKeyRequired": "חובה להזין ApiKey כדי להפעיל את פונקציית E2B" + }, + "deleteServer": "מחק שרת", + "editServer": "ערוך שרת", + "setDefault": "הגדר כברירת מחדל", + "removeDefault": "הסר ברירת מחדל", + "isDefault": "שרת ברירת מחדל", + "default": "ברירת מחדל", + "setAsDefault": "הגדר כברירת מחדל", + "removeServer": "הסר שרת", + "autoStart": "הפעלה אוטומטית", + "confirmRemoveServer": "האם אתה בטוח שברצונך למחוק את השרת {name}? לא ניתן לבטל פעולה זו.", + "removeServerDialog": { + "title": "מחק שרת" + }, + "confirmDelete": { + "title": "אשר מחיקה", + "description": "האם אתה בטוח שברצונך למחוק את השרת {name}? לא ניתן לבטל פעולה זו.", + "confirm": "מחק", + "cancel": "ביטול" + }, + "resetToDefault": "אפס לברירת מחדל", + "resetConfirmTitle": "אפס לשרתי ברירת המחדל", + "resetConfirmDescription": "פעולה זו תשחזר את כל שרתי ברירת המחדל תוך שמירה על השרתים המותאמים אישית שלך. כל שינוי בשרתי ברירת המחדל יאבד.", + "resetConfirm": "אפס", + "builtInServers": "שרתים מובנים", + "customServers": "שרתים מותאמים אישית", + "builtIn": "מובנה", + "cannotRemoveBuiltIn": "לא ניתן להסיר שרת מובנה", + "builtInServerCannotBeRemoved": "לא ניתן להסיר שרתים מובנים, ניתן לשנות רק פרמטרים ומשתני סביבה", + "maxDefaultServersReached": "ניתן להגדיר לכל היותר 3 שרתי ברירת מחדל", + "removeDefaultFirst": "אנא הסר תחילה מספר שרתי ברירת מחדל", + "higressMarket": "עבור להתקנת Higress MCP", + "npmRegistry": { + "title": "תצורת NPM Registry", + "currentSource": "מקור נוכחי", + "cached": "במטמון", + "lastChecked": "נבדק לאחרונה", + "refresh": "רענן", + "advanced": "מתקדם", + "advancedSettings": "הגדרות מתקדמות", + "advancedSettingsDesc": "הגדר אפשרויות מתקדמות של NPM registry, כולל זיהוי אוטומטי והגדרות מקור מותאמות אישית", + "autoDetect": "זהה אוטומטית מקור אופטימלי", + "autoDetectDesc": "מזהה ומשתמש אוטומטית ב-NPM registry המהיר ביותר בעת ההפעלה", + "customSource": "מקור מותאם אישית", + "customSourcePlaceholder": "הזן כתובת URL של NPM registry מותאם אישית", + "currentCustom": "מקור מותאם אישית נוכחי", + "justNow": "ממש עכשיו", + "minutesAgo": "לפני {minutes} דקות", + "hoursAgo": "לפני {hours} שעות", + "daysAgo": "לפני {days} ימים", + "refreshSuccess": "NPM registry רוענן בהצלחה", + "refreshSuccessDesc": "זוהה ועודכן ה-NPM registry האופטימלי", + "refreshFailed": "רענון NPM registry נכשל", + "autoDetectUpdated": "הגדרת זיהוי אוטומטי עודכנה", + "autoDetectEnabled": "זיהוי אוטומטי של NPM registry אופטימלי הופעל", + "autoDetectDisabled": "זיהוי אוטומטי מושבת, ישתמש ב-registry ברירת המחדל", + "updateFailed": "עדכון ההגדרה נכשל", + "customSourceSet": "מקור מותאם אישית הוגדר", + "customSourceSetDesc": "NPM registry מותאם אישית הוגדר: {registry}", + "customSourceCleared": "מקור מותאם אישית נוקה", + "customSourceClearedDesc": "NPM registry מותאם אישית נוקה, ישתמש בזיהוי אוטומטי", + "invalidUrl": "כתובת URL לא חוקית", + "invalidUrlDesc": "אנא הזן כתובת HTTP או HTTPS תקינה", + "testing": "בודק NPM registry", + "testingDesc": "בודק קישוריות ל-{registry}...", + "testFailed": "בדיקת NPM registry נכשלה", + "testFailedDesc": "לא ניתן להתחבר ל-{registry}, שגיאה: {error}. אנא בדוק אם הכתובת נכונה או בדוק את חיבור הרשת.", + "redetectingOptimal": "מזהה מחדש NPM registry אופטימלי...", + "redetectComplete": "זיהוי מחדש הושלם", + "redetectCompleteDesc": "זוהה והוגדר ה-NPM registry האופטימלי הנוכחי", + "redetectFailed": "זיהוי מחדש נכשל", + "redetectFailedDesc": "לא ניתן לזהות מחדש registry אופטימלי, ישתמש בתצורת ברירת המחדל" + } + }, + "about": { + "title": "אודותינו", + "version": "גרסה", + "checkUpdate": "בדוק עדכון", + "checking": "בודק...", + "latestVersion": "גרסה אחרונה" + }, + "display": { + "fontSize": "גודל טקסט", + "text-sm": "קטן", + "text-base": "בינוני", + "text-lg": "גדול", + "text-xl": "גדול מאוד", + "text-2xl": "ענק", + "floatingButton": "כפתור צף", + "floatingButtonDesc": "הצג כפתור צף על שולחן העבודה להפעלה מהירה של חלון האפליקציה" + }, + "shortcuts": { + "title": "הגדרות קיצורי מקשים", + "pressKeys": "לחץ על מקשים", + "pressEnterToSave": "לחץ Enter לשמירה, Esc לביטול", + "noModifierOnly": "לא ניתן להשתמש במקש שינוי (Modifier) בלבד כקיצור דרך", + "keyConflict": "התנגשות מקשי קיצור, אנא בחר שילוב אחר", + "clearShortcut": "נקה קיצור דרך", + "cleanHistory": "נקה היסטוריית צ'אט", + "deleteConversation": "מחק שיחה", + "goSettings": "פתח הגדרות", + "hideWindow": "הסתר חלון", + "quitApp": "צא מהאפליקציה", + "zoomIn": "הגדל תצוגה ", + "zoomOut": "הקטן תצוגה ", + "zoomReset": "אפס תצוגה", + "closeTab": "סגור את הכרטיסייה הנוכחית", + "newTab": "צור כרטיסייה חדשה", + "newWindow": "פתח חלון חדש", + "showHideWindow": "הצג/הסתר חלון", + "newConversation": "שיחה חדשה", + "nextTab": "עבור לכרטיסייה הבאה", + "previousTab": "עבור לכרטיסייה הקודמת", + "specificTab": "עבור לכרטיסייה מסוימת (1-8)", + "lastTab": "עבור לכרטיסייה האחרונה" + }, + "acp": { + "title": "סוכני ACP", + "description": "ניהול סוכני ACP מקומיים (Agent Client Protocol) המופעלים על ידי DeepChat.", + "enabledTitle": "הפעל את ACP", + "enabledDescription": "כאשר מופעל, סוכני ACP מוגדרים יופיעו כמודלים בבוחר.", + "useBuiltinRuntimeTitle": "השתמש בסביבת הרצה מובנית של DeepChat", + "useBuiltinRuntimeDescription": "כאשר מופעל, עוקף פקודות node ו-uv של המערכת, ומשתמש בגרסאות המצורפות ל-DeepChat.", + "enableToAccess": "הפעל את ACP כדי להגדיר סוכנים.", + "addCustomAgent": "הוסף סוכן מותאם אישית", + "customEmpty": "אין סוכנים מותאמים אישית עדיין.", + "customDeleteConfirm": "למחוק את הסוכן המותאם אישית \"{name}\"?", + "builtinSectionTitle": "סוכנים מובנים", + "builtinSectionDescription": "לכל סוכן מובנה יכולים להיות מספר פרופילי הפעלה. רק סוכנים מופעלים עם פרופיל פעיל מופיעים ברשימת המודלים.", + "builtinHint": "הפעל את {name} עם הגדרות אלה.", + "disabledBadge": "מושבת", + "manageProfiles": "נהל פרופילים", + "addProfile": "הוסף פרופיל", + "activeProfile": "פרופיל פעיל", + "profilePlaceholder": "בחר פרופיל", + "profileSwitched": "פרופיל הוחלף", + "customSectionTitle": "סוכנים מותאמים אישית", + "customSectionDescription": "עטוף כל פקודה תואמת ACP כרשומת מודל לשימוש חוזר.", + "loading": "טוען נתוני ACP...", + "none": "ללא", + "saveSuccess": "התצורה נשמרה", + "saveFailed": "שמירת הסוכן נכשלה", + "deleteSuccess": "נמחק בהצלחה", + "initialize": "אתחל", + "initializing": "מאתחל...", + "initializeDescription": "טרמינל נפתח עם פקודות אתחול", + "initializeSuccess": "האתחול התחיל", + "initializeFailed": "האתחול נכשל", + "missingFieldsTitle": "שם ופקודה הם חובה", + "missingFieldsDesc": "אנא מלא גם שם וגם פקודה לפני השמירה.", + "command": "פקודה", + "commandPlaceholder": "נתיב קובץ הפעלה או סקריפט", + "args": "ארגומנטים", + "argsPlaceholder": "אופציונלי, מופרדים ברווחים. השתמש במרכאות כדי לשמור על ארגומנטים יחד.", + "env": "משתני סביבה", + "addEnv": "הוסף משתנה", + "envKeyPlaceholder": "מפתח (KEY)", + "envValuePlaceholder": "ערך (VALUE)", + "profileDialog": { + "addBuiltinTitle": "הוסף פרופיל {name}", + "editBuiltinTitle": "ערוך פרופיל {name}", + "addCustomTitle": "הוסף סוכן מותאם אישית", + "editCustomTitle": "ערוך סוכן מותאם אישית", + "builtinHint": "השתמש בהגדרות קבועות מראש שונות לכל תרחיש והחלף ביניהן בבוחר.", + "customHint": "ספק את הפקודה, הארגומנטים ומשתני הסביבה כדי להפעיל את הסוכן שלך.", + "profileName": "שם הפרופיל", + "profileNamePlaceholder": "לדוגמה: תחנת עבודה", + "agentName": "שם הסוכן", + "agentNamePlaceholder": "לדוגמה: ה-ACP המקומי שלי" + }, + "profileManager": { + "title": "פרופילים", + "description": "החלף, ערוך או מחק פרופילי הפעלה שמורים.", + "count": "{count} פרופילים", + "empty": "אין פרופילים עדיין.", + "active": "פעיל", + "setActive": "הגדר כפעיל", + "deleteConfirm": "למחוק את הפרופיל \"{name}\"?", + "cannotDeleteTitle": "השאר לפחות פרופיל אחד", + "cannotDeleteDesc": "סוכנים מובנים דורשים לפחות תצורה אחת.", + "noAgent": "בחר סוכן כדי לנהל את הפרופילים שלו." + }, + "terminal": { + "title": "טרמינל אתחול", + "waiting": "ממתין לתחילת האתחול...", + "starting": "מתחיל אתחול...", + "close": "סגור", + "closing": "סוגר...", + "exitSuccess": "התהליך הושלם בהצלחה (קוד יציאה: {code})", + "exitError": "התהליך יצא עם שגיאה (קוד יציאה: {code})", + "processError": "שגיאת תהליך", + "paste": "הדבק", + "pasteError": "ההדבקה מהלוח נכשלה", + "status": { + "idle": "בהמתנה", + "running": "פועל", + "completed": "הושלם", + "error": "שגיאה" + } + }, + "dependency": { + "title": "תלויות חיצוניות חסרות", + "description": "יש להתקין את התלויות הבאות לפני האתחול.", + "installCommands": "פקודות התקנה", + "downloadUrl": "קישור להורדה", + "copy": "העתק", + "copied": "הועתק ללוח", + "copyFailed": "ההעתקה נכשלה" + } + }, + "rateLimit": { + "title": "מגבלת קצב (Rate Limit)", + "description": "שלוט במרווח הבקשות כדי למנוע חריגה ממגבלות ה-API", + "intervalLimit": "מרווח בקשות", + "intervalUnit": "שניות", + "intervalHelper": "מרווח מינימלי בין בקשות, השבת את מגבלת הקצב אם אין צורך", + "lastRequestTime": "בקשה אחרונה", + "queueLength": "אורך תור", + "nextAllowedTime": "הבא מותר", + "never": "מעולם לא", + "justNow": "ממש עכשיו", + "secondsAgo": "לפני שניות", + "minutesAgo": "לפני דקות", + "immediately": "עכשיו", + "secondsLater": "שניות מאוחר יותר", + "confirmDisableTitle": "אשר ביטול מגבלת קצב", + "confirmDisableMessage": "הערך לא יכול להיות קטן או שווה ל-0. האם ברצונך לבטל את מגבלת הקצב?", + "confirmDisable": "בטל מגבלה", + "disabled": "מגבלת קצב מושבתת", + "disabledDescription": "מגבלת הקצב הושבתה" + }, + "promptSetting": { + "resetToDefault": "אפס להנחיית ברירת מחדל", + "resetToDefaultSuccess": "איפוס להנחיית מערכת ברירת מחדל הצליח", + "resetToDefaultFailed": "האיפוס נכשל, אנא נסה שוב" + } +} diff --git a/src/renderer/src/i18n/he-IL/sync.json b/src/renderer/src/i18n/he-IL/sync.json new file mode 100644 index 000000000..e641785a2 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/sync.json @@ -0,0 +1,17 @@ +{ + "success": { + "importComplete": "יובאו בהצלחה {count} שיחות. היישום יופעל מחדש כעת." + }, + "error": { + "notEnabled": "הסנכרון אינו מופעל", + "folderNotExists": "תיקיית הסנכרון אינה קיימת", + "noValidBackup": "לא נמצאו קבצי גיבוי תקינים בתיקיית הסנכרון.", + "dbNotExists": "קובץ מסד הנתונים אינו קיים", + "configNotExists": "קובץ התצורה אינו קיים", + "tempDbFailed": "נכשל ביצירת קובץ גיבוי זמני למסד הנתונים", + "tempConfigFailed": "נכשל ביצירת קובץ גיבוי זמני לתצורה", + "importFailed": "הייבוא נכשל, הנתונים המקוריים שוחזרו", + "importProcess": "אירעה שגיאה במהלך תהליך הייבוא", + "unknown": "שגיאה לא ידועה" + } +} diff --git a/src/renderer/src/i18n/he-IL/thread.json b/src/renderer/src/i18n/he-IL/thread.json new file mode 100644 index 000000000..da2240d9b --- /dev/null +++ b/src/renderer/src/i18n/he-IL/thread.json @@ -0,0 +1,46 @@ +{ + "actions": { + "rename": "שנה שם", + "delete": "מחק", + "cleanMessages": "נקה הודעות", + "pin": "נעץ", + "unpin": "בטל נעיצה", + "export": "ייצוא", + "exportText": "טקסט רגיל", + "exportNowledgeMem": "Nowledge-mem" + }, + "toolbar": { + "save": "שמור", + "cancel": "ביטול", + "previousVariant": "גרסה קודמת", + "nextVariant": "גרסה הבאה", + "copy": "העתק כ-Markdown", + "copyImage": "העתק כתמונה", + "copyImageWithLongPress": "העתק כתמונה (לחיצה ארוכה ללכידה מלמעלה)", + "copyFromTopSuccess": "תמונת השיחה המלאה הועתקה", + "capturing": "לוכד...", + "retry": "צור מחדש", + "fork": "צור ענף לשיחה חדשה", + "edit": "ערוך הודעה", + "delete": "מחק הודעה", + "trace": "עקוב אחר בקשה (Trace)" + }, + "message": { + "toolbar": { + "save": "שמור" + } + }, + "export": { + "failed": "הייצוא נכשל", + "failedDesc": "אירעה שגיאה במהלך תהליך הייצוא, אנא נסה שוב", + "success": "הייצוא הושלם בהצלחה", + "successDesc": "השיחה יוצאה בהצלחה", + "nowledgeMemSuccess": "ייצוא ל-Nowledge-mem הושלם בהצלחה", + "nowledgeMemSuccessDesc": "השיחה יוצאה בהצלחה לפורמט nowledge-mem", + "nowledgeMemSubmitPrompt": "האם ברצונך לשלוח שיחה זו ל-nowledge-mem?", + "nowledgeMemSubmitSuccess": "השליחה ל-Nowledge-mem הושלמה בהצלחה", + "nowledgeMemSubmitSuccessDesc": "השיחה נשלחה בהצלחה ל-nowledge-mem", + "nowledgeMemSubmitFailed": "השליחה ל-Nowledge-mem נכשלה", + "nowledgeMemSubmitFailedDesc": "נכשל בשליחת השיחה ל-nowledge-mem" + } +} diff --git a/src/renderer/src/i18n/he-IL/toolCall.json b/src/renderer/src/i18n/he-IL/toolCall.json new file mode 100644 index 000000000..9524fee9e --- /dev/null +++ b/src/renderer/src/i18n/he-IL/toolCall.json @@ -0,0 +1,19 @@ +{ + "calling": "קורא...", + "response": "רץ...", + "end": "בוצע", + "error": "שגיאה", + "title": "קריאה לכלי", + "clickToView": "לחץ לצפייה בפרטים", + "functionName": "שם הפונקציה", + "permission": "מבקש הרשאה...", + "params": "פרמטרי פונקציה", + "responseData": "תגובה", + "failed": "לְהִכָּשֵׁל", + "fileOperation": "פעולות קובץ", + "filePath": "נתיב הקובץ", + "fileRead": "לקרוא קובץ", + "fileWrite": "לכתוב קובץ", + "success": "הַצלָחָה", + "terminalOutput": "פלט מסוף" +} diff --git a/src/renderer/src/i18n/he-IL/traceDialog.json b/src/renderer/src/i18n/he-IL/traceDialog.json new file mode 100644 index 000000000..703332a23 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/traceDialog.json @@ -0,0 +1,17 @@ +{ + "title": "תצוגה מקדימה של הבקשה", + "provider": "ספק", + "model": "מודל", + "endpoint": "נקודת קצה (API Endpoint)", + "headers": "כותרות (Headers)", + "body": "גוף הבקשה (Body)", + "copyJson": "העתק JSON", + "copySuccess": "הועתק ללוח", + "close": "סגור", + "loading": "טוען...", + "error": "הטעינה נכשלה", + "errorDesc": "לא ניתן להביא תצוגה מקדימה של הבקשה, אנא נסה שוב", + "notImplemented": "לא נתמך", + "notImplementedDesc": "ספק זה טרם יישם תצוגה מקדימה של הבקשה", + "mayNotMatch": "הערה: תצוגה מקדימה זו משוחזרת מהגדרות השיחה הנוכחיות ועשויה שלא להתאים במדויק לפרמטרי הבקשה בפועל" +} diff --git a/src/renderer/src/i18n/he-IL/update.json b/src/renderer/src/i18n/he-IL/update.json new file mode 100644 index 000000000..1ca614070 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/update.json @@ -0,0 +1,16 @@ +{ + "newVersion": "גרסה חדשה נמצאה", + "version": "גרסה", + "releaseDate": "תאריך שחרור", + "releaseNotes": "הערות גרסה", + "later": "מאוחר יותר", + "githubDownload": "הורדה מ-GitHub", + "netdiskDownload": "הורדה מהענן", + "checkUpdate": "בדוק עדכונים", + "downloading": "מוריד", + "installNow": "התקן כעת", + "autoUpdate": "עדכון אוטומטי", + "restarting": "מפעיל מחדש", + "alreadyUpToDate": "התוכנה מעודכנת", + "alreadyUpToDateDesc": "ה-DeepChat שלך כבר מעודכן לגרסה האחרונה, אין צורך בעדכון." +} diff --git a/src/renderer/src/i18n/he-IL/welcome.json b/src/renderer/src/i18n/he-IL/welcome.json new file mode 100644 index 000000000..5d742a512 --- /dev/null +++ b/src/renderer/src/i18n/he-IL/welcome.json @@ -0,0 +1,37 @@ +{ + "steps": { + "welcome": { + "title": "ברוכים הבאים", + "description": "בוא נתחיל להגדיר את DeepChat" + }, + "provider": { + "title": "ספק", + "description": "בחר את ספק המודל המועדף עליך" + }, + "configuration": { + "title": "תצורה", + "description": "הגדר את המודלים שברצונך להשתמש בהם" + }, + "complete": { + "title": "סיום", + "description": "הכל מוכן ואפשר לצאת לדרך!" + } + }, + "title": "ברוכים הבאים ל-DeepChat", + "description": "בוא נעבור יחד על ההתקנה.", + "provider": { + "select": "בחר ספק", + "apiUrl": "כתובת API", + "apiKey": "מפתח API", + "verifyLink": "אמת קישור" + }, + "complete": { + "title": "סיימנו!", + "description": "אתה מוכן לשימוש. בוא נתחיל!" + }, + "buttons": { + "getStarted": "התחל", + "next": "הבא", + "back": "חזור" + } +} diff --git a/src/renderer/src/i18n/index.ts b/src/renderer/src/i18n/index.ts index 429e4ff46..12990b2c6 100644 --- a/src/renderer/src/i18n/index.ts +++ b/src/renderer/src/i18n/index.ts @@ -9,6 +9,7 @@ import frFR from './fr-FR' import faIR from './fa-IR' import ptBR from './pt-BR' import daDK from './da-DK' +import heIL from './he-IL' const locales = { 'zh-CN': zhCN, @@ -22,11 +23,13 @@ const locales = { 'fa-IR': faIR, 'pt-BR': ptBR, 'da-DK': daDK, + 'he-IL': heIL, zh: zhCN, en: enUS, fr: frFR, pt: ptBR, - da: daDK + da: daDK, + he: heIL } console.log('locales', locales) export default locales diff --git a/src/renderer/src/stores/language.ts b/src/renderer/src/stores/language.ts index 2a5377350..f6b38d2a5 100644 --- a/src/renderer/src/stores/language.ts +++ b/src/renderer/src/stores/language.ts @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n' import { usePresenter } from '@/composables/usePresenter' import { CONFIG_EVENTS } from '@/events' -const RTL_LIST = ['fa-IR'] +const RTL_LIST = ['fa-IR', 'he-IL'] export const useLanguageStore = defineStore('language', () => { const { locale } = useI18n({ useScope: 'global' }) const language = ref('system') From e99e536f0526b9305c7a435d563f0b42c62c7f44 Mon Sep 17 00:00:00 2001 From: duskzhen Date: Thu, 4 Dec 2025 18:23:13 +0800 Subject: [PATCH 2/7] feat: add workspace view to acp agents (#1158) * feat: add workspaceview for acp agent * feat: support workspace dirs * fix: workspace file refresh * fix: tool call status * fix: review refactor --- src/main/events.ts | 8 + .../acpWorkspacePresenter/directoryReader.ts | 133 +++++++++ .../presenter/acpWorkspacePresenter/index.ts | 112 ++++++++ .../acpWorkspacePresenter/planStateManager.ts | 119 ++++++++ src/main/presenter/index.ts | 8 +- .../agent/acpFsHandler.ts | 10 + .../agent/acpProcessManager.ts | 130 ++++++--- .../agent/acpSessionManager.ts | 29 +- .../managers/agentLoopHandler.ts | 66 +++-- .../providers/acpProvider.ts | 57 +++- src/main/presenter/threadPresenter/index.ts | 12 +- src/renderer/src/components/ChatView.vue | 46 ++- .../acp-workspace/AcpWorkspaceFileNode.vue | 96 +++++++ .../acp-workspace/AcpWorkspaceFiles.vue | 94 +++++++ .../acp-workspace/AcpWorkspacePlan.vue | 121 ++++++++ .../acp-workspace/AcpWorkspaceTerminal.vue | 87 ++++++ .../acp-workspace/AcpWorkspaceView.vue | 47 ++++ .../src/components/chat-input/ChatInput.vue | 14 +- .../chat-input/composables/useAcpMode.ts | 95 ++++++- .../message/MessageActionButtons.vue | 17 ++ .../message/MessageBlockPermissionRequest.vue | 21 +- .../components/message/MessageBlockPlan.vue | 112 +------- .../src/components/message/MessageList.vue | 13 + .../components/think-content/ThinkContent.vue | 14 +- src/renderer/src/events.ts | 8 + src/renderer/src/i18n/da-DK/chat.json | 31 ++- src/renderer/src/i18n/en-US/chat.json | 33 ++- src/renderer/src/i18n/fa-IR/chat.json | 33 ++- src/renderer/src/i18n/fr-FR/chat.json | 33 ++- src/renderer/src/i18n/ja-JP/chat.json | 33 ++- src/renderer/src/i18n/ko-KR/chat.json | 33 ++- src/renderer/src/i18n/pt-BR/chat.json | 33 ++- src/renderer/src/i18n/ru-RU/chat.json | 33 ++- src/renderer/src/i18n/zh-CN/chat.json | 33 ++- src/renderer/src/i18n/zh-HK/chat.json | 33 ++- src/renderer/src/i18n/zh-TW/chat.json | 33 ++- src/renderer/src/stores/acpWorkspace.ts | 263 ++++++++++++++++++ src/shared/types/index.d.ts | 1 + .../types/presenters/acp-workspace.d.ts | 128 +++++++++ src/shared/types/presenters/index.d.ts | 10 + .../types/presenters/legacy.presenters.d.ts | 2 + 41 files changed, 1971 insertions(+), 263 deletions(-) create mode 100644 src/main/presenter/acpWorkspacePresenter/directoryReader.ts create mode 100644 src/main/presenter/acpWorkspacePresenter/index.ts create mode 100644 src/main/presenter/acpWorkspacePresenter/planStateManager.ts create mode 100644 src/renderer/src/components/acp-workspace/AcpWorkspaceFileNode.vue create mode 100644 src/renderer/src/components/acp-workspace/AcpWorkspaceFiles.vue create mode 100644 src/renderer/src/components/acp-workspace/AcpWorkspacePlan.vue create mode 100644 src/renderer/src/components/acp-workspace/AcpWorkspaceTerminal.vue create mode 100644 src/renderer/src/components/acp-workspace/AcpWorkspaceView.vue create mode 100644 src/renderer/src/stores/acpWorkspace.ts create mode 100644 src/shared/types/presenters/acp-workspace.d.ts diff --git a/src/main/events.ts b/src/main/events.ts index 11eeb7aee..7002f85f7 100644 --- a/src/main/events.ts +++ b/src/main/events.ts @@ -230,3 +230,11 @@ export const LIFECYCLE_EVENTS = { PROGRESS_UPDATED: 'lifecycle:progress-updated', // Lifecycle progress updated SHUTDOWN_REQUESTED: 'lifecycle:shutdown-requested' // Application shutdown requested } + +// ACP Workspace events +export const ACP_WORKSPACE_EVENTS = { + PLAN_UPDATED: 'acp-workspace:plan-updated', // Plan entries updated + TERMINAL_OUTPUT: 'acp-workspace:terminal-output', // Terminal output snippet + FILES_CHANGED: 'acp-workspace:files-changed', // File tree changed + SESSION_MODES_READY: 'acp-workspace:session-modes-ready' // Session modes available +} diff --git a/src/main/presenter/acpWorkspacePresenter/directoryReader.ts b/src/main/presenter/acpWorkspacePresenter/directoryReader.ts new file mode 100644 index 000000000..483a77be0 --- /dev/null +++ b/src/main/presenter/acpWorkspacePresenter/directoryReader.ts @@ -0,0 +1,133 @@ +import fs from 'fs/promises' +import path from 'path' +import type { AcpFileNode } from '@shared/presenter' + +// Ignored directory/file patterns +const IGNORED_PATTERNS = [ + 'node_modules', + '.git', + '.DS_Store', + 'dist', + 'build', + '__pycache__', + '.venv', + 'venv', + '.idea', + '.vscode', + '.cache', + 'coverage', + '.next', + '.nuxt', + 'out', + '.turbo' +] + +/** + * Read directory structure shallowly (only first level) + * Directories will have children = undefined, indicating not yet loaded + * @param dirPath Directory path + */ +export async function readDirectoryShallow(dirPath: string): Promise { + try { + const entries = await fs.readdir(dirPath, { withFileTypes: true }) + const nodes: AcpFileNode[] = [] + + for (const entry of entries) { + // Skip ignored files/directories + if (IGNORED_PATTERNS.includes(entry.name)) { + continue + } + + // Skip hidden files (starting with .) + if (entry.name.startsWith('.')) { + continue + } + + const fullPath = path.join(dirPath, entry.name) + const node: AcpFileNode = { + name: entry.name, + path: fullPath, + isDirectory: entry.isDirectory() + } + + // For directories, leave children as undefined (lazy load) + if (entry.isDirectory()) { + node.expanded = false + // children is intentionally undefined - will be loaded on expand + } + + nodes.push(node) + } + + // Sort: directories first, files second, same type sorted by name + return nodes.sort((a, b) => { + if (a.isDirectory !== b.isDirectory) { + return a.isDirectory ? -1 : 1 + } + return a.name.localeCompare(b.name) + }) + } catch (error) { + console.error(`[AcpWorkspace] Failed to read directory ${dirPath}:`, error) + return [] + } +} + +/** + * Recursively read directory structure (deprecated, use readDirectoryShallow for lazy loading) + * @param dirPath Directory path + * @param currentDepth Current depth + * @param maxDepth Maximum depth + */ +export async function readDirectoryTree( + dirPath: string, + currentDepth: number = 0, + maxDepth: number = 3 +): Promise { + // Boundary check: depth limit + if (currentDepth >= maxDepth) { + return [] + } + + try { + const entries = await fs.readdir(dirPath, { withFileTypes: true }) + const nodes: AcpFileNode[] = [] + + for (const entry of entries) { + // Skip ignored files/directories + if (IGNORED_PATTERNS.includes(entry.name)) { + continue + } + + // Skip hidden files (starting with .) + if (entry.name.startsWith('.')) { + continue + } + + const fullPath = path.join(dirPath, entry.name) + const node: AcpFileNode = { + name: entry.name, + path: fullPath, + isDirectory: entry.isDirectory() + } + + // Recursively read subdirectories + if (entry.isDirectory()) { + node.children = await readDirectoryTree(fullPath, currentDepth + 1, maxDepth) + node.expanded = false // Default collapsed + } + + nodes.push(node) + } + + // Sort: directories first, files second, same type sorted by name + return nodes.sort((a, b) => { + if (a.isDirectory !== b.isDirectory) { + return a.isDirectory ? -1 : 1 + } + return a.name.localeCompare(b.name) + }) + } catch (error) { + console.error(`[AcpWorkspace] Failed to read directory ${dirPath}:`, error) + return [] + } +} diff --git a/src/main/presenter/acpWorkspacePresenter/index.ts b/src/main/presenter/acpWorkspacePresenter/index.ts new file mode 100644 index 000000000..5256d7d95 --- /dev/null +++ b/src/main/presenter/acpWorkspacePresenter/index.ts @@ -0,0 +1,112 @@ +import path from 'path' +import { eventBus, SendTarget } from '@/eventbus' +import { ACP_WORKSPACE_EVENTS } from '@/events' +import { readDirectoryShallow } from './directoryReader' +import { PlanStateManager } from './planStateManager' +import type { + IAcpWorkspacePresenter, + AcpFileNode, + AcpPlanEntry, + AcpTerminalSnippet, + AcpRawPlanEntry +} from '@shared/presenter' + +export class AcpWorkspacePresenter implements IAcpWorkspacePresenter { + private readonly planManager = new PlanStateManager() + // Allowed workdir paths (registered by ACP sessions) + private readonly allowedWorkdirs = new Set() + + /** + * Register a workdir as allowed for reading + * Returns Promise to ensure IPC call completion + */ + async registerWorkdir(workdir: string): Promise { + const normalized = path.resolve(workdir) + this.allowedWorkdirs.add(normalized) + } + + /** + * Unregister a workdir + */ + async unregisterWorkdir(workdir: string): Promise { + const normalized = path.resolve(workdir) + this.allowedWorkdirs.delete(normalized) + } + + /** + * Check if a path is within allowed workdirs + */ + private isPathAllowed(targetPath: string): boolean { + const normalized = path.resolve(targetPath) + for (const workdir of this.allowedWorkdirs) { + // Check if targetPath is equal to or under the workdir + if (normalized === workdir || normalized.startsWith(workdir + path.sep)) { + return true + } + } + return false + } + + /** + * Read directory (shallow, only first level) + * Use expandDirectory to load subdirectory contents + */ + async readDirectory(dirPath: string): Promise { + // Security check: only allow reading within registered workdirs + if (!this.isPathAllowed(dirPath)) { + console.warn(`[AcpWorkspace] Blocked read attempt for unauthorized path: ${dirPath}`) + return [] + } + return readDirectoryShallow(dirPath) + } + + /** + * Expand a directory to load its children (lazy loading) + * @param dirPath Directory path to expand + */ + async expandDirectory(dirPath: string): Promise { + // Security check: only allow reading within registered workdirs + if (!this.isPathAllowed(dirPath)) { + console.warn(`[AcpWorkspace] Blocked expand attempt for unauthorized path: ${dirPath}`) + return [] + } + return readDirectoryShallow(dirPath) + } + + /** + * Get plan entries + */ + async getPlanEntries(conversationId: string): Promise { + return this.planManager.getEntries(conversationId) + } + + /** + * Update plan entries (called by acpContentMapper) + */ + async updatePlanEntries(conversationId: string, entries: AcpRawPlanEntry[]): Promise { + const updated = this.planManager.updateEntries(conversationId, entries) + + // Send event to renderer + eventBus.sendToRenderer(ACP_WORKSPACE_EVENTS.PLAN_UPDATED, SendTarget.ALL_WINDOWS, { + conversationId, + entries: updated + }) + } + + /** + * Emit terminal output snippet (called by acpContentMapper) + */ + async emitTerminalSnippet(conversationId: string, snippet: AcpTerminalSnippet): Promise { + eventBus.sendToRenderer(ACP_WORKSPACE_EVENTS.TERMINAL_OUTPUT, SendTarget.ALL_WINDOWS, { + conversationId, + snippet + }) + } + + /** + * Clear workspace data for a conversation + */ + async clearWorkspaceData(conversationId: string): Promise { + this.planManager.clear(conversationId) + } +} diff --git a/src/main/presenter/acpWorkspacePresenter/planStateManager.ts b/src/main/presenter/acpWorkspacePresenter/planStateManager.ts new file mode 100644 index 000000000..ab548ae20 --- /dev/null +++ b/src/main/presenter/acpWorkspacePresenter/planStateManager.ts @@ -0,0 +1,119 @@ +import crypto from 'crypto' +import { nanoid } from 'nanoid' +import type { AcpPlanEntry, AcpPlanStatus, AcpRawPlanEntry } from '@shared/presenter' + +// Maximum number of completed entries to retain per conversation +const MAX_COMPLETED_ENTRIES = 10 + +/** + * Plan State Manager + * Maintains plan entries for each conversation, supports incremental updates + */ +export class PlanStateManager { + // Map> + private readonly planStore = new Map>() + + /** + * Update plan entries (incremental merge) + * @param conversationId Conversation ID + * @param rawEntries Raw plan entries + * @returns Updated complete entries list + */ + updateEntries(conversationId: string, rawEntries: AcpRawPlanEntry[]): AcpPlanEntry[] { + if (!this.planStore.has(conversationId)) { + this.planStore.set(conversationId, new Map()) + } + const store = this.planStore.get(conversationId)! + + for (const raw of rawEntries) { + const contentKey = this.hashContent(raw.content) + const existing = store.get(contentKey) + + if (existing) { + // Update existing entry status + existing.status = this.normalizeStatus(raw.status) + existing.priority = raw.priority ?? existing.priority + existing.updatedAt = Date.now() + } else { + // Add new entry + store.set(contentKey, { + id: nanoid(8), + content: raw.content, + status: this.normalizeStatus(raw.status), + priority: raw.priority ?? null, + updatedAt: Date.now() + }) + } + } + + // Cleanup: keep only the latest MAX_COMPLETED_ENTRIES completed entries + this.pruneCompletedEntries(store) + + return this.getEntries(conversationId) + } + + /** + * Get all plan entries for a conversation + */ + getEntries(conversationId: string): AcpPlanEntry[] { + const store = this.planStore.get(conversationId) + if (!store) return [] + return Array.from(store.values()) + } + + /** + * Clear conversation data + */ + clear(conversationId: string): void { + this.planStore.delete(conversationId) + } + + /** + * Prune completed entries, keeping only the latest MAX_COMPLETED_ENTRIES + */ + private pruneCompletedEntries(store: Map): void { + const completedEntries: Array<{ key: string; entry: AcpPlanEntry }> = [] + + for (const [key, entry] of store) { + if (entry.status === 'completed') { + completedEntries.push({ key, entry }) + } + } + + // If completed entries exceed the limit, remove oldest ones + if (completedEntries.length > MAX_COMPLETED_ENTRIES) { + // Sort by updatedAt ascending (oldest first) + completedEntries.sort((a, b) => a.entry.updatedAt - b.entry.updatedAt) + + // Remove oldest entries beyond the limit + const toRemove = completedEntries.slice(0, completedEntries.length - MAX_COMPLETED_ENTRIES) + for (const { key } of toRemove) { + store.delete(key) + } + } + } + + /** + * Hash content using SHA-256 for reliable deduplication + */ + private hashContent(content: string): string { + const normalized = content.trim().toLowerCase() + return crypto.createHash('sha256').update(normalized).digest('hex') + } + + private normalizeStatus(status?: string | null): AcpPlanStatus { + switch (status) { + case 'completed': + case 'done': + return 'completed' + case 'in_progress': + return 'in_progress' + case 'failed': + return 'failed' + case 'skipped': + return 'skipped' + default: + return 'pending' + } + } +} diff --git a/src/main/presenter/index.ts b/src/main/presenter/index.ts index 1cb9b3d5e..497a2eddb 100644 --- a/src/main/presenter/index.ts +++ b/src/main/presenter/index.ts @@ -22,7 +22,8 @@ import { ITabPresenter, IThreadPresenter, IUpgradePresenter, - IWindowPresenter + IWindowPresenter, + IAcpWorkspacePresenter } from '@shared/presenter' import { eventBus } from '@/eventbus' import { LLMProviderPresenter } from './llmProviderPresenter' @@ -40,6 +41,7 @@ import { OAuthPresenter } from './oauthPresenter' import { FloatingButtonPresenter } from './floatingButtonPresenter' import { CONFIG_EVENTS, WINDOW_EVENTS } from '@/events' import { KnowledgePresenter } from './knowledgePresenter' +import { AcpWorkspacePresenter } from './acpWorkspacePresenter' // IPC调用上下文接口 interface IPCCallContext { @@ -77,6 +79,7 @@ export class Presenter implements IPresenter { oauthPresenter: OAuthPresenter floatingButtonPresenter: FloatingButtonPresenter knowledgePresenter: IKnowledgePresenter + acpWorkspacePresenter: IAcpWorkspacePresenter // llamaCppPresenter: LlamaCppPresenter // 保留原始注释 dialogPresenter: IDialogPresenter lifecycleManager: ILifecycleManager @@ -119,6 +122,9 @@ export class Presenter implements IPresenter { this.filePresenter ) + // Initialize ACP Workspace presenter + this.acpWorkspacePresenter = new AcpWorkspacePresenter() + // this.llamaCppPresenter = new LlamaCppPresenter() // 保留原始注释 this.setupEventBus() // 设置事件总线监听 } diff --git a/src/main/presenter/llmProviderPresenter/agent/acpFsHandler.ts b/src/main/presenter/llmProviderPresenter/agent/acpFsHandler.ts index 8c7ea86ec..c81d44b1c 100644 --- a/src/main/presenter/llmProviderPresenter/agent/acpFsHandler.ts +++ b/src/main/presenter/llmProviderPresenter/agent/acpFsHandler.ts @@ -8,6 +8,8 @@ export interface FsHandlerOptions { workspaceRoot: string | null /** Maximum file size in bytes to read (default: 10MB) */ maxReadSize?: number + /** Callback when a file is written */ + onFileChange?: (filePath: string) => void } /** @@ -21,10 +23,12 @@ export interface FsHandlerOptions { export class AcpFsHandler { private readonly workspaceRoot: string | null private readonly maxReadSize: number + private readonly onFileChange?: (filePath: string) => void constructor(options: FsHandlerOptions) { this.workspaceRoot = options.workspaceRoot ? path.resolve(options.workspaceRoot) : null this.maxReadSize = options.maxReadSize ?? 10 * 1024 * 1024 // 10MB default + this.onFileChange = options.onFileChange } /** @@ -101,6 +105,12 @@ export class AcpFsHandler { await fs.mkdir(dir, { recursive: true }) await fs.writeFile(filePath, params.content, 'utf-8') + + // Notify file change + if (this.onFileChange) { + this.onFileChange(filePath) + } + return {} } catch (error) { if (error instanceof RequestError) { diff --git a/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts b/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts index 106a4d4bc..62ccc09e3 100644 --- a/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts +++ b/src/main/presenter/llmProviderPresenter/agent/acpProcessManager.ts @@ -24,6 +24,8 @@ export interface AcpProcessHandle extends AgentProcessHandle { connection: ClientSideConnectionType agent: AcpAgentConfig readyAt: number + /** The working directory this process was spawned with */ + workdir: string } interface AcpProcessManagerOptions { @@ -70,6 +72,7 @@ export class AcpProcessManager implements AgentProcessManager() private readonly fsHandlers = new Map() + private readonly agentLocks = new Map>() constructor(options: AcpProcessManagerOptions) { this.providerId = options.providerId @@ -121,28 +124,69 @@ export class AcpProcessManager implements AgentProcessManager { + /** + * Get or create a connection for the given agent. + * If workdir is provided and differs from the existing process's workdir, + * the existing process will be released and a new one spawned with the new workdir. + */ + async getConnection(agent: AcpAgentConfig, workdir?: string): Promise { + const resolvedWorkdir = this.resolveWorkdir(workdir) const existing = this.handles.get(agent.id) - if (existing && this.isHandleAlive(existing)) { - return existing - } - const inflight = this.pendingHandles.get(agent.id) - if (inflight) { - return inflight + // Fast-path for already-alive handles with matching workdir + if (existing && this.isHandleAlive(existing) && existing.workdir === resolvedWorkdir) { + return existing } - const handlePromise = this.spawnProcess(agent) - this.pendingHandles.set(agent.id, handlePromise) + const releaseLock = await this.acquireAgentLock(agent.id) try { - const handle = await handlePromise - this.handles.set(agent.id, handle) - return handle + const currentHandle = this.handles.get(agent.id) + if (currentHandle && this.isHandleAlive(currentHandle)) { + if (currentHandle.workdir === resolvedWorkdir) { + return currentHandle + } + console.info( + `[ACP] Workdir changed for agent ${agent.id}: "${currentHandle.workdir}" -> "${resolvedWorkdir}", recreating process` + ) + await this.release(agent.id) + } + + const inflight = this.pendingHandles.get(agent.id) + if (inflight) { + const inflightHandle = await inflight + if (inflightHandle.workdir === resolvedWorkdir) { + return inflightHandle + } + console.info( + `[ACP] Workdir mismatch for inflight agent ${agent.id}, recreating with workdir: "${resolvedWorkdir}"` + ) + await this.release(agent.id) + } + + const handlePromise = this.spawnProcess(agent, resolvedWorkdir) + this.pendingHandles.set(agent.id, handlePromise) + try { + const handle = await handlePromise + this.handles.set(agent.id, handle) + return handle + } finally { + this.pendingHandles.delete(agent.id) + } } finally { - this.pendingHandles.delete(agent.id) + releaseLock() } } + /** + * Resolve workdir to an absolute path, using fallback if not provided. + */ + private resolveWorkdir(workdir?: string): string { + if (workdir && workdir.trim()) { + return workdir.trim() + } + return this.getFallbackWorkdir() + } + getProcess(agentId: string): AcpProcessHandle | null { return this.handles.get(agentId) ?? null } @@ -224,8 +268,8 @@ export class AcpProcessManager implements AgentProcessManager { - const child = await this.spawnAgentProcess(agent) + private async spawnProcess(agent: AcpAgentConfig, workdir: string): Promise { + const child = await this.spawnAgentProcess(agent, workdir) const stream = this.createAgentStream(child) const client = this.createClientProxy() const connection = new ClientSideConnection(() => client, stream) @@ -317,7 +361,8 @@ export class AcpProcessManager implements AgentProcessManager { @@ -330,12 +375,12 @@ export class AcpProcessManager implements AgentProcessManager { - const output = chunk.toString().trim() - if (output) { - console.info(`[ACP] ${agent.id} stdout: ${output}`) - } - }) + // child.stdout?.on('data', (chunk: Buffer) => { + // const output = chunk.toString().trim() + // if (output) { + // console.info(`[ACP] ${agent.id} stdout: ${output}`) + // } + // }) child.stderr?.on('data', (chunk: Buffer) => { const error = chunk.toString().trim() @@ -354,7 +399,10 @@ export class AcpProcessManager implements AgentProcessManager { + private async spawnAgentProcess( + agent: AcpAgentConfig, + workdir: string + ): Promise { // Initialize runtime paths if not already done this.runtimeHelper.initializeRuntimes() @@ -533,16 +581,15 @@ export class AcpProcessManager implements AgentProcessManager void> { + const previousLock = this.agentLocks.get(agentId) ?? Promise.resolve() + + let releaseResolver: (() => void) | undefined + const currentLock = new Promise((resolve) => { + releaseResolver = resolve + }) + + this.agentLocks.set(agentId, currentLock) + await previousLock + + return () => { + releaseResolver?.() + if (this.agentLocks.get(agentId) === currentLock) { + this.agentLocks.delete(agentId) + } + } + } + private isHandleAlive(handle: AcpProcessHandle): boolean { return !handle.child.killed && !handle.connection.signal.aborted } diff --git a/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts b/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts index f2448c1c0..06eb7dd7d 100644 --- a/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts +++ b/src/main/presenter/llmProviderPresenter/agent/acpSessionManager.ts @@ -152,7 +152,8 @@ export class AcpSessionManager { hooks: SessionHooks, workdir: string ): Promise { - const handle = await this.processManager.getConnection(agent) + // Pass workdir to process manager so the process runs in the correct directory + const handle = await this.processManager.getConnection(agent, workdir) const session = await this.initializeSession(handle, agent, workdir) const detachListeners = this.attachSessionHooks(agent.id, session.sessionId, hooks) @@ -219,15 +220,29 @@ export class AcpSessionManager { // Extract modes from response if available const modes = response.modes + const availableModes = modes?.availableModes?.map((m) => ({ + id: m.id, + name: m.name, + description: m.description ?? '' + })) + const currentModeId = modes?.currentModeId + + // Log available modes for the agent + if (availableModes && availableModes.length > 0) { + console.info( + `[ACP] Agent "${agent.name}" (${agent.id}) supports modes: [${availableModes.map((m) => m.id).join(', ')}], ` + + `current mode: "${currentModeId ?? 'default'}"` + ) + } else { + console.info( + `[ACP] Agent "${agent.name}" (${agent.id}) does not declare any modes (will use default behavior)` + ) + } return { sessionId: response.sessionId, - availableModes: modes?.availableModes?.map((m) => ({ - id: m.id, - name: m.name, - description: m.description ?? '' - })), - currentModeId: modes?.currentModeId + availableModes, + currentModeId } } catch (error) { console.error(`[ACP] Failed to create session for agent ${agent.id}:`, error) diff --git a/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts b/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts index 196f2f831..ededb9d23 100644 --- a/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts +++ b/src/main/presenter/llmProviderPresenter/managers/agentLoopHandler.ts @@ -1,5 +1,7 @@ import { ChatMessage, IConfigPresenter, LLMAgentEvent, MCPToolCall } from '@shared/presenter' import { presenter } from '@/presenter' +import { eventBus, SendTarget } from '@/eventbus' +import { ACP_WORKSPACE_EVENTS } from '@/events' import { BaseLLMProvider } from '../baseProvider' import { StreamState } from '../types' import { RateLimitManager } from './rateLimitManager' @@ -255,25 +257,50 @@ export class AgentLoopHandler { const completeArgs = chunk.tool_call_arguments_complete ?? currentToolChunks[chunk.tool_call_id].arguments_chunk - currentToolCalls.push({ - id: chunk.tool_call_id, - name: currentToolChunks[chunk.tool_call_id].name, - arguments: completeArgs - }) + const toolCallName = currentToolChunks[chunk.tool_call_id].name + + // For ACP provider, tool call execution is completed on agent side + // The tool_call_arguments_complete contains the execution result + // So we should immediately send 'end' event to mark it as successful + if (providerId === 'acp') { + // For ACP, tool_call_arguments_complete contains the execution result + // Use it directly as the response + yield { + type: 'response', + data: { + eventId, + tool_call: 'end', + tool_call_id: chunk.tool_call_id, + tool_call_name: toolCallName, + tool_call_params: completeArgs, + tool_call_response: completeArgs + } + } - // Send final update event to ensure parameter completeness - yield { - type: 'response', - data: { - eventId, - tool_call: 'update', - tool_call_id: chunk.tool_call_id, - tool_call_name: currentToolChunks[chunk.tool_call_id].name, - tool_call_params: completeArgs + // Don't add to currentToolCalls for ACP - execution already completed + delete currentToolChunks[chunk.tool_call_id] + } else { + // For non-ACP providers, tool call needs to be executed by ToolCallProcessor + currentToolCalls.push({ + id: chunk.tool_call_id, + name: toolCallName, + arguments: completeArgs + }) + + // Send final update event to ensure parameter completeness + yield { + type: 'response', + data: { + eventId, + tool_call: 'update', + tool_call_id: chunk.tool_call_id, + tool_call_name: toolCallName, + tool_call_params: completeArgs + } } - } - delete currentToolChunks[chunk.tool_call_id] + delete currentToolChunks[chunk.tool_call_id] + } } break case 'permission': { @@ -504,6 +531,13 @@ export class AgentLoopHandler { this.options.activeStreams.delete(eventId) console.log('Agent loop finished for event:', eventId, 'User stopped:', userStop) + + // Trigger ACP workspace file refresh (only for ACP provider) + if (providerId === 'acp' && conversationId) { + eventBus.sendToRenderer(ACP_WORKSPACE_EVENTS.FILES_CHANGED, SendTarget.ALL_WINDOWS, { + conversationId + }) + } } } } diff --git a/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts b/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts index 8ffcbf925..ee1333690 100644 --- a/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts +++ b/src/main/presenter/llmProviderPresenter/providers/acpProvider.ts @@ -19,7 +19,7 @@ import { } from '@shared/types/core/llm-events' import { ModelType } from '@shared/model' import { eventBus, SendTarget } from '@/eventbus' -import { CONFIG_EVENTS } from '@/events' +import { CONFIG_EVENTS, ACP_WORKSPACE_EVENTS } from '@/events' import { AcpProcessManager } from '../agent/acpProcessManager' import { AcpSessionManager } from '../agent/acpSessionManager' import type { AcpSessionRecord } from '../agent/acpSessionManager' @@ -327,7 +327,7 @@ export class AcpProvider extends BaseAgentProvider< agent, { onSessionUpdate: (notification) => { - console.log('[ACP] onSessionUpdate: notification:', JSON.stringify(notification)) + // console.log('[ACP] onSessionUpdate: notification:', JSON.stringify(notification)) const mapped = this.contentMapper.map(notification) mapped.events.forEach((event) => queue.push(event)) }, @@ -340,6 +340,19 @@ export class AcpProvider extends BaseAgentProvider< workdir ) + // Notify renderer of available session modes (if any) + if (session.availableModes && session.availableModes.length > 0) { + eventBus.sendToRenderer( + ACP_WORKSPACE_EVENTS.SESSION_MODES_READY, + SendTarget.ALL_WINDOWS, + { + conversationId: conversationKey, + current: session.currentModeId ?? 'default', + available: session.availableModes + } + ) + } + const promptBlocks = this.messageFormatter.format(messages, modelConfig) void this.runPrompt(session, promptBlocks, queue) } @@ -666,12 +679,38 @@ export class AcpProvider extends BaseAgentProvider< throw new Error(`[ACP] No session found for conversation ${conversationId}`) } + const previousMode = session.currentModeId ?? 'default' + const availableModes = session.availableModes ?? [] + const availableModeIds = availableModes.map((m) => m.id) + + // Log available modes for debugging + console.info( + `[ACP] Agent "${session.agentId}" available modes: [${availableModeIds.join(', ')}]` + ) + + // Warn if requested mode is not in available modes + if (availableModeIds.length > 0 && !availableModeIds.includes(modeId)) { + console.warn( + `[ACP] Mode "${modeId}" is not in agent's available modes [${availableModeIds.join(', ')}]. ` + + `The agent may not support this mode.` + ) + } + try { + console.info( + `[ACP] Changing session mode: "${previousMode}" -> "${modeId}" ` + + `(conversation: ${conversationId}, agent: ${session.agentId})` + ) await session.connection.setSessionMode({ sessionId: session.sessionId, modeId }) session.currentModeId = modeId - console.info(`[ACP] Session mode changed to ${modeId} for conversation ${conversationId}`) + console.info( + `[ACP] Session mode successfully changed to "${modeId}" for conversation ${conversationId}` + ) } catch (error) { - console.error('[ACP] Failed to set session mode:', error) + console.error( + `[ACP] Failed to set session mode "${modeId}" for agent "${session.agentId}":`, + error + ) throw error } } @@ -685,12 +724,20 @@ export class AcpProvider extends BaseAgentProvider< } | null> { const session = this.sessionManager.getSession(conversationId) if (!session) { + console.warn(`[ACP] getSessionModes: No session found for conversation ${conversationId}`) return null } - return { + const result = { current: session.currentModeId ?? 'default', available: session.availableModes ?? [] } + + console.info( + `[ACP] getSessionModes for agent "${session.agentId}": ` + + `current="${result.current}", available=[${result.available.map((m) => m.id).join(', ')}]` + ) + + return result } } diff --git a/src/main/presenter/threadPresenter/index.ts b/src/main/presenter/threadPresenter/index.ts index 95962ca97..268b5cc24 100644 --- a/src/main/presenter/threadPresenter/index.ts +++ b/src/main/presenter/threadPresenter/index.ts @@ -175,11 +175,13 @@ export class ThreadPresenter implements IThreadPresenter { if (conversation.is_new === 1) { try { - const title = await this.summaryTitles(undefined, state.conversationId) - if (title) { - await this.renameConversation(state.conversationId, title) - return - } + this.summaryTitles(undefined, state.conversationId) + .then((title) => { + return this.renameConversation(state.conversationId, title) + }) + .then(() => { + console.log('renameConversation success') + }) } catch (error) { console.error('[ThreadPresenter] Failed to summarize title', { conversationId: state.conversationId, diff --git a/src/renderer/src/components/ChatView.vue b/src/renderer/src/components/ChatView.vue index 1c6bbd0d4..f7fccb6b2 100644 --- a/src/renderer/src/components/ChatView.vue +++ b/src/renderer/src/components/ChatView.vue @@ -1,11 +1,20 @@ { return chatStore.generatingThreadIds.has(chatStore.getActiveThreadId() ?? '') }) +// Show workspace button only in ACP mode when workspace is closed +const showWorkspaceButton = computed(() => { + return acpWorkspaceStore.isAcpMode && !acpWorkspaceStore.isOpen +}) + +const handleOpenWorkspace = () => { + acpWorkspaceStore.setOpen(true) +} + const handleTrace = (messageId: string) => { traceMessageId.value = messageId } diff --git a/src/renderer/src/components/think-content/ThinkContent.vue b/src/renderer/src/components/think-content/ThinkContent.vue index 84ecc8766..e69bc55e2 100644 --- a/src/renderer/src/components/think-content/ThinkContent.vue +++ b/src/renderer/src/components/think-content/ThinkContent.vue @@ -28,10 +28,10 @@
@@ -47,16 +47,22 @@ diff --git a/src/renderer/src/components/acp-workspace/AcpWorkspaceFiles.vue b/src/renderer/src/components/acp-workspace/AcpWorkspaceFiles.vue index 37b3a0f34..d71f49dc8 100644 --- a/src/renderer/src/components/acp-workspace/AcpWorkspaceFiles.vue +++ b/src/renderer/src/components/acp-workspace/AcpWorkspaceFiles.vue @@ -32,6 +32,7 @@ :node="node" :depth="0" @toggle="handleToggle" + @append-path="handleAppendPath" />
@@ -53,6 +54,9 @@ import type { AcpFileNode } from '@shared/presenter' const { t } = useI18n() const store = useAcpWorkspaceStore() const showFiles = ref(true) +const emit = defineEmits<{ + 'append-path': [filePath: string] +}>() const countFiles = (nodes: AcpFileNode[]): number => { let count = 0 @@ -70,6 +74,10 @@ const fileCount = computed(() => countFiles(store.fileTree)) const handleToggle = async (node: AcpFileNode) => { await store.toggleFileNode(node) } + +const handleAppendPath = (filePath: string) => { + emit('append-path', filePath) +} diff --git a/src/renderer/src/composables/useChatConfigFields.ts b/src/renderer/src/composables/useChatConfigFields.ts index 36c82538f..3c0024422 100644 --- a/src/renderer/src/composables/useChatConfigFields.ts +++ b/src/renderer/src/composables/useChatConfigFields.ts @@ -74,7 +74,7 @@ export function useChatConfigFields(options: UseChatConfigFieldsOptions) { label: t('settings.model.temperature.label'), description: t('settings.model.temperature.description'), min: 0, - max: 1.5, + max: 2, step: 0.1, getValue: () => options.temperature.value, setValue: (val) => options.emit('update:temperature', val) diff --git a/src/renderer/src/stores/searchAssistantStore.ts b/src/renderer/src/stores/searchAssistantStore.ts index 9434b2131..8127d1874 100644 --- a/src/renderer/src/stores/searchAssistantStore.ts +++ b/src/renderer/src/stores/searchAssistantStore.ts @@ -26,6 +26,13 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { const searchAssistantModel = computed(() => modelRef.value) const searchAssistantProvider = computed(() => providerRef.value) + const isProviderAllowed = (providerId?: string) => providerId !== 'acp' + const isModelEnabledForProvider = (model: RENDERER_MODEL_META, providerId: string) => + enabledModels.value.some( + (provider) => + provider.providerId === providerId && + provider.models.some((enabledModel) => enabledModel.id === model.id) + ) const findPriorityModel = (): { model: RENDERER_MODEL_META; providerId: string } | null => { if (!enabledModels.value || enabledModels.value.length === 0) { @@ -34,6 +41,9 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { for (const keyword of priorities) { for (const providerModels of enabledModels.value) { + if (!isProviderAllowed(providerModels.providerId)) { + continue + } for (const model of providerModels.models) { if ( model.id.toLowerCase().includes(keyword.toLowerCase()) || @@ -49,6 +59,7 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { } const fallback = enabledModels.value + .filter((provider) => isProviderAllowed(provider.providerId)) .flatMap((provider) => provider.models.map((model) => ({ ...model, providerId: provider.providerId })) ) @@ -65,6 +76,10 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { } const setSearchAssistantModel = async (model: RENDERER_MODEL_META, providerId: string) => { + if (!isProviderAllowed(providerId)) { + await initOrUpdateSearchAssistantModel() + return + } const rawModel = toRaw(model) modelRef.value = rawModel providerRef.value = providerId @@ -82,10 +97,18 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { 'searchAssistantModel' ) savedModel = toRaw(savedModel) - if (savedModel) { - modelRef.value = savedModel.model - providerRef.value = savedModel.providerId - threadP.setSearchAssistantModel(savedModel.model, savedModel.providerId) + const hasEnabledModels = enabledModels.value.length > 0 + const usableSavedModel = + savedModel && + isProviderAllowed(savedModel.providerId) && + (!hasEnabledModels || isModelEnabledForProvider(savedModel.model, savedModel.providerId)) + ? savedModel + : null + + if (usableSavedModel) { + modelRef.value = usableSavedModel.model + providerRef.value = usableSavedModel.providerId + threadP.setSearchAssistantModel(usableSavedModel.model, usableSavedModel.providerId) return } @@ -113,9 +136,14 @@ export const useSearchAssistantStore = defineStore('searchAssistant', () => { return } - const stillAvailable = enabledModels.value.some((provider) => - provider.models.some((model) => model.id === currentModel.id) - ) + const resolvedProviderId = providerRef.value || currentModel.providerId || '' + if (!isProviderAllowed(resolvedProviderId)) { + await initOrUpdateSearchAssistantModel() + return + } + + const stillAvailable = + resolvedProviderId !== '' && isModelEnabledForProvider(currentModel, resolvedProviderId) if (!stillAvailable) { await initOrUpdateSearchAssistantModel() From 8052db4407b411bbb93a4c751d6cdaa15dd098d9 Mon Sep 17 00:00:00 2001 From: zerob13 Date: Mon, 8 Dec 2025 13:09:05 +0800 Subject: [PATCH 7/7] feat: add new i18n translation --- src/renderer/src/i18n/he-IL/chat.json | 36 +++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/i18n/he-IL/chat.json b/src/renderer/src/i18n/he-IL/chat.json index 2a4cbd650..effb8f617 100644 --- a/src/renderer/src/i18n/he-IL/chat.json +++ b/src/renderer/src/i18n/he-IL/chat.json @@ -22,11 +22,6 @@ "acpWorkdirSelect": "בחר תיקייה שתשמש כתיקיית העבודה של ACP", "acpWorkdirCurrent": "תיקיית עבודה נוכחית: {path}", "acpMode": "דֶגֶם", - "acpModeAcceptEdits": "קבל באופן אוטומטי עריכות", - "acpModeBypassPermissions": "דילוג על הרשאות", - "acpModeDefault": "תמיד לשאול", - "acpModePlan": "מצב תכנון", - "acpModeSwitched": "עבר ל-{mode}", "acpModeTooltip": "מצב נוכחי: {mode}" }, "features": { @@ -93,5 +88,36 @@ "functionName": "פונקציה", "params": "פרמטרים", "responseData": "נתוני תגובה" + }, + "acp": { + "workspace": { + "collapse": "לִסְגוֹר", + "files": { + "contextMenu": { + "insertPath": "הכנס לתוך תיבת הקלט", + "openFile": "לפתוח קובץ", + "revealInFolder": "פתח במנהל הקבצים" + }, + "empty": "עדיין אין קבצים", + "loading": "טוען קבצים...", + "section": "מִסְמָך" + }, + "plan": { + "empty": "עדיין אין משימות", + "section": "לְתַכְנֵן", + "status": { + "completed": "הושלם", + "failed": "לְהִכָּשֵׁל", + "in_progress": "בתהליך", + "pending": "תָלוּי וְעוֹמֵד", + "skipped": "דילג" + } + }, + "terminal": { + "empty": "עדיין אין פלט", + "section": "מָסוֹף" + }, + "title": "סביבת עבודה" + } } }