From 5dc2451c3ccaf3358fa85f4fbd8c42f77aad4358 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 6 Jan 2026 11:46:30 +0100 Subject: [PATCH 001/123] no concurrency runs of the prerelease workflow --- .github/workflows/prerelease_comment_issue.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/prerelease_comment_issue.yml b/.github/workflows/prerelease_comment_issue.yml index d82226b3..aca32a21 100644 --- a/.github/workflows/prerelease_comment_issue.yml +++ b/.github/workflows/prerelease_comment_issue.yml @@ -4,13 +4,17 @@ on: release: types: [published, edited] +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + permissions: contents: read issues: write jobs: comment-milestone-issues: - # consenti il run manuale per test; in produzione resta solo prerelease + # allow manual run for testing; in production, only prerelease if: ${{ github.event.release.prerelease == true }} runs-on: ubuntu-latest steps: From a22398a354752f09ac9f1ca7dbb63f5b0a58662f Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 6 Jan 2026 12:07:31 +0100 Subject: [PATCH 002/123] Gett the completion of the job on ChatGPT Web. Fixes #607 --- js/mzta-chatgpt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-chatgpt.js b/js/mzta-chatgpt.js index a5dbda64..9b7087d3 100644 --- a/js/mzta-chatgpt.js +++ b/js/mzta-chatgpt.js @@ -85,7 +85,7 @@ async function chatgpt_isIdle() { function chatgpt_getRegenerateButton() { for (const mainSVG of document.querySelectorAll('main svg.icon')) { - if (mainSVG.querySelector('path[d^="M3.502 16.6663V13"]') || mainSVG.querySelector('path[d^="M3.06957"]') || mainSVG.querySelector('path[d^="M10.9153 1.83987L11.2942 1.88772L11.4749"]')){ // regen icon or thumb-up icon found + if (mainSVG.querySelector('path[d^="M3.502 16.6663V13"]') || mainSVG.querySelector('path[d^="M3.06957"]') || mainSVG.querySelector('path[d^="M10.9153 1.83987L11.2942 1.88772L11.4749"]') || document.querySelector("button[data-testid=good-response-turn-action-button]")){ // regen icon or thumb-up icon found //console.log(">>>>>>>>>> found regen icon!"); return mainSVG.parentNode.parentNode; } From 85ffca55799c952c6324ecbde567b25690d8a4a1 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 6 Jan 2026 12:08:56 +0100 Subject: [PATCH 003/123] version set to 3.7.9. release notes updated --- CHANGELOG.md | 4 ++++ manifest.json | 2 +- options/mzta-release-notes.html | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce925d7a..6412b985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

Version 3.7.9 - 06/01/2026

+
    +
  • [ChatGPT Web] Fix: Correctly getting the job completion [#607].
  • +

Version 3.7.8 - 18/12/2025

  • Greek (el) translation added, thanks to ChristosK..
  • diff --git a/manifest.json b/manifest.json index a3cef247..4985fbf3 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.7.8", + "version": "3.7.9", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index d021cc39..11f7418b 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

    ThunderAI Release Notes

    +

    Version 3.7.9 - 06/01/2026

    +
      +
    • [ChatGPT Web] Fix: Correctly getting the job completion [#607].
    • +

    Version 3.7.8 - 18/12/2025

    • Greek (el) translation added, thanks to ChristosK..
    • From aa0fd9756397cdd9a0a962ea48cb83e2a30322ff Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 9 Jan 2026 22:52:41 +0100 Subject: [PATCH 004/123] fix query selector --- pages/_lib/connection-ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 37c779ed..7e668e50 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -1164,9 +1164,9 @@ export function showConnectionOptions(conntype_select, modelId_prefix = '') { element.style.display = anthropic_api_display; }); if (varConnectionUI.permission_all_urls) { - const openaiCompWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning'); + const openaiCompWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning'); if (openaiCompWarning) openaiCompWarning.style.display = 'none'; - const ollamaWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning'); + const ollamaWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning'); if (ollamaWarning) ollamaWarning.style.display = 'none'; } } From 0206e421aeb91c5b7d057e8abb3b38db63925235 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 9 Jan 2026 23:11:38 +0100 Subject: [PATCH 005/123] missing spaces added --- CHANGELOG.md | 4 ++-- options/mzta-release-notes.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbad26b5..53286eb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,7 +60,7 @@
    • [All APIs] It's now possibile to define a list of tags to be used when autotagging received emails [#436]. The tags are are now shown in the information header in the AI API chat [#289].
    • [All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
    • Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
    • -
    • [Google Gemini API]Support for the thinkingBudget parameter has been added [#494].
    • +
    • [Google Gemini API] Support for the thinkingBudget parameter has been added [#494].
    • [OpenAI Comp API] Added DeepSeek configuration [#486].
    • [ChatGPT Web] Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [#419].
    • Anthropic API renamed to Claude API [#510].
    • @@ -394,7 +394,7 @@
    • Added a better error message when there is an error fetching models.
    • When selecting a correct model in the options page, the field is no more highlighted in red [#100].
    • When using the ChatGPT API, the double quotes at the beginning and end of the response are removed [#99].
    • -
    • [ChatGPT Web]"Keep formatting" option removed.
    • +
    • [ChatGPT Web] "Keep formatting" option removed.

    Version 2.0.1 - 09/08/2024

      diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index f45c1934..c0ffa6c8 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -63,7 +63,7 @@
    • [All APIs] It's now possibile to define a list of tags to be used when autotagging received emails [#436]. The tags are are now shown in the information header in the AI API chat [#289].
    • [All APIs] The prompt id and name are now shown in the information header in the AI API chat [#436].
    • Added the {%mail_attachments_info%} placeholder to retrieve the name, type and file size of the mail attachments [#446].
    • -
    • [Google Gemini API]Support for the thinkingBudget parameter has been added [#494].
    • +
    • [Google Gemini API] Support for the thinkingBudget parameter has been added [#494].
    • [OpenAI Comp API] Added DeepSeek configuration [#486].
    • [ChatGPT Web] Added a message to explain to click on "Force completion" if the ChatGPT job is not done after 7 seconds [#419].
    • Anthropic API renamed to Claude API [#510].
    • @@ -397,7 +397,7 @@
    • [ChatGPT API] Added a better error message when there is an error fetching models.
    • When selecting a correct model in the options page, the field is no more highlighted in red [#100].
    • [ChatGPT API] The double quotes at the beginning and end of the response are removed [#99].
    • -
    • [ChatGPT Web]"Keep formatting" option removed.
    • +
    • [ChatGPT Web] "Keep formatting" option removed.

    Version 2.0.1 - 09/08/2024

      From de7ba70993e5b8feb695c3f118312283555af8db Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 9 Jan 2026 23:32:55 +0100 Subject: [PATCH 006/123] debug log improved. now commented out --- js/api/anthropic.js | 4 ++-- js/api/google_gemini.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/api/anthropic.js b/js/api/anthropic.js index 2fa9ae78..9d44a99e 100644 --- a/js/api/anthropic.js +++ b/js/api/anthropic.js @@ -87,8 +87,6 @@ export class Anthropic { fetchResponse = async (messages) => { - // console.log(">>>>>>>>>>> Anthropic API request: " + JSON.stringify(messages)); - try { let claude_body = { @@ -103,6 +101,8 @@ export class Anthropic { if(this.temperature != '' && !Number.isNaN(tempFloat)) claude_body.temperature = tempFloat; + // console.log(">>>>>>>>>>>>>>>>> [ThunderAI] Anthropic API request: " + JSON.stringify(claude_body)); + const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { diff --git a/js/api/google_gemini.js b/js/api/google_gemini.js index caea5eb0..91e764bb 100644 --- a/js/api/google_gemini.js +++ b/js/api/google_gemini.js @@ -116,7 +116,7 @@ export class GoogleGemini { google_gemini_body.generationConfig.temperature = tempFloat; } - // console.log("[ThunderAI] Google Gemini API request: " + JSON.stringify(google_gemini_body)); + // console.log(">>>>>>>>>>>>>>>>> [ThunderAI] Google Gemini API request: " + JSON.stringify(google_gemini_body)); const response = await fetch("https://generativelanguage.googleapis.com/v1beta/models/" + this.model + ":" + (this.stream ? 'streamGenerateContent?alt=sse&' : 'generateContent?') + "key=" + this.apiKey, { method: "POST", From 12ba436f4d9ac0a0228f644db602cbe4262fa5d9 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 9 Jan 2026 23:37:35 +0100 Subject: [PATCH 007/123] hiding api keys in the prompt log --- js/mzta-menus.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index a74124ed..b164bae1 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -430,7 +430,13 @@ export class mzta_Menus { } }else{ // Classic prompts for the API webchat this.logger.log("fullPrompt: " + fullPrompt); - this.logger.log("curr_prompt: " + JSON.stringify(curr_prompt)); + this.logger.log("curr_prompt: " + JSON.stringify(curr_prompt, (key, value) => { + if (typeof key === 'string' && key.endsWith('_api_key')) { + return '****************'; + } + return value; + }) + ); this.openChatGPT(fullPrompt, curr_prompt.action, tabs[0].id, curr_prompt.name, curr_prompt.need_custom_text, curr_prompt); taWorkingStatus.stopWorking(); return {ok:'1'}; From 84a65acd8fab550f1ae9197abe10356689fde724 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Sat, 3 Jan 2026 11:49:37 +0100 Subject: [PATCH 008/123] resolve rebase conflicts --- _locales/en/messages.json | 16 ++++++++++++++++ js/mzta-utils.js | 2 ++ mzta-background.js | 18 ++++++++++++++++++ options/mzta-options-default.js | 2 ++ options/mzta-options.html | 13 ++++++++++++- 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 1e8b9cac..432b6f34 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1195,6 +1195,18 @@ "message": "Manage spam filter settings", "description": "" }, + "prefs_OptionText_summarize": { + "message": "Summarize mail", + "description": "" + }, + "prefs_OptionText_summarize_Info": { + "message": "If checked, adds an option to context menu to summarize mail.", + "description": "" + }, + "prefs_OptionText_btnManageSummarizeInfo": { + "message": "Manage summarize settings", + "description": "" + }, "SpamFilter_PageTitle": { "message": "Manage Spam Filter Settings", "description": "" @@ -1295,6 +1307,10 @@ "message": "Analyze for spam", "description": "" }, + "context_menu_mzta-summary": { + "message": "Summarize", + "description": "" + }, "prefs_OptionText_add_tags_context_menu": { "message": "Show the \"Add tags\" context menu item", "description": "" diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 67ce0823..79216f9d 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -25,9 +25,11 @@ export const getMenuContextDisplay = () => 'message_display_action_menu'; export const contextMenuID_AddTags = 'mzta-add-tags'; export const contextMenuID_Spamfilter = 'mzta-spamfilter'; +export const contextMenuID_Summary = 'mzta-summary'; export const contextMenuIconsPath = { [contextMenuID_AddTags]: 'moz-extension:images/autotags.png', [contextMenuID_Spamfilter]: 'moz-extension:images/spamfilter.png', + // [contextMenuID_Summary]: 'moz-extension:images/summary.png', }; export function getLanguageDisplayName(languageCode) { diff --git a/mzta-background.js b/mzta-background.js index e2161b66..ce3d1d7b 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -45,6 +45,7 @@ import { extractJsonObject, contextMenuID_AddTags, contextMenuID_Spamfilter, + contextMenuID_Summary, contextMenuIconsPath, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, @@ -802,10 +803,12 @@ async function reload_pref_init(){ add_tags_auto_force_existing: prefs_default.add_tags_auto_force_existing, add_tags_auto_only_inbox: prefs_default.add_tags_auto_only_inbox, spamfilter: prefs_default.spamfilter, + summarize: prefs_default.summarize, spamfilter_threshold: prefs_default.spamfilter_threshold, dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, add_tags_context_menu: prefs_default.add_tags_context_menu, spamfilter_context_menu: prefs_default.spamfilter_context_menu, + summarize_context_menu: prefs_default.summarize_context_menu, ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); _process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter; @@ -917,6 +920,15 @@ function setupStorageChangeListener() { removeContextMenu(contextMenuID_Spamfilter); } } + if (changes.summarize) { + if (changes.summarize.newValue){ + if (prefs_init.summarize_context_menu){ + addContextMenu(contextMenuID_Summary); + } + } else { + removeContextMenu(contextMenuID_Summary); + } + } reload_pref_init(); } }); @@ -977,6 +989,12 @@ function addContextMenuItems() { if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && checkAPIIntegration(prefs_init.connection_type, prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type)){ addContextMenu(contextMenuID_Spamfilter); } + + // Add Context menu: Summary + if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { + console.log("adding summary to context menu") + addContextMenu(contextMenuID_Summary); + } } addContextMenuItems(); diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 66b24890..e14b2808 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -133,5 +133,7 @@ export const prefs_default = { spamfilter_threshold: 70, spamfilter_context_menu: true, spamfilter_enabled_accounts: [], + summarize: false, + summarize_context_menu: true, ...generated_prefs } diff --git a/options/mzta-options.html b/options/mzta-options.html index 0e24f172..99078369 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -147,6 +147,17 @@ + + __MSG_prefs_OptionText_summarize__ +
      + + + + " __MSG_prefs_OptionText_get_calendar_event__
      @@ -164,7 +175,7 @@ + From 050a3fd1f75e794cc885a0398b0c6d77f2de7b15 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 10:00:10 +0100 Subject: [PATCH 009/123] Add MZTA summary page --- pages/summary/mzta-summary.css | 0 pages/summary/mzta-summary.html | 0 pages/summary/mzta-summary.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pages/summary/mzta-summary.css create mode 100644 pages/summary/mzta-summary.html create mode 100644 pages/summary/mzta-summary.js diff --git a/pages/summary/mzta-summary.css b/pages/summary/mzta-summary.css new file mode 100644 index 00000000..e69de29b diff --git a/pages/summary/mzta-summary.html b/pages/summary/mzta-summary.html new file mode 100644 index 00000000..e69de29b diff --git a/pages/summary/mzta-summary.js b/pages/summary/mzta-summary.js new file mode 100644 index 00000000..e69de29b From 4ab6da2faf08ad0e1e4e357ccc306e7724bff2c6 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 13:09:25 +0100 Subject: [PATCH 010/123] change all "summary" -> "summarize" --- _locales/en/messages.json | 22 ++++- js/mzta-utils.js | 4 +- mzta-background.js | 8 +- options/mzta-options.js | 4 + pages/summarize/mzta-summarize.css | 123 ++++++++++++++++++++++++++++ pages/summarize/mzta-summarize.html | 30 +++++++ pages/summarize/mzta-summarize.js | 77 +++++++++++++++++ pages/summary/mzta-summary.css | 0 pages/summary/mzta-summary.html | 0 pages/summary/mzta-summary.js | 0 10 files changed, 261 insertions(+), 7 deletions(-) create mode 100644 pages/summarize/mzta-summarize.css create mode 100644 pages/summarize/mzta-summarize.html create mode 100644 pages/summarize/mzta-summarize.js delete mode 100644 pages/summary/mzta-summary.css delete mode 100644 pages/summary/mzta-summary.html delete mode 100644 pages/summary/mzta-summary.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 432b6f34..c98079bd 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1003,6 +1003,14 @@ "message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\n- Attendees\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nThese are the attendees: {%author%}, {%recipients%}, {%cc_list%}. If present, exclude my address: {%account_email_address%}.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHere's the text:\"{%selected_text%}\"", "description": "" }, + "prompt_summarize": { + "message": "Summarize this email or these emails", + "description": "" + }, + "prompt_summarize_full_text": { + "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.", + "description": "" + }, "prompt_get_task": { "message": "Add a new task", "description": "" @@ -1231,6 +1239,18 @@ "message": "Spam Filter Options", "description": "" }, + "Summarize_PageTitle": { + "message": "Manage Summarize Settings", + "description": "" + }, + "Summarize_info_default": { + "message": "In this page you can modify the default prompt used to summarize emails.", + "description": "" + }, + "Summarize_prompt_text_title": { + "message": "Current prompt text", + "description": "" + }, "prefs_OptionText_use_specific_integration": { "message": "Use specific Model and API", "description": "" @@ -1307,7 +1327,7 @@ "message": "Analyze for spam", "description": "" }, - "context_menu_mzta-summary": { + "context_menu_mzta-summarize": { "message": "Summarize", "description": "" }, diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 79216f9d..eb4f8d49 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -25,11 +25,11 @@ export const getMenuContextDisplay = () => 'message_display_action_menu'; export const contextMenuID_AddTags = 'mzta-add-tags'; export const contextMenuID_Spamfilter = 'mzta-spamfilter'; -export const contextMenuID_Summary = 'mzta-summary'; +export const contextMenuID_Summarize = 'mzta-summarize'; export const contextMenuIconsPath = { [contextMenuID_AddTags]: 'moz-extension:images/autotags.png', [contextMenuID_Spamfilter]: 'moz-extension:images/spamfilter.png', - // [contextMenuID_Summary]: 'moz-extension:images/summary.png', + // [contextMenuID_Summarize]: 'moz-extension:images/summarize.png', }; export function getLanguageDisplayName(languageCode) { diff --git a/mzta-background.js b/mzta-background.js index ce3d1d7b..5ceb483e 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -45,7 +45,7 @@ import { extractJsonObject, contextMenuID_AddTags, contextMenuID_Spamfilter, - contextMenuID_Summary, + contextMenuID_Summarize, contextMenuIconsPath, sanitizeChatGPTModelData, sanitizeChatGPTWebCustomData, @@ -990,10 +990,10 @@ function addContextMenuItems() { addContextMenu(contextMenuID_Spamfilter); } - // Add Context menu: Summary + // Add Context menu: Summarize if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { - console.log("adding summary to context menu") - addContextMenu(contextMenuID_Summary); + console.log("adding summarize to context menu") + addContextMenu(contextMenuID_Summariz); } } diff --git a/options/mzta-options.js b/options/mzta-options.js index 16b130fd..3b2ac351 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -291,6 +291,10 @@ document.addEventListener('DOMContentLoaded', async () => { document.getElementById('btnManageSpamFilterInfo').addEventListener('click', () => { openTab('/pages/spamfilter/mzta-spamfilter.html'); }); + + document.getElementById('btnManageSummarizeInfo').addEventListener('click', () => { + openTab('/pages/summarize/mzta-summarize.html'); + }); document.getElementById('btnManageCalendarEventInfo').addEventListener('click', () => { openTab('/pages/get-calendar-event/mzta-get-calendar-event.html'); diff --git a/pages/summarize/mzta-summarize.css b/pages/summarize/mzta-summarize.css new file mode 100644 index 00000000..173353e7 --- /dev/null +++ b/pages/summarize/mzta-summarize.css @@ -0,0 +1,123 @@ +#summarize_prompt_container { + width: 90%; + margin: 20px auto; +} + +#summarize_prompt_text { + width: 100%; +} + +.infoline { + font-size: 0.8em; + font-style: italic; +} + +.btn_div { + width: 100%; + display: flex; + justify-content: space-between; +} + +table#miczPrefs { + padding: 10px; + border-spacing: 0px; + width: 90%; + margin: 0px auto 40px auto; + border: 1px solid #ccc; +} + +.section_title { + font-weight: bold; +} + +table#miczPrefs td { + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + vertical-align: top; + padding: 2px; +} + +table#miczPrefs tr:first-child td { + border-top: none; +} + +table#miczPrefs tr:last-child td { + border-bottom: none; +} + +.autocomplete-container { + position: relative; +} + +.autocomplete-list { + position: absolute; + top: 100%; + left: 0; + right: 0; + background-color: white; + border: 1px solid #ccc; + z-index: 1000; + max-height: 200px; + overflow-y: auto; + padding: 0; + margin: 0; + list-style: none; + font-size: small; +} + +.autocomplete-list li { + padding: 8px; + cursor: pointer; +} + +.autocomplete-list li:hover { + background-color: #f0f0f0; +} + +.autocomplete-list li.active { + background-color: #ddd; +} + +.hidden { + display: none; +} + +.unsaved { + color: red; +} + +@media (prefers-color-scheme: dark) { + body { + background-color: #1c1b22; + color: rgb(251, 251, 254); + } + + a:link { + color: #409eff; + } + a:visited { + color: #409eff; + } + a:hover { + color: #66b1ff; + } + a:active { + color: #66b1ff; + } + a:active { + color: #66b1ff; + } + + .autocomplete-list { + background-color: #2e2f36; + border: 1px solid #2e2f36; + } + + .autocomplete-list li:hover { + background-color: #4c4e58; + } + + .autocomplete-list li.active { + background-color: #4c4e58; + } +} diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html new file mode 100644 index 00000000..7433ec82 --- /dev/null +++ b/pages/summarize/mzta-summarize.html @@ -0,0 +1,30 @@ + + + + + ThunderAI - __MSG_Summarize_PageTitle__ + + + + +
      +

      __MSG_Summarize_PageTitle__

      +

      __MSG_Summarize_info_default__

      +
      +
      + __MSG_Summarize_prompt_text_title__ + +
      __MSG_prefs_OptionText_btnManagePrompts_infoline__ __MSG_more_info_string__ +
      __MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__
      +
      +
      + + +
      +
      +
      +
      + + + + diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js new file mode 100644 index 00000000..646cb096 --- /dev/null +++ b/pages/summarize/mzta-summarize.js @@ -0,0 +1,77 @@ +/* + * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] + * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import { prefs_default } from "../../options/mzta-options-default.js"; +import { taLogger } from "../../js/mzta-logger.js"; +import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js"; +import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; +import { isAPIKeyValue } from "../../js/mzta-utils.js"; + +let autocompleteSuggestions = []; +let taLog = new taLogger("mzta-summarize-page", true); + +document.addEventListener("DOMContentLoaded", async () => { + + i18n.updateDocument(); + + + const summarize_textarea = document.getElementById("summarize_prompt_text"); + const summarize_save_btn = document.getElementById("btn_save_prompt"); + const summarize_reset_btn = document.getElementById("btn_reset_prompt"); + + let specialPrompts = await getSpecialPrompts(); + let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); + + summarize_textarea.addEventListener("input", (event) => { + summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); + summarize_save_btn.disabled = (event.target.value === summarize_prompt.text); + if (summarize_save_btn.disabled) { + document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); + } else { + document.getElementById("summarize_prompt_unsaved").classList.remove("hidden"); + } + }); + + summarize_reset_btn.addEventListener("click", () => { + summarize_textarea.value = browser.i18n.getMessage("prompt_summarize_full_text"); + summarize_reset_btn.disabled = true; + let event = new Event("input", { bubbles: true, cancelable: true }); + summarize_textarea.dispatchEvent(event); + }); + + summarize_save_btn.addEventListener("click", () => { + specialPrompts.find(prompt => prompt.id === 'prompt_summarize') + setSpecialPrompts(specialPrompts); + summarize_save_btn.disabled = true; + document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); + browser.runtime.sendMessage({ command: "reload_menus" }); + }); + + if(summarize_prompt.text === 'prompt_summarize_full_text'){ + summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); + } + summarize_textarea.value = summarize_prompt.text; + summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text")); + + autocompleteSuggestions = (await getPlaceholders(true)) + .filter((p) => p.id !== "additional_text") + .map((p) => ({ command: `{%${p.id}%}`, type: p.type })); + textareaAutocomplete(summarize_textarea, autocompleteSuggestions, 1); +}); + diff --git a/pages/summary/mzta-summary.css b/pages/summary/mzta-summary.css deleted file mode 100644 index e69de29b..00000000 diff --git a/pages/summary/mzta-summary.html b/pages/summary/mzta-summary.html deleted file mode 100644 index e69de29b..00000000 diff --git a/pages/summary/mzta-summary.js b/pages/summary/mzta-summary.js deleted file mode 100644 index e69de29b..00000000 From 02787e2f25584c736b93efbbfeac58b753aa1197 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 17:41:36 +0100 Subject: [PATCH 011/123] Fix context menu ID typos --- mzta-background.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 5ceb483e..4ef33580 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -923,10 +923,10 @@ function setupStorageChangeListener() { if (changes.summarize) { if (changes.summarize.newValue){ if (prefs_init.summarize_context_menu){ - addContextMenu(contextMenuID_Summary); + addContextMenu(contextMenuID_Summarize); } } else { - removeContextMenu(contextMenuID_Summary); + removeContextMenu(contextMenuID_Summarize); } } reload_pref_init(); @@ -993,7 +993,7 @@ function addContextMenuItems() { // Add Context menu: Summarize if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { console.log("adding summarize to context menu") - addContextMenu(contextMenuID_Summariz); + addContextMenu(contextMenuID_Summarize); } } From 8abb7e349bdf53db81452307a0a6e4eee8b15f8b Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 17:50:31 +0100 Subject: [PATCH 012/123] Add summarize prompt to specialPrompts --- js/mzta-prompts.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index b598cbce..4ea5d552 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -324,6 +324,22 @@ const specialPrompts = [ is_default: "1", is_special: "1", }, + { + id: 'prompt_summarize', + name: "__MSG_prompt_summarize__", + text: "prompt_summarize_full_text", + type: "1", + action: "0", + need_selected: "0", + need_signature: "0", + need_custom_text: "0", + define_response_lang: "0", + use_diff_viewer: "0", + api_type: '', + api_model: '', + is_default: "1", + is_special: "1", + } ]; From 2c07aa6336cb9aa58cd7dcda78210f8c236f47a6 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 17:51:24 +0100 Subject: [PATCH 013/123] Remove unused imports from mzta-summarize.js --- pages/summarize/mzta-summarize.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 646cb096..4eb831c0 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -16,12 +16,10 @@ * along with this program. If not, see . */ -import { prefs_default } from "../../options/mzta-options-default.js"; import { taLogger } from "../../js/mzta-logger.js"; import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js"; import { getPlaceholders } from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; -import { isAPIKeyValue } from "../../js/mzta-utils.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-summarize-page", true); @@ -37,7 +35,7 @@ document.addEventListener("DOMContentLoaded", async () => { let specialPrompts = await getSpecialPrompts(); let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); - + summarize_textarea.addEventListener("input", (event) => { summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); summarize_save_btn.disabled = (event.target.value === summarize_prompt.text); From 7eb9a2cf56e685e6dbbafb79d4f4651cfea438ef Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 19 Dec 2025 18:06:45 +0100 Subject: [PATCH 014/123] fixes saving of summarize prompt --- pages/summarize/mzta-summarize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 4eb831c0..93bb67e8 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -54,7 +54,7 @@ document.addEventListener("DOMContentLoaded", async () => { }); summarize_save_btn.addEventListener("click", () => { - specialPrompts.find(prompt => prompt.id === 'prompt_summarize') + specialPrompts.find(prompt => prompt.id === 'prompt_summarize').text = summarize_textarea.value; setSpecialPrompts(specialPrompts); summarize_save_btn.disabled = true; document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); From fe427c29eec5c1e55a39562428b678136e259916 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Tue, 23 Dec 2025 13:22:47 +0100 Subject: [PATCH 015/123] Add Email Template Editor to Summarize Panel --- _locales/en/messages.json | 10 +++++- js/mzta-prompts.js | 16 +++++++++ pages/summarize/mzta-summarize.css | 4 +++ pages/summarize/mzta-summarize.html | 51 ++++++++++++++++++++++++++--- pages/summarize/mzta-summarize.js | 42 +++++++++++++++++++----- 5 files changed, 108 insertions(+), 15 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c98079bd..c7ceded5 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1008,7 +1008,11 @@ "description": "" }, "prompt_summarize_full_text": { - "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.", + "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.\n------------------\n\n", + "description": "" + }, + "prompt_summarize_email_template": { + "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\nBody:\n{%mail_text_body%}\n---------------\n\n", "description": "" }, "prompt_get_task": { @@ -1075,6 +1079,10 @@ "message": "You can change the prompt as you wish, but the response received from the AI must be in JSON format as specified in the default prompt!", "description": "" }, + "prefs_OptionText_Summarize_infoline2": { + "message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt.", + "description": "" + }, "prefs_OptionText_get_calendar_event_Sparks_not_present": { "message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.", "description": "" diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 4ea5d552..f68a3997 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -339,6 +339,22 @@ const specialPrompts = [ api_model: '', is_default: "1", is_special: "1", + }, + { + id: 'prompt_summarize_email_template', + name: "__MSG_prompt_summarize_email_template__", + text: "prompt_summarize_email_template_full_text", + type: "1", + action: "0", + need_selected: "0", + need_signature: "0", + need_custom_text: "0", + define_response_lang: "0", + use_diff_viewer: "0", + api_type: '', + api_model: '', + is_default: "1", + is_special: "1", } ]; diff --git a/pages/summarize/mzta-summarize.css b/pages/summarize/mzta-summarize.css index 173353e7..f4bbc091 100644 --- a/pages/summarize/mzta-summarize.css +++ b/pages/summarize/mzta-summarize.css @@ -3,6 +3,10 @@ margin: 20px auto; } +#summarize_email_template_text { + width: 100%; +} + #summarize_prompt_text { width: 100%; } diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html index 7433ec82..54405840 100644 --- a/pages/summarize/mzta-summarize.html +++ b/pages/summarize/mzta-summarize.html @@ -12,17 +12,58 @@

      __MSG_Summarize_info_default__

    - __MSG_Summarize_prompt_text_title__ - -
    __MSG_prefs_OptionText_btnManagePrompts_infoline__ __MSG_more_info_string__ -
    __MSG_prefs_OptionText_AdvancedPromptResponse_infoline2__
    + + + __MSG_Summarize_prompt_text_title__ + +
    + + + __MSG_prefs_OptionText_btnManagePrompts_infoline__ + + __MSG_more_info_string__ + + +
    + + __MSG_prefs_OptionText_Summarize_infoline2__ +
    + +
    + +
    +
    -
    +
    + + +
    + + +
    + + +
    + +
    +
    + + +
    +
    diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 93bb67e8..45f7463f 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -32,41 +32,65 @@ document.addEventListener("DOMContentLoaded", async () => { const summarize_textarea = document.getElementById("summarize_prompt_text"); const summarize_save_btn = document.getElementById("btn_save_prompt"); const summarize_reset_btn = document.getElementById("btn_reset_prompt"); + const summarize_textarea_email_template = document.getElementById("summarize_email_template_text"); + const summarize_reset_email_template_btn = document.getElementById("btn_reset_email_template"); + const summarize_save_email_template_btn = document.getElementById("btn_save_email_template"); let specialPrompts = await getSpecialPrompts(); let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); + let summarize_email_template = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); summarize_textarea.addEventListener("input", (event) => { summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); summarize_save_btn.disabled = (event.target.value === summarize_prompt.text); - if (summarize_save_btn.disabled) { - document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); - } else { - document.getElementById("summarize_prompt_unsaved").classList.remove("hidden"); - } }); - + + summarize_textarea_email_template.addEventListener("input", (event) => { + summarize_reset_email_template_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_template')); + summarize_save_email_template_btn.disabled = (event.target.value === summarize_email_template.text); + }); + + summarize_reset_email_template_btn.addEventListener("click", () => { + summarize_textarea_email_template.value = browser.i18n.getMessage("prompt_summarize_email_template"); + summarize_reset_email_template_btn.disabled = true; + let event = new Event("input", { bubbles: true, cancelable: true }); + summarize_textarea_email_template.dispatchEvent(event); + }); + summarize_reset_btn.addEventListener("click", () => { summarize_textarea.value = browser.i18n.getMessage("prompt_summarize_full_text"); summarize_reset_btn.disabled = true; let event = new Event("input", { bubbles: true, cancelable: true }); summarize_textarea.dispatchEvent(event); }); - + + summarize_save_email_template_btn.addEventListener("click", () => { + specialPrompts.find(prompt => prompt.id === 'prompt_summarize_email_template').text = summarize_textarea_email_template.value; + setSpecialPrompts(specialPrompts); + summarize_save_email_template_btn.disabled = true; + browser.runtime.sendMessage({ command: "reload_menus" }); + }); + summarize_save_btn.addEventListener("click", () => { specialPrompts.find(prompt => prompt.id === 'prompt_summarize').text = summarize_textarea.value; setSpecialPrompts(specialPrompts); summarize_save_btn.disabled = true; - document.getElementById("summarize_prompt_unsaved").classList.add("hidden"); browser.runtime.sendMessage({ command: "reload_menus" }); }); if(summarize_prompt.text === 'prompt_summarize_full_text'){ summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); } + if(summarize_email_template === 'prompt_summarize_email_template'){ + summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text); + } + + summarize_textarea_email_template.value = summarize_email_template.text; + summarize_reset_email_template_btn.disabled = (summarize_email_template.value === browser.i18n.getMessage("prompt_summarize_email_template")); + summarize_textarea.value = summarize_prompt.text; summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text")); - + autocompleteSuggestions = (await getPlaceholders(true)) .filter((p) => p.id !== "additional_text") .map((p) => ({ command: `{%${p.id}%}`, type: p.type })); From f29d8337adeaca64b9df4ed8b76c0ea347a6ad97 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Tue, 23 Dec 2025 13:23:09 +0100 Subject: [PATCH 016/123] WIP: Add Summarize context menu action and handler --- mzta-background.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/mzta-background.js b/mzta-background.js index 4ef33580..8d1659ab 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1003,17 +1003,70 @@ addContextMenuItems(); browser.menus.onClicked.addListener( (info, tab) => { let _add_tags = false let _spamfilter = false + let _summarize = false; if(info.menuItemId === contextMenuID_AddTags){ _add_tags = true; } if(info.menuItemId === contextMenuID_Spamfilter){ _spamfilter = true; } + if(info.menuItemId === contextMenuID_Summarize) { + _summarize = true; + } if(_add_tags || _spamfilter){ processEmails(getMessages(info.selectedMessages), _add_tags, _spamfilter); } + if(_summarize) { + summarizeEmails(getMessages(info.selectedMessages)); + } }); +async function summarizeEmails(messages) { + taWorkingStatus.startWorking(); + // generate the special prompt for summarization + + // - make a long string of all the emails + let emails_content = ''; + for await (let message of messages) { +////// TODO: make this customizable through placeholders! +// plan: make a second option field where placeholders can be used and +// simply add the result from that tepmlate to the end of the prompt option +// field + emails_content += "\n\n---\n\n"; + let curr_fullMessage = await browser.messages.getFull(message.id); + + // from + curr_fullMessage + + // to + // cc + // bcc + // subject + // date + // attachment info + + // body + let msg_text = getMailBody(curr_fullMessage) + let body_text = htmlBodyToPlainText(msg_text.html); + + if( body_text.length == 0 ){ + taLog.log("No HTML found in the message body, using plain text..."); + body_text = msg_text.text.replace(/\s+/g, ' ').trim(); + }; + emails_content += body_text; + + }; + emails_content += "\n\n---\n\n"; + + // - join prompt and emails + + taWorkingStatus.stopWorking(); + // send to LLM + + console.log(emails_content); + +} + // Listening for new received emails const newEmailListener = (folder, messagesList) => { From 7595c70a3834fc97a0139f30026f8d03bbeddaee Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 2 Jan 2026 20:39:35 +0100 Subject: [PATCH 017/123] Implement summarization internals --- mzta-background.js | 92 ++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 8d1659ab..5b92c76c 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -58,7 +58,10 @@ import { } from './js/mzta-utils.js'; import { taPromptUtils } from './js/mzta-utils-prompt.js'; import { mzta_specialCommand } from './js/mzta-special-commands.js'; -import { getSpamFilterPrompt } from './js/mzta-prompts.js'; +import { + getSpamFilterPrompt, + getSpecialPrompts +} from './js/mzta-prompts.js'; import { taSpamReport } from './js/mzta-spamreport.js'; import { taWorkingStatus } from './js/mzta-working-status.js'; import { addTags_getExclusionList, checkExcludedTag } from './js/mzta-addatags-exclusion-list.js'; @@ -1017,54 +1020,63 @@ browser.menus.onClicked.addListener( (info, tab) => { processEmails(getMessages(info.selectedMessages), _add_tags, _spamfilter); } if(_summarize) { + // info.selectedMessages is of type MessageList summarizeEmails(getMessages(info.selectedMessages)); } }); async function summarizeEmails(messages) { taWorkingStatus.startWorking(); - // generate the special prompt for summarization - - // - make a long string of all the emails - let emails_content = ''; - for await (let message of messages) { -////// TODO: make this customizable through placeholders! -// plan: make a second option field where placeholders can be used and -// simply add the result from that tepmlate to the end of the prompt option -// field - emails_content += "\n\n---\n\n"; - let curr_fullMessage = await browser.messages.getFull(message.id); - - // from - curr_fullMessage - - // to - // cc - // bcc - // subject - // date - // attachment info - - // body - let msg_text = getMailBody(curr_fullMessage) - let body_text = htmlBodyToPlainText(msg_text.html); - - if( body_text.length == 0 ){ - taLog.log("No HTML found in the message body, using plain text..."); - body_text = msg_text.text.replace(/\s+/g, ' ').trim(); - }; - emails_content += body_text; - - }; - emails_content += "\n\n---\n\n"; - // - join prompt and emails + // we have two prompts, the actual assignment for the LLM and the email + // template prompt. + const specialPrompts = await getSpecialPrompts(); + const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); + const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); + + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); + + // assemble all email messages into one string and add the assignment prompt + let messages_list = []; + for await (let curr_message of messages) { + + // extract body of current message as text + let curr_message_full = await browser.messages.getFull(curr_message.id); + let curr_body_full_html = getMailBody(curr_message_full); + let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html); + if( curr_body_full_text.length === 0) { + taLog.log("No HTML found in the message body, using plain text..."); + curr_body_full_text = curr_message_full.text; + } + + messages_list.push(await taPromptUtils.preparePrompt({ + curr_prompt: prompt_email, + curr_message: curr_message, + chatgpt_lang: chatgpt_lang, + body_text: curr_body_full_text, + subject_text: curr_message_full.headers.subject, + msg_text: curr_body_full_html, + })); + }; + let messages_string = messages_list.join("\n\n--- Next Email ---\n\n"); + + let full_prompt = prompt.text + "\n\n\n" + messages_string; + + console.log(full_prompt); + + // send the prompt to the chat interface + openChatGPT( + full_prompt, + prompt.action, + tabs[0].id, + prompt.name, + prompt.need_custom_text, + prompt + ) taWorkingStatus.stopWorking(); - // send to LLM - - console.log(emails_content); - + return {ok : '1'}; } From c3e27f03564703ce5344faa6c3ec9fe32932bc30 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 2 Jan 2026 21:42:44 +0100 Subject: [PATCH 018/123] Fix malformed label closing tag in options page --- options/mzta-options.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/mzta-options.html b/options/mzta-options.html index 99078369..02b0f6ea 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -175,7 +175,7 @@ From 3d2c2b93208771187f6ad93882a5efe477f076d5 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Sat, 3 Jan 2026 22:18:00 +0100 Subject: [PATCH 019/123] add customizable model options for summarize --- _locales/en/messages.json | 8 ++ pages/summarize/mzta-summarize.css | 92 +++++++++++--- pages/summarize/mzta-summarize.html | 24 +++- pages/summarize/mzta-summarize.js | 181 +++++++++++++++++++++++++--- 4 files changed, 270 insertions(+), 35 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c7ceded5..a7a0102d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1003,6 +1003,10 @@ "message": "Extract all relevant details required to generate a calendar event from the following text. The extracted information should include:\n- Event Title\n- Start Date and Time (including timezone, if specified)\n- End Date and Time (including timezone, if specified)\n- Full day (if mentioned)\n- Attendees\nEnsure the data is formatted clearly and consistently so that it can be directly used for creating a calendar event.\nIf there are relative time references, consider that the date and time of the email are \"{%mail_datetime%}\". Calculate the start date and time based on this reference. If the calculated start date and time are earlier than \"{%current_datetime%}\", recalculate the start date and time using \"{%current_datetime%}\" as the base.\nIf the duration is not specified, set it to one hour.\nThese are the attendees: {%author%}, {%recipients%}, {%cc_list%}. If present, exclude my address: {%account_email_address%}.\nIf you're not able to get one or more of the required information, please respond with an empty string.\nGenerate a response in JSON format only. Do not include any additional text or explanations; provide only the JSON. Here is the format to be used:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"Calendar event summary here\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHere's the text:\"{%selected_text%}\"", "description": "" }, + "Summarize_prompt_prefs_title": { + "message": "Add Summarization Options", + "description": "" + }, "prompt_summarize": { "message": "Summarize this email or these emails", "description": "" @@ -1215,6 +1219,10 @@ "message": "Summarize mail", "description": "" }, + "prefs_OptionText_summarize_use_specific_integration_Info": { + "message": "If checked, the Model and API specified below will be used for summarizing email(s), regardless the one choosen in the ThunderAI options page.", + "description": "" + }, "prefs_OptionText_summarize_Info": { "message": "If checked, adds an option to context menu to summarize mail.", "description": "" diff --git a/pages/summarize/mzta-summarize.css b/pages/summarize/mzta-summarize.css index f4bbc091..26b08e10 100644 --- a/pages/summarize/mzta-summarize.css +++ b/pages/summarize/mzta-summarize.css @@ -16,6 +16,49 @@ font-style: italic; } +#account_selector_container{ + display: none; +} + +#account_selector_checkboxes{ + padding: 10px; + border: 1px solid gray; + width: 24em; + margin-bottom: 10px; + margin-top: 10px; +} + +.specific_integration{ + background-color: #dfeaff; +} + +table { + border-collapse: separate; + border-spacing: 0; +} + +.group td { + border-top: none; + border-bottom: none; +} + +.specific_integration_sub td:first-child { + border-left: 10px solid #dfeaff; +} + +.specific_integration_sub td:last-child { + border-right: 10px solid #dfeaff; +} + +#connection_ui_end td{ + height: 6px; + background-color: #dfeaff; +} + +#connection_ui_end{ + display: none; +} + .btn_div { width: 100%; display: flex; @@ -30,6 +73,11 @@ table#miczPrefs { border: 1px solid #ccc; } +.addtags_table_title{ + width: 90%; + margin: auto; +} + .section_title { font-weight: bold; } @@ -90,27 +138,21 @@ table#miczPrefs tr:last-child td { color: red; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} + @media (prefers-color-scheme: dark) { body { background-color: #1c1b22; color: rgb(251, 251, 254); } - a:link { - color: #409eff; - } - a:visited { - color: #409eff; - } - a:hover { - color: #66b1ff; - } - a:active { - color: #66b1ff; - } - a:active { - color: #66b1ff; - } + a:link { color: #409eff; } + a:visited { color: #409eff; } + a:hover { color: #66b1ff; } + a:active { color: #66b1ff; } + a:active { color: #66b1ff; } .autocomplete-list { background-color: #2e2f36; @@ -124,4 +166,24 @@ table#miczPrefs tr:last-child td { .autocomplete-list li.active { background-color: #4c4e58; } + + .summarize_auto{ + background-color: #415c35; + } + + .specific_integration{ + background-color: #2E3A4F; + } + + .specific_integration_sub td:first-child { + border-left: 10px solid #2E3A4F; + } + + .specific_integration_sub td:last-child { + border-right: 10px solid #2E3A4F; + } + + #connection_ui_end td{ + background-color: #2E3A4F; + } } diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html index 54405840..82679339 100644 --- a/pages/summarize/mzta-summarize.html +++ b/pages/summarize/mzta-summarize.html @@ -4,13 +4,29 @@ ThunderAI - __MSG_Summarize_PageTitle__ + -
    -

    __MSG_Summarize_PageTitle__

    -

    __MSG_Summarize_info_default__

    -
    +
    +

    __MSG_Summarize_PageTitle__

    +

    __MSG_Summarize_info_default__

    +
    +
    __MSG_Summarize_prompt_prefs_title__
    + + + + + + + +
    __MSG_prefs_OptionText_use_specific_integration__ + + +
    diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 45f7463f..20252fc4 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -16,29 +16,71 @@ * along with this program. If not, see . */ +import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; import { taLogger } from "../../js/mzta-logger.js"; -import { getSpecialPrompts, setSpecialPrompts } from "../../js/mzta-prompts.js"; -import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { + getSpecialPrompts, + setSpecialPrompts +} from "../../js/mzta-prompts.js"; +import { + getPlaceholders, + mapPlaceholderToSuggestion +} from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; +import { + getAccountsList, + normalizeStringList, + isAPIKeyValue +} from "../../js/mzta-utils.js"; +import { + initializeSpecificIntegrationUI +} from "../_lib/connection-ui.js"; let autocompleteSuggestions = []; let taLog = new taLogger("mzta-summarize-page", true); document.addEventListener("DOMContentLoaded", async () => { - i18n.updateDocument(); - - - const summarize_textarea = document.getElementById("summarize_prompt_text"); - const summarize_save_btn = document.getElementById("btn_save_prompt"); - const summarize_reset_btn = document.getElementById("btn_reset_prompt"); - const summarize_textarea_email_template = document.getElementById("summarize_email_template_text"); - const summarize_reset_email_template_btn = document.getElementById("btn_reset_email_template"); - const summarize_save_email_template_btn = document.getElementById("btn_save_email_template"); - let specialPrompts = await getSpecialPrompts(); let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); let summarize_email_template = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); + + if (summarize_prompt && summarize_prompt.api_type && summarize_prompt.api_type !== '') { + let update_prefs = {}; + update_prefs['summarize_connection_type'] = summarize_prompt.api_type; + + let integration = summarize_prompt.api_type.replace('_api', ''); + if (integration_options_config && integration_options_config[integration]) { + for (const key of Object.keys(integration_options_config[integration])) { + if (summarize_prompt[key] !== undefined) { + update_prefs[`summarize_${integration}_${key}`] = summarize_prompt[key]; + } + } + } + await browser.storage.sync.set(update_prefs); + } + + await initializeSpecificIntegrationUI({ + prefix: 'summarize', + promptId: 'prompt_summarize', + taLog: taLog, + restoreOptionsCallback: restoreOptions + }); + + i18n.updateDocument(); + + document.querySelectorAll(".option-input").forEach(element => { + element.addEventListener("change", saveOptions); + }); + let prefs_summarize = await browser.storage.sync.get({ summarize_enabled_accounts: [], connection_type: 'chatgpt_web' }); + + let summarize_textarea = document.getElementById("summarize_prompt_text"); + let summarize_save_btn = document.getElementById("btn_save_prompt"); + let summarize_reset_btn = document.getElementById("btn_reset_prompt"); + let summarize_textarea_email_template = document.getElementById("summarize_email_template_text"); + let summarize_reset_email_template_btn = document.getElementById("btn_reset_email_template"); + let summarize_save_email_template_btn = document.getElementById("btn_save_email_template"); + summarize_textarea.addEventListener("input", (event) => { summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); @@ -84,16 +126,123 @@ document.addEventListener("DOMContentLoaded", async () => { if(summarize_email_template === 'prompt_summarize_email_template'){ summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text); } - summarize_textarea_email_template.value = summarize_email_template.text; summarize_reset_email_template_btn.disabled = (summarize_email_template.value === browser.i18n.getMessage("prompt_summarize_email_template")); - summarize_textarea.value = summarize_prompt.text; summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text")); - + autocompleteSuggestions = (await getPlaceholders(true)) .filter((p) => p.id !== "additional_text") - .map((p) => ({ command: `{%${p.id}%}`, type: p.type })); + .map(mapPlaceholderToSuggestion); textareaAutocomplete(summarize_textarea, autocompleteSuggestions, 1); + textareaAutocomplete(summarize_textarea_email_template, autocompleteSuggestions, 1); + }); +// Methods to manage options, derived from: /options/mzta-options.js + +function saveOptions(e) { + e.preventDefault(); + let options = {}; + let element = e.target; + // console.log(">>>>>>>>>> Saving option: " + element.id + " = " + element.value); + switch (element.type) { + case 'checkbox': + options[element.id] = element.checked; + break; + case 'number': + options[element.id] = element.valueAsNumber; + break; + case 'text': + case 'password': + options[element.id] = element.value.trim(); + break; + case 'select-one': + // console.log(">>>>>>>>>> Saving option [select-one]: " + element.id + " = " + element.value); + options[element.id] = element.value; + break; + case 'textarea': + if(element.id === 'add_tags_auto_uselist_list') { + element.value = normalizeStringList(element.value, 1); + } + options[element.id] = normalizeStringList(element.value); + break; + default: + console.error("[ThunderAI] Unhandled input type:", element.type); + } + + browser.storage.sync.set(options); +} + +async function restoreOptions() { + function setCurrentChoice(result) { + document.querySelectorAll(".option-input").forEach(element => { + taLog.log("Options restoring " + element.id + " = " + (isAPIKeyValue(element.id) ? "****************" : result[element.id])); + switch (element.type) { + case 'checkbox': + element.checked = result[element.id] || false; + break; + case 'number': + let default_number_value = 0; + if(element.id == 'chatgpt_win_height') default_number_value = prefs_default.chatgpt_win_height; + if(element.id == 'chatgpt_win_width') default_number_value = prefs_default.chatgpt_win_width; + element.value = result[element.id] ?? default_number_value; + break; + case 'text': + case 'textarea': + case 'password': + let default_text_value = ''; + if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang; + if(element.id === 'add_tags_auto_uselist_list') { + result[element.id] = normalizeStringList(result[element.id], 1); + } + element.value = result[element.id] || default_text_value; + break; + default: + if (element.tagName === 'SELECT') { + let default_select_value = ''; + const restoreValue = result[element.id] || default_select_value; + // Check if option exists + let optionExists = Array.from(element.options).some(opt => opt.value === restoreValue); + // If it doesn't exist and restoreValue is not empty, create it + if (!optionExists && restoreValue !== '') { + let newOption = new Option(restoreValue, restoreValue); + element.add(newOption); + } + // Set value + element.value = restoreValue; + if (element.value === '') { + element.selectedIndex = -1; + } + }else{ + console.error("[ThunderAI] Unhandled input type:", element.type); + } + } + }); + } + + let getting = await browser.storage.sync.get(prefs_default); + + let specialPrompts = await getSpecialPrompts(); + let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); + + if (addtags_prompt) { + if (addtags_prompt.api_type && addtags_prompt.api_type !== '') { + getting['add_tags_connection_type'] = addtags_prompt.api_type; + } else { + getting['add_tags_connection_type'] = getting['connection_type']; + } + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + if (addtags_prompt[propName] !== undefined && addtags_prompt[propName] !== '') { + getting[`add_tags_${propName}`] = addtags_prompt[propName]; + } else { + getting[`add_tags_${propName}`] = getting[propName]; + } + } + } + } + + setCurrentChoice(getting); +} From 66cc35746f7b8299117a8b852c83b7eb56019db7 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Wed, 7 Jan 2026 20:40:15 +0100 Subject: [PATCH 020/123] move email separators to extra prompt field --- _locales/en/messages.json | 8 +++++-- js/mzta-prompts.js | 18 ++++++++++++++- mzta-background.js | 11 +++++---- pages/summarize/mzta-summarize.css | 4 ++++ pages/summarize/mzta-summarize.html | 16 +++++++++++++ pages/summarize/mzta-summarize.js | 36 +++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 8 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a7a0102d..08f5a2f8 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1012,11 +1012,15 @@ "description": "" }, "prompt_summarize_full_text": { - "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.\n------------------\n\n", + "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.", "description": "" }, "prompt_summarize_email_template": { - "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\nBody:\n{%mail_text_body%}\n---------------\n\n", + "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\nBody:\n{%mail_text_body%}", + "description": "" + }, + "prompt_summarize_email_separator": { + "message": "\n\n---------- NEXT EMAIL ----------\n\n", "description": "" }, "prompt_get_task": { diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index f68a3997..76736064 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -355,6 +355,22 @@ const specialPrompts = [ api_model: '', is_default: "1", is_special: "1", + }, + { + id: 'prompt_summarize_email_separator', + name: "__MSG_prompt_summarize_email_separator__", + text: "prompt_summarize_email_separator_full_text", + type: "1", + action: "0", + need_selected: "0", + need_signature: "0", + need_custom_text: "0", + define_response_lang: "0", + use_diff_viewer: "0", + api_type: '', + api_model: '', + is_default: "1", + is_special: "1", } ]; @@ -619,4 +635,4 @@ export async function clearPromptAPI(id){ } // console.log(">>>>>>>>>>>>> clearPromptAPI _prompt AFTER: " + JSON.stringify(_prompt)); await savePrompt(_prompt); -} \ No newline at end of file +} diff --git a/mzta-background.js b/mzta-background.js index 5b92c76c..46370b6f 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1028,11 +1028,12 @@ browser.menus.onClicked.addListener( (info, tab) => { async function summarizeEmails(messages) { taWorkingStatus.startWorking(); - // we have two prompts, the actual assignment for the LLM and the email - // template prompt. + // we have three prompts, the actual assignment for the LLM, the email + // template prompt, and the email separator prompt const specialPrompts = await getSpecialPrompts(); const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); + const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator'); const tabs = await browser.tabs.query({ active: true, currentWindow: true }); const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); @@ -1059,11 +1060,11 @@ async function summarizeEmails(messages) { msg_text: curr_body_full_html, })); }; - let messages_string = messages_list.join("\n\n--- Next Email ---\n\n"); + const messages_string = messages_list.join(prompt_email_separator_string); - let full_prompt = prompt.text + "\n\n\n" + messages_string; + const full_prompt = prompt_string + prompt_email_separator_string + messages_string; - console.log(full_prompt); + // console.log(full_prompt); // send the prompt to the chat interface openChatGPT( diff --git a/pages/summarize/mzta-summarize.css b/pages/summarize/mzta-summarize.css index 26b08e10..add7a975 100644 --- a/pages/summarize/mzta-summarize.css +++ b/pages/summarize/mzta-summarize.css @@ -11,6 +11,10 @@ width: 100%; } +#summarize_email_separator_text { + width: 100%; +} + .infoline { font-size: 0.8em; font-style: italic; diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html index 82679339..12c94b3c 100644 --- a/pages/summarize/mzta-summarize.html +++ b/pages/summarize/mzta-summarize.html @@ -79,6 +79,22 @@ __MSG_save__
    + + +
    + + +
    + +
    +
    + + +
    diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 20252fc4..bd57c0c5 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -44,6 +44,7 @@ document.addEventListener("DOMContentLoaded", async () => { let specialPrompts = await getSpecialPrompts(); let summarize_prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); let summarize_email_template = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); + let summarize_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator'); if (summarize_prompt && summarize_prompt.api_type && summarize_prompt.api_type !== '') { let update_prefs = {}; @@ -80,8 +81,12 @@ document.addEventListener("DOMContentLoaded", async () => { let summarize_textarea_email_template = document.getElementById("summarize_email_template_text"); let summarize_reset_email_template_btn = document.getElementById("btn_reset_email_template"); let summarize_save_email_template_btn = document.getElementById("btn_save_email_template"); + let summarize_email_separator_textarea = document.getElementById("summarize_email_separator_text"); + let summarize_email_separator_save_btn = document.getElementById("btn_save_email_separator"); + let summarize_email_separator_reset_btn = document.getElementById("btn_reset_email_separator"); + // on changing textareas summarize_textarea.addEventListener("input", (event) => { summarize_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_full_text')); summarize_save_btn.disabled = (event.target.value === summarize_prompt.text); @@ -91,7 +96,14 @@ document.addEventListener("DOMContentLoaded", async () => { summarize_reset_email_template_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_template')); summarize_save_email_template_btn.disabled = (event.target.value === summarize_email_template.text); }); + + summarize_email_separator_textarea.addEventListener("input", (event) => { + summarize_email_separator_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_separator')); + summarize_email_separator_save_btn.disabled = (event.target.value === summarize_email_separator.text); + }); + + // on clicking buttons, reset summarize_reset_email_template_btn.addEventListener("click", () => { summarize_textarea_email_template.value = browser.i18n.getMessage("prompt_summarize_email_template"); summarize_reset_email_template_btn.disabled = true; @@ -105,7 +117,15 @@ document.addEventListener("DOMContentLoaded", async () => { let event = new Event("input", { bubbles: true, cancelable: true }); summarize_textarea.dispatchEvent(event); }); + + summarize_email_separator_reset_btn.addEventListener("click", () => { + summarize_email_separator_textarea.value = browser.i18n.getMessage("prompt_summarize_email_separator"); + summarize_email_separator_reset_btn.disabled = true; + let event = new Event("input", { bubbles: true, cancelable: true }); + summarize_email_separator_textarea.dispatchEvent(event); + }); + // on clicking buttons, save summarize_save_email_template_btn.addEventListener("click", () => { specialPrompts.find(prompt => prompt.id === 'prompt_summarize_email_template').text = summarize_textarea_email_template.value; setSpecialPrompts(specialPrompts); @@ -119,6 +139,14 @@ document.addEventListener("DOMContentLoaded", async () => { summarize_save_btn.disabled = true; browser.runtime.sendMessage({ command: "reload_menus" }); }); + + summarize_email_separator_save_btn.addEventListener("click", () => { + specialPrompts.find(prompt => prompt.id === 'prompt_summarize_email_separator').text = summarize_email_separator_textarea.value; + setSpecialPrompts(specialPrompts); + summarize_email_separator_save_btn.disabled = true; + browser.runtime.sendMessage({ command: "reload_menus" }); + }); + if(summarize_prompt.text === 'prompt_summarize_full_text'){ summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); @@ -126,16 +154,24 @@ document.addEventListener("DOMContentLoaded", async () => { if(summarize_email_template === 'prompt_summarize_email_template'){ summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text); } + if(summarize_email_separator.text === 'prompt_summarize_email_separator'){ + summarize_email_separator.text = browser.i18n.getMessage(summarize_email_separator.text); + } + summarize_textarea_email_template.value = summarize_email_template.text; summarize_reset_email_template_btn.disabled = (summarize_email_template.value === browser.i18n.getMessage("prompt_summarize_email_template")); summarize_textarea.value = summarize_prompt.text; summarize_reset_btn.disabled = (summarize_textarea.value === browser.i18n.getMessage("prompt_summarize_full_text")); + summarize_email_separator_textarea.value = summarize_email_separator.text; + summarize_email_separator_reset_btn.disabled = (summarize_email_separator.value === browser.i18n.getMessage("prompt_summarize_email_separator")); autocompleteSuggestions = (await getPlaceholders(true)) .filter((p) => p.id !== "additional_text") .map(mapPlaceholderToSuggestion); + textareaAutocomplete(summarize_textarea, autocompleteSuggestions, 1); textareaAutocomplete(summarize_textarea_email_template, autocompleteSuggestions, 1); + textareaAutocomplete(summarize_email_separator_textarea, autocompleteSuggestions, 1); }); From 24edcc09e6875b15fa500ad1c23a5d132b918118 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Wed, 7 Jan 2026 20:40:43 +0100 Subject: [PATCH 021/123] make some variables const --- mzta-background.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 46370b6f..40532152 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1039,13 +1039,13 @@ async function summarizeEmails(messages) { const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); // assemble all email messages into one string and add the assignment prompt - let messages_list = []; + const messages_list = []; for await (let curr_message of messages) { // extract body of current message as text - let curr_message_full = await browser.messages.getFull(curr_message.id); - let curr_body_full_html = getMailBody(curr_message_full); - let curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html); + const curr_message_full = await browser.messages.getFull(curr_message.id); + const curr_body_full_html = getMailBody(curr_message_full); + const curr_body_full_text = htmlBodyToPlainText(curr_body_full_html.html); if( curr_body_full_text.length === 0) { taLog.log("No HTML found in the message body, using plain text..."); curr_body_full_text = curr_message_full.text; From c6bf2edba50f53babfbc13b2aba0a788ee30edfa Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Wed, 7 Jan 2026 20:40:58 +0100 Subject: [PATCH 022/123] allow placeholders in other summarize prompts --- mzta-background.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mzta-background.js b/mzta-background.js index 40532152..c06d5c0b 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1037,6 +1037,19 @@ async function summarizeEmails(messages) { const tabs = await browser.tabs.query({ active: true, currentWindow: true }); const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); + + // replace placeholders in the prompts the assignment prompt and email + // separator prompt do not have a message as context, so there is only + // limited things to replace + const prompt_string = await taPromptUtils.preparePrompt({ + curr_prompt: prompt, + chatgpt_lang: chatgpt_lang, + }); + const prompt_email_separator_string = await taPromptUtils.preparePrompt({ + curr_prompt: prompt_email_separator, + chatgpt_lang: chatgpt_lang, + }); + // assemble all email messages into one string and add the assignment prompt const messages_list = []; From c261c1da9049be324977c141c709d082cc10e158 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Wed, 7 Jan 2026 20:41:18 +0100 Subject: [PATCH 023/123] fix bug --- pages/summarize/mzta-summarize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index bd57c0c5..ea8d8364 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -151,7 +151,7 @@ document.addEventListener("DOMContentLoaded", async () => { if(summarize_prompt.text === 'prompt_summarize_full_text'){ summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); } - if(summarize_email_template === 'prompt_summarize_email_template'){ + if(summarize_email_template.text === 'prompt_summarize_email_template'){ summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text); } if(summarize_email_separator.text === 'prompt_summarize_email_separator'){ From 30a7de3756575fc8c292422dbfd8f5ad4fc3ff95 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Wed, 7 Jan 2026 20:43:42 +0100 Subject: [PATCH 024/123] better explanation --- _locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 08f5a2f8..f64feb2d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1088,7 +1088,7 @@ "description": "" }, "prefs_OptionText_Summarize_infoline2": { - "message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt.", + "message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt. Emails will be separated by the separator specified in the third field.", "description": "" }, "prefs_OptionText_get_calendar_event_Sparks_not_present": { From d601121852e8ab6095de7d8e3d177afc4067a065 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Sat, 10 Jan 2026 22:59:26 +0100 Subject: [PATCH 025/123] better descriptions for prompts --- _locales/en/messages.json | 12 ++++++++++++ pages/summarize/mzta-summarize.html | 22 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index f64feb2d..2d7329ec 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1091,6 +1091,18 @@ "message": "You can change the prompt as you wish, the first field is the main prompt, the second field is the template for a single mail. The list of emails will be appended to the main prompt. Emails will be separated by the separator specified in the third field.", "description": "" }, + "prefs_OptionText_Summarize_main_prompt": { + "message": "The main prompt describing the task to be performed on all selected emails:", + "description": "" + }, + "prefs_OptionText_Summarize_email_template": { + "message": "The template for a single email:", + "description": "" + }, + "prefs_OptionText_Summarize_email_separator": { + "message": "The separator between emails:", + "description": "" + }, "prefs_OptionText_get_calendar_event_Sparks_not_present": { "message": "To use the calendar event and task features, please install the ThunderAI Sparks addon.", "description": "" diff --git a/pages/summarize/mzta-summarize.html b/pages/summarize/mzta-summarize.html index 12c94b3c..a8db111d 100644 --- a/pages/summarize/mzta-summarize.html +++ b/pages/summarize/mzta-summarize.html @@ -27,6 +27,8 @@ + +
    @@ -47,8 +49,14 @@
    - + + + __MSG_prefs_OptionText_Summarize_main_prompt__ + + +
    +
    @@ -65,6 +73,12 @@
    + + __MSG_prefs_OptionText_Summarize_email_template__ + + +
    +
    @@ -81,6 +95,12 @@
    + + __MSG_prefs_OptionText_Summarize_email_separator__ + + +
    +
    From 51c81418a38e007b9d5ba181a87332bb25217c45 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Sat, 10 Jan 2026 23:00:20 +0100 Subject: [PATCH 026/123] handle disabling summarize options button --- options/mzta-options-default.js | 2 +- options/mzta-options.html | 2 +- options/mzta-options.js | 41 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index e14b2808..6fd52d1d 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -const special_prompts_with_integration = ['add_tags', 'spamfilter']; +const special_prompts_with_integration = ['add_tags', 'spamfilter', 'summarize']; export const integration_options_config = { chatgpt: { diff --git a/options/mzta-options.html b/options/mzta-options.html index 02b0f6ea..534f33b8 100644 --- a/options/mzta-options.html +++ b/options/mzta-options.html @@ -154,7 +154,7 @@ " diff --git a/options/mzta-options.js b/options/mzta-options.js index 3b2ac351..46a7439d 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -167,6 +167,27 @@ function disable_SpamFilter(prefs_opt){ } } +function disable_Summarize(prefs_opt){ + let summarize = document.getElementById('summarize'); + let conntype_select = document.getElementById("connection_type"); + const tempPrefs = { + connection_type: conntype_select.value, + ...prefs_opt + }; + let summarize_disabled = (getConnectionType(tempPrefs, null, 'summarize') === "chatgpt_web"); + let summarize_checked_original = summarize.checked; + summarize.checked = summarize_disabled ? false : summarize.checked; + if(!summarize.checked){ + let summarize_info_btn = document.getElementById('btnManageSummarizeInfo'); + summarize_info_btn.disabled = 'disabled'; + } + let summarize_warn_API_needed = document.getElementById('summarize_warn_API_needed'); + summarize_warn_API_needed.style.display = (summarize_disabled) ? 'inline-block' : 'none'; + if(summarize_checked_original != summarize.checked){ + browser.storage.sync.set({summarize: summarize.checked}); + } +} + async function disable_GetCalendarEvent(){ let get_calendar_event = document.getElementById('get_calendar_event'); let get_task = document.getElementById('get_task'); @@ -262,6 +283,24 @@ document.addEventListener('DOMContentLoaded', async () => { }); spamfilter_info_btn.disabled = spamfilter_el.checked ? '' : 'disabled'; + let summarize_el = document.getElementById('summarize'); + let summarize_info_btn = document.getElementById('btnManageSummarizeInfo'); + summarize_el.addEventListener('click', (event) => { + async function _summarize_el_change() { + if (event.target.checked) { + let granted = await messenger.permissions.request({ permissions: ["messagesRead"] }); + if (!granted) { + event.target.checked = false; + summarize_info_btn.disabled = 'disabled'; + browser.storage.sync.set({summarize: false}); + } + } + } + _summarize_el_change(); + summarize_info_btn.disabled = event.target.checked ? '' : 'disabled'; + }); + summarize_info_btn.disabled = summarize_el.checked ? '' : 'disabled'; + let get_calendar_event_el = document.getElementById('get_calendar_event'); let get_calendar_event_info_btn = document.getElementById('btnManageCalendarEventInfo'); get_calendar_event_el.addEventListener('click', (event) => { @@ -321,12 +360,14 @@ document.addEventListener('DOMContentLoaded', async () => { conntype_select.addEventListener("change", disable_MaxPromptLength); conntype_select.addEventListener("change", () => disable_AddTags(prefs_opt)); conntype_select.addEventListener("change", () => disable_SpamFilter(prefs_opt)); + conntype_select.addEventListener("change", () => disable_Summarize(prefs_opt)); conntype_select.addEventListener("change", disable_GetCalendarEvent); showConnectionOptions(conntype_select); disable_MaxPromptLength(); disable_AddTags(prefs_opt); disable_SpamFilter(prefs_opt); + disable_Summarize(prefs_opt); disable_GetCalendarEvent(); document.getElementById('reset_max_prompt_length').addEventListener('click', resetMaxPromptLength); From bd1ea03f789fa3ca5653877f8d600d636abe3e31 Mon Sep 17 00:00:00 2001 From: Christos Kanotidis Date: Wed, 14 Jan 2026 19:24:24 +0100 Subject: [PATCH 027/123] Translated using Weblate (Greek) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/el/ --- _locales/el/messages.json | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/_locales/el/messages.json b/_locales/el/messages.json index 16a60884..eb6e3538 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -942,7 +942,7 @@ "message": "ΑΠΑΙΤΕΙΤΑΙ. Μην αλλάξετε αυτήν την τιμή εκτός αν γνωρίζετε τι κάνετε. Περισσότερες πληροφορίες στη διεύθυνση:" }, "prefs_OptionText_anthropic_max_tokens": { - "message": "Claude Μέγιστα Tokens" + "message": "Μέγιστα Tokens" }, "prefs_OptionText_anthropic_max_tokens_Info": { "message": "Ο μέγιστος αριθμός διακριτικών που θα δημιουργηθούν κατά την ολοκλήρωση. Ο αριθμός διακριτικών της προτροπής σας συν το max_tokens δεν μπορεί να υπερβαίνει το μήκος περιβάλλοντος του μοντέλου." @@ -1280,5 +1280,29 @@ }, "reset": { "message": "Επαναφορά" + }, + "prompt_string": { + "message": "Εντολή" + }, + "placeholder_mail_headers": { + "message": "Κεφαλίδες αλληλογραφίας" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "Ποια θερμοκρασία δειγματοληψίας να χρησιμοποιηθεί, μεταξύ 0 και 2. Υψηλότερες τιμές όπως 0,8 θα κάνουν την έξοδο πιο τυχαία, ενώ χαμηλότερες τιμές όπως 0,2 θα την κάνουν πιο εστιασμένη και ντετερμινιστική." + }, + "prefs_ollama_temperature_Info": { + "message": "Η θερμοκρασία του μοντέλου. Η αύξηση της θερμοκρασίας θα κάνει το μοντέλο να απαντά πιο δημιουργικά. Η προεπιλεγμένη τιμή είναι 0,8. Συνιστάται η χρήση τιμών μεταξύ 0 και 1." + }, + "prefs_api_temperature": { + "message": "Θερμοκρασία" + }, + "prefs_openai_comp_temperature_Info": { + "message": "Ποια θερμοκρασία δειγματοληψίας να χρησιμοποιηθεί, μεταξύ 0 και 2. Υψηλότερες τιμές όπως 0,8 θα κάνουν την έξοδο πιο τυχαία, ενώ χαμηλότερες τιμές όπως 0,2 θα την κάνουν πιο εστιασμένη και ντετερμινιστική." + }, + "prefs_google_gemini_temperature_Info": { + "message": "Αυτή η παράμετρος πρέπει να είναι ένας αριθμός μεταξύ 0,0 και 2,0. Ελέγχει την τυχαιότητα της εξόδου. Η προεπιλεγμένη τιμή ποικίλλει ανάλογα με το μοντέλο. Αφήστε την κενή για να αποφύγετε τον ορισμό της παραμέτρου στην κλήση API." + }, + "prefs_anthropic_temperature_Info": { + "message": "Ποσότητα τυχαιότητας που εισάγεται στην απόκριση. Προεπιλογή 1,0. Εύρος από 0,0 έως 1,0. Χρησιμοποιήστε θερμοκρασία πιο κοντά στο 0,0 για αναλυτική ανάλυση." } } From 8679e1cb085b5b3882c1ec7f0b72985ff94a3e84 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 12:55:56 +0100 Subject: [PATCH 028/123] remove checking for non-optional permission --- options/mzta-options.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/options/mzta-options.js b/options/mzta-options.js index 46a7439d..7563cd51 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -286,17 +286,6 @@ document.addEventListener('DOMContentLoaded', async () => { let summarize_el = document.getElementById('summarize'); let summarize_info_btn = document.getElementById('btnManageSummarizeInfo'); summarize_el.addEventListener('click', (event) => { - async function _summarize_el_change() { - if (event.target.checked) { - let granted = await messenger.permissions.request({ permissions: ["messagesRead"] }); - if (!granted) { - event.target.checked = false; - summarize_info_btn.disabled = 'disabled'; - browser.storage.sync.set({summarize: false}); - } - } - } - _summarize_el_change(); summarize_info_btn.disabled = event.target.checked ? '' : 'disabled'; }); summarize_info_btn.disabled = summarize_el.checked ? '' : 'disabled'; From 90dcf8437b4d54a18cb0547e47ef82b4542139a3 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 12:56:35 +0100 Subject: [PATCH 029/123] remove stray console logging --- mzta-background.js | 1 - 1 file changed, 1 deletion(-) diff --git a/mzta-background.js b/mzta-background.js index c06d5c0b..da862ccb 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -995,7 +995,6 @@ function addContextMenuItems() { // Add Context menu: Summarize if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { - console.log("adding summarize to context menu") addContextMenu(contextMenuID_Summarize); } } From f147a0453b8e3781b3fb7b1d77322d74a07edb77 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 12:57:06 +0100 Subject: [PATCH 030/123] remove summarize_context_menu option in favor of summarize option --- mzta-background.js | 5 ++--- options/mzta-options-default.js | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index da862ccb..d433581a 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -811,7 +811,6 @@ async function reload_pref_init(){ dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, add_tags_context_menu: prefs_default.add_tags_context_menu, spamfilter_context_menu: prefs_default.spamfilter_context_menu, - summarize_context_menu: prefs_default.summarize_context_menu, ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); _process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter; @@ -925,7 +924,7 @@ function setupStorageChangeListener() { } if (changes.summarize) { if (changes.summarize.newValue){ - if (prefs_init.summarize_context_menu){ + if (prefs_init.summarize){ addContextMenu(contextMenuID_Summarize); } } else { @@ -994,7 +993,7 @@ function addContextMenuItems() { } // Add Context menu: Summarize - if(prefs_init.summarize && prefs_init.summarize_context_menu && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { + if(prefs_init.summarize && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { addContextMenu(contextMenuID_Summarize); } } diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 6fd52d1d..d5ccf9b2 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -134,6 +134,5 @@ export const prefs_default = { spamfilter_context_menu: true, spamfilter_enabled_accounts: [], summarize: false, - summarize_context_menu: true, ...generated_prefs } From cb6c93625b1bbda21b0766c6a25e7073a5285723 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 13:39:22 +0100 Subject: [PATCH 031/123] correct prompt naming --- _locales/en/messages.json | 8 ++++++++ mzta-background.js | 6 +++--- pages/summarize/mzta-summarize.js | 12 ++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 2d7329ec..b52a5539 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1016,10 +1016,18 @@ "description": "" }, "prompt_summarize_email_template": { + "message": "Summarize email template", + "description": "" + }, + "prompt_summarize_email_template_full_text": { "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\nBody:\n{%mail_text_body%}", "description": "" }, "prompt_summarize_email_separator": { + "message": "Email separator", + "description": "" + }, + "prompt_summarize_email_separator_full_text": { "message": "\n\n---------- NEXT EMAIL ----------\n\n", "description": "" }, diff --git a/mzta-background.js b/mzta-background.js index d433581a..e7d2e3ac 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1029,9 +1029,9 @@ async function summarizeEmails(messages) { // we have three prompts, the actual assignment for the LLM, the email // template prompt, and the email separator prompt const specialPrompts = await getSpecialPrompts(); - const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); - const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); - const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator'); + const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_full_text'); + const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template_full_text'); + const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator_full_text'); const tabs = await browser.tabs.query({ active: true, currentWindow: true }); const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index ea8d8364..8df7d8b7 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -93,19 +93,19 @@ document.addEventListener("DOMContentLoaded", async () => { }); summarize_textarea_email_template.addEventListener("input", (event) => { - summarize_reset_email_template_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_template')); + summarize_reset_email_template_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_template_full_text')); summarize_save_email_template_btn.disabled = (event.target.value === summarize_email_template.text); }); summarize_email_separator_textarea.addEventListener("input", (event) => { - summarize_email_separator_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_separator')); + summarize_email_separator_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_summarize_email_separator_full_text')); summarize_email_separator_save_btn.disabled = (event.target.value === summarize_email_separator.text); }); // on clicking buttons, reset summarize_reset_email_template_btn.addEventListener("click", () => { - summarize_textarea_email_template.value = browser.i18n.getMessage("prompt_summarize_email_template"); + summarize_textarea_email_template.value = browser.i18n.getMessage("prompt_summarize_email_template_full_text"); summarize_reset_email_template_btn.disabled = true; let event = new Event("input", { bubbles: true, cancelable: true }); summarize_textarea_email_template.dispatchEvent(event); @@ -119,7 +119,7 @@ document.addEventListener("DOMContentLoaded", async () => { }); summarize_email_separator_reset_btn.addEventListener("click", () => { - summarize_email_separator_textarea.value = browser.i18n.getMessage("prompt_summarize_email_separator"); + summarize_email_separator_textarea.value = browser.i18n.getMessage("prompt_summarize_email_separator_full_text"); summarize_email_separator_reset_btn.disabled = true; let event = new Event("input", { bubbles: true, cancelable: true }); summarize_email_separator_textarea.dispatchEvent(event); @@ -151,10 +151,10 @@ document.addEventListener("DOMContentLoaded", async () => { if(summarize_prompt.text === 'prompt_summarize_full_text'){ summarize_prompt.text = browser.i18n.getMessage(summarize_prompt.text); } - if(summarize_email_template.text === 'prompt_summarize_email_template'){ + if(summarize_email_template.text === 'prompt_summarize_email_template_full_text'){ summarize_email_template.text = browser.i18n.getMessage(summarize_email_template.text); } - if(summarize_email_separator.text === 'prompt_summarize_email_separator'){ + if(summarize_email_separator.text === 'prompt_summarize_email_separator_full_text'){ summarize_email_separator.text = browser.i18n.getMessage(summarize_email_separator.text); } From 7202b5a3e29e11839722a6fd6a4bff8065d0b30a Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 14:21:35 +0100 Subject: [PATCH 032/123] fix prompt names --- mzta-background.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index e7d2e3ac..d433581a 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1029,9 +1029,9 @@ async function summarizeEmails(messages) { // we have three prompts, the actual assignment for the LLM, the email // template prompt, and the email separator prompt const specialPrompts = await getSpecialPrompts(); - const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_full_text'); - const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template_full_text'); - const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator_full_text'); + const prompt = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize'); + const prompt_email = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_template'); + const prompt_email_separator = specialPrompts.find((prompt) => prompt.id === 'prompt_summarize_email_separator'); const tabs = await browser.tabs.query({ active: true, currentWindow: true }); const chatgpt_lang = await taPromptUtils.getDefaultLang(prompt); From b247dad80f1b103de31ff5c0b39dd1099fed3c06 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 14:22:07 +0100 Subject: [PATCH 033/123] adapt code copied from add_tags --- pages/summarize/mzta-summarize.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/pages/summarize/mzta-summarize.js b/pages/summarize/mzta-summarize.js index 8df7d8b7..71634058 100644 --- a/pages/summarize/mzta-summarize.js +++ b/pages/summarize/mzta-summarize.js @@ -198,9 +198,6 @@ function saveOptions(e) { options[element.id] = element.value; break; case 'textarea': - if(element.id === 'add_tags_auto_uselist_list') { - element.value = normalizeStringList(element.value, 1); - } options[element.id] = normalizeStringList(element.value); break; default: @@ -229,9 +226,6 @@ async function restoreOptions() { case 'password': let default_text_value = ''; if(element.id == 'default_chatgpt_lang') default_text_value = prefs_default.default_chatgpt_lang; - if(element.id === 'add_tags_auto_uselist_list') { - result[element.id] = normalizeStringList(result[element.id], 1); - } element.value = result[element.id] || default_text_value; break; default: @@ -260,21 +254,21 @@ async function restoreOptions() { let getting = await browser.storage.sync.get(prefs_default); let specialPrompts = await getSpecialPrompts(); - let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); + let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_summarize'); if (addtags_prompt) { if (addtags_prompt.api_type && addtags_prompt.api_type !== '') { - getting['add_tags_connection_type'] = addtags_prompt.api_type; + getting['summarize_connection_type'] = addtags_prompt.api_type; } else { - getting['add_tags_connection_type'] = getting['connection_type']; + getting['summarize_connection_type'] = getting['connection_type']; } for (const [integration, options] of Object.entries(integration_options_config)) { for (const key of Object.keys(options)) { const propName = `${integration}_${key}`; if (addtags_prompt[propName] !== undefined && addtags_prompt[propName] !== '') { - getting[`add_tags_${propName}`] = addtags_prompt[propName]; + getting[`summarize_${propName}`] = addtags_prompt[propName]; } else { - getting[`add_tags_${propName}`] = getting[propName]; + getting[`summarize_${propName}`] = getting[propName]; } } } From f6fcaac0bb9947ad1117b3ebe07dbfd4b31e28f0 Mon Sep 17 00:00:00 2001 From: Guido Kraemer Date: Fri, 16 Jan 2026 15:09:47 +0100 Subject: [PATCH 034/123] update prompts --- _locales/en/messages.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index b52a5539..3ce55cc4 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1012,7 +1012,7 @@ "description": "" }, "prompt_summarize_full_text": { - "message": "Summarize the following email or emails into a bullet point list. If there are multiple emails, consider the entire thread for the summary.", + "message": "You are an assistant that summarizes email conversations.\n\nGiven an email thread, produce a concise, accurate summary that captures:\n\n- The main topic or purpose of the conversation\n- Key decisions, conclusions, or agreements\n- Important questions, requests, or action items\n- Who is responsible for each action item (if stated)\n\nOmit greetings, signatures, quoted text, and redundant back-and-forth.\nDo not add assumptions or information not present in the emails.\n\nWrite the summary in clear, neutral language suitable for a busy professional.", "description": "" }, "prompt_summarize_email_template": { @@ -1020,7 +1020,7 @@ "description": "" }, "prompt_summarize_email_template_full_text": { - "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\nBody:\n{%mail_text_body%}", + "message": "From: {%author%}\nTo: {%recipients%}\nCC: {%cc_list%}\nSubject: {%mail_subject%}\nDate: {%mail_datetime%}\nAttachments:\n{%mail_attachments_info%}\n\nBody:\n{%mail_text_body%}", "description": "" }, "prompt_summarize_email_separator": { From 1d83c3a8c094f68c9da44447e1436fb29dd3a493 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 16 Jan 2026 22:29:34 +0100 Subject: [PATCH 035/123] correctly handling empty body with no placeholders. see #614 --- js/mzta-utils-prompt.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/mzta-utils-prompt.js b/js/mzta-utils-prompt.js index d1c638b7..c19499f8 100644 --- a/js/mzta-utils-prompt.js +++ b/js/mzta-utils-prompt.js @@ -50,7 +50,9 @@ export const taPromptUtils = { if(!placeholdersUtils.hasPlaceholder(curr_prompt.text)){ // no placeholders, do as usual - fullPrompt = curr_prompt.text + (String(curr_prompt.need_signature) == "1" ? " " + await taPromptUtils.getDefaultSignature():"") + " " + chatgpt_lang + " \"" + (selection_text=='' ? body_text : selection_text) + "\" "; + const signature = String(curr_prompt.need_signature) === "1" ? await taPromptUtils.getDefaultSignature() : ""; + const content = selection_text || body_text; + fullPrompt = [curr_prompt.text, signature, chatgpt_lang, content ? `"${content}"` : ""].filter(Boolean).join(" "); }else{ // we have at least a placeholder, do the magic! // check if we have custom placeholders From 272dc59f009ac7a8caa2208b79db92d2621b0e0a Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 16 Jan 2026 22:34:47 +0100 Subject: [PATCH 036/123] Version set to 3.8.0. Release notes updated. --- CHANGELOG.md | 3 +-- manifest.json | 2 +- options/mzta-release-notes.html | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 567c9294..93653ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ -

    Version 3.8.0 - ??/??/2026

    +

    Version 3.8.0 - 16/01/2026

    • [All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
    • [All APIs] When using special prompts (like automatically adding tags or the spam filter) with a specific API integration, all the settings for that integration can be specific. In this way you can use different api keys for the same integration, or different system prompt or temperature [#590].
    • @@ -16,7 +16,6 @@
    • Spanish (es) translation added, thanks to Gerardo Sobarzo, Andrés Rendón Hernández, Erick Limon.
    • Swedish (sv) translation added, thanks to Andreas Pettersson.
    • Various fixes.
    • -
    • ...

    Version 3.7.9 - 06/01/2026

      diff --git a/manifest.json b/manifest.json index 5128f779..92a30fb3 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.0pre4", + "version": "3.8.0", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 77dbbf75..e0c428de 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,7 +7,7 @@

      ThunderAI Release Notes

      -

      Version 3.8.0 - ??/??/2026

      +

      Version 3.8.0 - 16/01/2026

      • [All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
      • [All APIs] When using special prompts (like automatically adding tags or the spam filter) with a specific API integration, all the settings for that integration can be specific. In this way you can use different api keys for the same integration, or different system prompt or temperature [#590].
      • @@ -19,7 +19,6 @@
      • Spanish (es) translation added, thanks to Gerardo Sobarzo, Andrés Rendón Hernández, Erick Limon.
      • Swedish (sv) translation added, thanks to Andreas Pettersson.
      • Various fixes.
      • -
      • ...

      Version 3.7.9 - 06/01/2026

        From cc7b8d164096bc3d3c5b4a89c712747a1494d769 Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 20 Jan 2026 13:37:20 +0100 Subject: [PATCH 037/123] added a commented out console.log debug line --- api_webchat/controller.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 6dec60df..8b722a25 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -213,6 +213,8 @@ if (worker) { version_string: prefs_api[`${integration_prefix}_version`], additional_messages: additional_text_elements }), "info"); + + //console.log(`>>>>>>>>>>>>> command: ${llm}_ready_${call_id}`,) browser.runtime.sendMessage({ command: `${llm}_ready_${call_id}`, From 04d12594a7770d8cf86b31fb80b7cb5d95804090 Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 20 Jan 2026 13:37:35 +0100 Subject: [PATCH 038/123] openai api fixed. see #620 --- mzta-background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mzta-background.js b/mzta-background.js index e2161b66..4ab3abc4 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -526,7 +526,7 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ browser.runtime.onMessage.removeListener(listener2); } - if (message.command === "openai_api_ready_"+rand_call_id2) { + if (message.command === "chatgpt_api_ready_"+rand_call_id2) { return handleChatGptApi(sender.tab); } return false; From 5e57ee19d09f723c7d47c39e3a7900919b294ed6 Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 20 Jan 2026 13:39:24 +0100 Subject: [PATCH 039/123] version set to 3.8.1. release notes updated --- CHANGELOG.md | 4 ++++ manifest.json | 2 +- options/mzta-release-notes.html | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93653ac0..82dc38e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

        Version 3.8.1 - 20/01/2026

        +
          +
        • [OpenAI API] Fix: Correctly sending the prompt after opening the chat window [#620].
        • +

        Version 3.8.0 - 16/01/2026

        • [All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
        • diff --git a/manifest.json b/manifest.json index 92a30fb3..6431ad9b 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.0", + "version": "3.8.1", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index e0c428de..5ee6db4d 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

          ThunderAI Release Notes

          +

          Version 3.8.1 - 20/01/2026

          +
            +
          • [OpenAI API] Fix: Correctly sending the prompt after opening the chat window [#620].
          • +

          Version 3.8.0 - 16/01/2026

          • [All APIs] Now it is possible to define an API and its settings for any custom prompt. This allows anyone to use different AI providers for different prompts [#102].
          • From 3180898dcea85d852adf5bf1b679a06d7c8fa828 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 20 Jan 2026 23:37:12 +0100 Subject: [PATCH 040/123] var name fixed. see #621 --- options/mzta-options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/mzta-options.js b/options/mzta-options.js index 16b130fd..8f48ca3d 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -329,7 +329,7 @@ document.addEventListener('DOMContentLoaded', async () => { browser.runtime.getPlatformInfo().then(info => { taLog.log("OS: " + info.os); - if ((info.os === "linux")&&(prefs.chatgpt_win_height!=0)&&(prefs.chatgpt_win_width!=0)){ + if ((info.os === "linux")&&(prefs_opt.chatgpt_win_height!=0)&&(prefs_opt.chatgpt_win_width!=0)){ document.getElementById('hyprland_warning').style.display = 'table-row'; } }); From 0041a8a6a45a7d2f1102b493c9a8b361809b7dfb Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 20 Jan 2026 23:43:46 +0100 Subject: [PATCH 041/123] correctly saving the enabled status with a direct edit on the page. see #621 --- pages/customprompts/mzta-custom-prompts.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 2a70510e..3af36e7b 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -806,6 +806,18 @@ function handleConfirmClick(e) { async function handleCheckboxChange(e) { e.preventDefault(); e.target.setAttribute('checked_val', e.target.checked ? '1' : '0'); + + if (e.target.classList.contains('enabled')) { + let tr = e.target.closest('tr'); + if (tr) { + let idnum = tr.getAttribute('data-idnum'); + let item = promptsList.get('idnum', idnum); + if (item && item.length > 0) { + item[0]._values.enabled = e.target.checked ? 1 : 0; + } + } + } + //console.log('>>>>>>>> checked_val: ' + e.target.getAttribute('checked_val')); if (e.target.classList.contains('need_selected') || e.target.classList.contains('need_custom_text') || e.target.classList.contains('need_selected_new') || e.target.classList.contains('need_custom_text_new')) { let textarea = e.target.closest('tr').querySelector('.text_output'); From a888370fd285d873171ac5764a277e876ee7e69c Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 20 Jan 2026 23:48:07 +0100 Subject: [PATCH 042/123] correctly saving the need_custom_text status with a direct edit on the page. see #621 --- pages/customprompts/mzta-custom-prompts.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 3af36e7b..a85a5053 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -807,13 +807,18 @@ async function handleCheckboxChange(e) { e.preventDefault(); e.target.setAttribute('checked_val', e.target.checked ? '1' : '0'); - if (e.target.classList.contains('enabled')) { + if (e.target.classList.contains('enabled') || e.target.classList.contains('need_custom_text')) { let tr = e.target.closest('tr'); if (tr) { let idnum = tr.getAttribute('data-idnum'); let item = promptsList.get('idnum', idnum); if (item && item.length > 0) { - item[0]._values.enabled = e.target.checked ? 1 : 0; + if (e.target.classList.contains('enabled')) { + item[0]._values.enabled = e.target.checked ? 1 : 0; + } + if (e.target.classList.contains('need_custom_text')) { + item[0]._values.need_custom_text = e.target.checked ? 1 : 0; + } } } } From a228a316b9a56ef8c3e771feab635a8894a48bc2 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 20 Jan 2026 23:49:19 +0100 Subject: [PATCH 043/123] version set to 3.8.2. release notes updated --- CHANGELOG.md | 4 ++++ manifest.json | 2 +- options/mzta-release-notes.html | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82dc38e8..923cba9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

            Version 3.8.2 - 20/01/2026

            +
              +
            • Fix: Correctly saving the enable status in custom prompts [#621].
            • +

            Version 3.8.1 - 20/01/2026

            • [OpenAI API] Fix: Correctly sending the prompt after opening the chat window [#620].
            • diff --git a/manifest.json b/manifest.json index 6431ad9b..b3dacaa4 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.1", + "version": "3.8.2", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 5ee6db4d..8bf0cfa4 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

              ThunderAI Release Notes

              +

              Version 3.8.2 - 20/01/2026

              +
                +
              • Fix: Correctly saving the enable status in custom prompts [#621].
              • +

              Version 3.8.1 - 20/01/2026

              • [OpenAI API] Fix: Correctly sending the prompt after opening the chat window [#620].
              • From 39a5c3367cd56bb9bbe743a41e7c1a4992713e60 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 20 Jan 2026 23:50:51 +0100 Subject: [PATCH 044/123] typo fixed --- CHANGELOG.md | 2 +- options/mzta-release-notes.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 923cba9a..0b6ce47f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@

                Version 3.8.2 - 20/01/2026

                  -
                • Fix: Correctly saving the enable status in custom prompts [#621].
                • +
                • Fix: Correctly saving the enabled status in custom prompts [#621].

                Version 3.8.1 - 20/01/2026

                  diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 8bf0cfa4..16f4dd6c 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -9,7 +9,7 @@

                  ThunderAI Release Notes

                  Version 3.8.2 - 20/01/2026

                    -
                  • Fix: Correctly saving the enable status in custom prompts [#621].
                  • +
                  • Fix: Correctly saving the enabled status in custom prompts [#621].

                  Version 3.8.1 - 20/01/2026

                    From 22296d37ac37ae781d1d895a7df55a8fa45d5880 Mon Sep 17 00:00:00 2001 From: "taichi ito (watya)" Date: Thu, 22 Jan 2026 01:44:42 +0100 Subject: [PATCH 045/123] Added translation using Weblate (Japanese) --- _locales/ja/messages.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 _locales/ja/messages.json diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/_locales/ja/messages.json @@ -0,0 +1 @@ +{} From 09b38776f22edf9ef3e9b879e44e791b4eb46e2f Mon Sep 17 00:00:00 2001 From: "taichi ito (watya)" Date: Thu, 22 Jan 2026 01:47:30 +0100 Subject: [PATCH 046/123] Translated using Weblate (Japanese) Currently translated at 0.0% (0 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/ja/ --- _locales/ja/messages.json | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 0967ef42..8e891f7e 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -1 +1,11 @@ -{} +{ + "extensionDescription": { + "message": "ChatGPT、Google Gemini、Claude、Ollama を使ってメールを強化しましょう!" + }, + "menu_title": { + "message": "AI" + }, + "prompt_lang": { + "message": "返信する" + } +} From 6afa053917336d4140a7c809b435e06d123bcdd0 Mon Sep 17 00:00:00 2001 From: "taichi ito (watya)" Date: Thu, 22 Jan 2026 02:43:31 +0100 Subject: [PATCH 047/123] Translated using Weblate (Japanese) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/ja/ --- _locales/ja/messages.json | 1297 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1297 insertions(+) diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 8e891f7e..4f1afbe0 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -7,5 +7,1302 @@ }, "prompt_lang": { "message": "返信する" + }, + "prompt_reply": { + "message": "このメールに返信" + }, + "prompt_reply_advanced": { + "message": "このスレッドに返信" + }, + "prompt_reply_custom_command": { + "message": "コマンドで返信" + }, + "prompt_rewrite_polite": { + "message": "丁寧に書き直す" + }, + "prompt_rewrite_formal": { + "message": "フォーマルに書き直す" + }, + "prompt_classify": { + "message": "分類する" + }, + "prompt_summarize_this": { + "message": "要約する" + }, + "prompt_translate_this": { + "message": "翻訳する" + }, + "prompt_this": { + "message": "プロンプトを実行" + }, + "prompt_selection_needed": { + "message": "続行するには、テキストを選択してください!" + }, + "customPrompts_managePrompts": { + "message": "プロンプトを管理" + }, + "more_info_string": { + "message": "詳細情報" + }, + "prompt_string": { + "message": "プロンプト" + }, + "customPrompts_managePrompts_info_default": { + "message": "デフォルトのプロンプトは編集できません。無効にしてから、プロンプトのテキストをコピーし、新しいプロンプトに貼り付けて変更版を作成できます。" + }, + "customPrompts_managePrompts_info_default_2": { + "message": "プロンプトのインポートとエクスポートができます。同じIDの既存プロンプトは上書きされます。新しいIDのプロンプトは追加されます。" + }, + "customPrompts_managePrompts_info_default_3": { + "message": "すべて正しければ、インポート後に「すべて保存」ボタンをクリックしてください。" + }, + "customPrompts_start_saving": { + "message": "プロンプトを保存中..." + }, + "customPrompts_reindexing_list": { + "message": "リストを再インデックス中..." + }, + "customPrompts_filtering_prompts": { + "message": "プロンプトをフィルタリング中..." + }, + "customPrompts_saving_default_prompts": { + "message": "デフォルトプロンプトを保存中..." + }, + "customPrompts_saving_custom_prompts": { + "message": "カスタムプロンプトを保存中..." + }, + "customPrompts_reloading_menus": { + "message": "メニューを再読み込み中..." + }, + "customPrompts_saved": { + "message": "プロンプトを保存しました!" + }, + "customPrompts_form_label_ID": { + "message": "ID" + }, + "customPrompts_form_label_ID_rules": { + "message": "一意で、小文字、スペースなしである必要があります" + }, + "customPrompts_form_label_Name": { + "message": "名前" + }, + "customPrompts_form_label_Text": { + "message": "プロンプトテキスト" + }, + "customPrompts_form_label_Action": { + "message": "アクション" + }, + "customPrompts_form_label_need_selected": { + "message": "テキスト選択が必要" + }, + "customPrompts_form_label_need_signature": { + "message": "常に署名を追加する" + }, + "customPrompts_form_label_need_custom_text": { + "message": "追加テキストを要求する" + }, + "customPrompts_form_label_enabled": { + "message": "有効" + }, + "customPrompts_form_label_use_diff_viewer": { + "message": "テキスト比較ビューアを有効にする" + }, + "customPrompts_form_label_use_diff_viewer_title": { + "message": "テキスト比較ビューアは、アクションが「テキストを置換」に設定されている場合に選択できます。" + }, + "customPrompts_form_required_fields": { + "message": "必須フィールド" + }, + "customPrompts_btnEdit": { + "message": "編集" + }, + "customPrompts_btnCancel": { + "message": "キャンセル" + }, + "customPrompts_btnOK": { + "message": "OK" + }, + "customPrompts_btnDelete": { + "message": "削除" + }, + "customPrompts_btnDelete_confirmText": { + "message": "このアイテムを削除してもよろしいですか?" + }, + "customPrompts_unsaved_changes": { + "message": "保存されていない変更があります!" + }, + "btnSaveAll_string": { + "message": "すべて保存" + }, + "btnNew_string": { + "message": "新規追加" + }, + "customPrompts_btnAddNewCommit": { + "message": "プロンプトを追加" + }, + "customPrompts_add_to_menu": { + "message": "メニューに追加" + }, + "customPrompts_add_to_menu_always": { + "message": "常に" + }, + "customPrompts_add_to_menu_reading": { + "message": "メール閲覧時" + }, + "customPrompts_add_to_menu_composing": { + "message": "メール作成時" + }, + "customPrompts_close_button": { + "message": "閉じるボタン" + }, + "customPrompts_do_reply": { + "message": "返信する" + }, + "customPrompts_substitute_text": { + "message": "テキストを置換" + }, + "chatgpt_win_working": { + "message": "処理中..." + }, + "chatgpt_win_job_completed": { + "message": "完了!" + }, + "chatgpt_win_job_completed_select": { + "message": "使用するテキストを選択してボタンをクリックしてください。" + }, + "chatgpt_win_get_answer": { + "message": "選択した回答を使用" + }, + "chatgpt_win_close": { + "message": "閉じる" + }, + "chatgpt_textarea_not_found_error": { + "message": "ChatGPTページの読み込みに時間がかかっているようです。読み込みが完了したら、右のボタンをクリックしてください。問題が続く場合は、サービスの状態を確認してください。" + }, + "chatgpt_btn_retry": { + "message": "再試行" + }, + "chatgpt_sendbutton_not_found_error": { + "message": "送信ボタンをクリックしてプロンプトを送信してください。" + }, + "chatgpt_user_not_logged_in": { + "message": "ChatGPTにログインしていません。認証情報でログインし、ChatGPTウィンドウを閉じてから、再度操作を行ってください。その後はログイン状態が維持されます。" + }, + "chatgpt_win_model_warning": { + "message": "何らかの理由で、正しいモデルが読み込まれているか確認できません。今のところ、青いボタンを押して続行できます。" + }, + "chatgpt_win_custom_text": { + "message": "プロンプト用の追加テキストをここに入力してください。" + }, + "chatgpt_win_send": { + "message": "送信" + }, + "chatgpt_force_completion": { + "message": "強制完了" + }, + "chatgpt_force_completion_title": { + "message": "ChatGPTが処理を完了したのにボタンが表示されない場合は、ここをクリックして「最後の回答を使用」ボタンを表示してください。" + }, + "msg_prompt_too_long": { + "message": "入力したテキストが長すぎます。短くしてください。" + }, + "prefs_OptionText_release_notes": { + "message": "リリースノート" + }, + "prefs_status_page": { + "message": "サービス状態" + }, + "prefs_OptionText_chatgpt_win_text": { + "message": "AIチャットウィンドウのサイズ" + }, + "prefs_OptionText_chatgpt_win_height": { + "message": "高さ" + }, + "prefs_OptionText_chatgpt_win_width": { + "message": "幅" + }, + "prefs_OptionText_default_sign_name": { + "message": "デフォルトの署名名" + }, + "prefs_OptionText_default_chatgpt_lang": { + "message": "返信のデフォルト言語" + }, + "prefs_OptionText_reply_all": { + "message": "全員に返信" + }, + "prefs_OptionText_reply_sender": { + "message": "送信者に返信" + }, + "prefs_OptionText_reply_type": { + "message": "返信タイプ" + }, + "prefs_OptionText_reply_type_Info": { + "message": "これはメールに返信する際に使用されるデフォルトの返信タイプです。返信ダイアログで後から変更できます。" + }, + "prefs_OptionText_btnManagePrompts": { + "message": "プロンプトを管理する" + }, + "prefs_OptionText_btnManageCustomDataPH": { + "message": "データプレースホルダーを管理する" + }, + "prefsInfoTitle": { + "message": "重要な情報" + }, + "prefsInfoDesc_1": { + "message": "ChatGPTのWebインターフェースが変更され、アドオンが動作しなくなる可能性があります。このページの下部にある「サービス状態」ページを確認してください。また、ThunderAIを初めて使用する際はChatGPTへのログインが必要です。" + }, + "prefsInfoDesc_2": { + "message": "ChatGPT APIを使用するには、OpenAI ChatGPT APIキーが必要で、モデルを選択する必要があります。" + }, + "prefsInfoDesc_3": { + "message": "Ollamaとの連携を使用するには、ローカルのOllamaサーバーを設定する必要があります。サーバーが起動したら、アプリケーション内の指定フィールドにアドレスを入力してください。ThunderAIとOllamaサーバー間の適切な通信を確保するため、OLLAMA_ORIGINS=moz-extension://*を設定してください。" + }, + "prefsInfoDesc_4": { + "message": "この連携を使用するには、LM StudioなどのOpenAI API互換のローカルサーバーを設定する必要があります。サーバーが起動したら、アプリケーション内の指定フィールドにアドレスを入力してください。ThunderAIとローカルサーバー間の適切な通信を確保するため、CORS設定を正しく行ってください。" + }, + "prefsInfoDesc_5": { + "message": "キーボードショートカットCTRL+ALT+AでThunderAIメニューを開けることを覚えておいてください。" + }, + "prefsInfoDesc_6": { + "message": "このページの右上にある歯車アイコンをクリックし、「拡張機能のショートカットを管理」を選択してショートカットを変更できます。" + }, + "prefsDonation_1": { + "message": "このアドオンは気に入りましたか?" + }, + "prefsDonation_2": { + "message": "寄付をご検討ください!" + }, + "backToOptionsText": { + "message": "オプション" + }, + "TranslateText": { + "message": "このアドオンの翻訳を手伝いませんか?" + }, + "TranslateLink": { + "message": "方法を確認!" + }, + "customPrompts_ExportAll": { + "message": "すべてのプロンプトをエクスポート" + }, + "customPrompts_Import": { + "message": "新しいプロンプトをインポート" + }, + "importPrompts_confirmText": { + "message": "新しいプロンプトをインポートしようとしています。" + }, + "customPrompts_start_import": { + "message": "カスタムプロンプトのインポートを開始中..." + }, + "customPrompts_import_completed": { + "message": "カスタムプロンプトのインポートが完了しました!「すべて保存」ボタンをクリックして変更を保存してください。" + }, + "importPrompts_invalidFile": { + "message": "インポートしようとしているファイルは有効なカスタムプロンプトファイルではありません。" + }, + "importPrompts_invalidPrompts": { + "message": "インポートしようとしているファイルには有効なプロンプトが含まれていません。" + }, + "currently_used_prompt": { + "message": "現在使用中のプロンプト名" + }, + "customprompts_form_label_define_response_lang": { + "message": "プロンプトで返信言語を定義する" + }, + "prefs_Connection_type": { + "message": "接続タイプ" + }, + "prefs_Connection_type_ChatGPT_Web": { + "message": "ChatGPT Webインターフェース" + }, + "prefs_Connection_type_ChatGPT_API": { + "message": "ChatGPT OpenAI API" + }, + "prefs_ChatGPT_API_Key": { + "message": "ChatGPT APIキー" + }, + "ChatGPT_Models": { + "message": "ChatGPTモデル" + }, + "ChatGPT_Models_Fetch": { + "message": "ChatGPTモデルリストを更新" + }, + "ChatGPT_Models_Error_fetching": { + "message": "ChatGPTモデルの取得中にエラー" + }, + "Loading": { + "message": "読み込み中..." + }, + "error": { + "message": "ThunderAI エラー!" + }, + "chatgpt_empty_apikey": { + "message": "ChatGPT APIのAPIキーが設定されていません。オプションページで設定してください。" + }, + "chatgpt_empty_model": { + "message": "ChatGPT APIのモデルが選択されていません。オプションページで選択してください。" + }, + "chagpt_api_send_button": { + "message": "使用モデル" + }, + "Debug": { + "message": "デバッグ" + }, + "prefs_OptionText_do_debug_info": { + "message": "デバッグシステムを有効にする" + }, + "prefs_Connection_type_Ollama_API": { + "message": "Ollama API(ローカルLLM)" + }, + "prefs_Connection_type_OpenAI_Comp_API": { + "message": "OpenAI互換API" + }, + "prefs_API_Host": { + "message": "ホストアドレス" + }, + "Ollama_Models": { + "message": "Ollamaモデル" + }, + "Ollama_Models_Fetch": { + "message": "Ollamaモデルリストを更新" + }, + "Ollama_Models_Error_fetching": { + "message": "Ollamaモデルの取得中にエラー" + }, + "API_Models_Error_NoModels": { + "message": "モデルが見つかりません" + }, + "ollama_empty_host": { + "message": "Ollama APIのホストアドレスが設定されていません。オプションページで設定してください。" + }, + "ollama_empty_model": { + "message": "Ollama APIのモデルが選択されていません。オプションページで選択してください。" + }, + "error_connection_interrupted": { + "message": "サーバーへの接続が予期せず中断されました" + }, + "ollama_api_request_failed": { + "message": "Ollama APIリクエストが失敗しました" + }, + "chatgpt_api_request_failed": { + "message": "OpenAI ChatGPT APIリクエストが失敗しました" + }, + "WaitingServerResponse": { + "message": "サーバーの応答を待っています" + }, + "prefs_API_Host_Info": { + "message": "例:" + }, + "OpenAIComp_Models": { + "message": "OpenAI互換APIモデル" + }, + "OpenAIComp_Models_Fetch": { + "message": "OpenAI互換APIモデルリストを更新" + }, + "OpenAIComp_Models_Error_fetching": { + "message": "OpenAI互換APIモデルの取得中にエラー" + }, + "OpenAIComp_empty_host": { + "message": "OpenAI互換APIのホストアドレスが設定されていません。オプションページで設定してください。" + }, + "OpenAIComp_empty_model": { + "message": "OpenAI互換APIのモデルが選択されていません。オプションページで選択してください。" + }, + "OpenAIComp_api_request_failed": { + "message": "OpenAI互換APIリクエストが失敗しました" + }, + "prefs_OpenAIComp_ChatName": { + "message": "チャット名" + }, + "prefs_OpenAIComp_ChatName_Info": { + "message": "AIチャットで使用される名前です。" + }, + "StorageSpace": { + "message": "使用中のストレージ容量" + }, + "SearchPrompt": { + "message": "プロンプトを検索" + }, + "prefs_OptionText_dynamic_menu_force_enter": { + "message": "メニュー:即時プロンプト送信" + }, + "prefs_OptionText_dynamic_menu_force_enter_info": { + "message": "チェックすると、キーボードショートカットCTRL+ALT+Aでメニューから選択したプロンプトが自動的に送信されます。チェックしない場合、プロンプト名が表示され、送信するにはEnterキーを再度押す必要があります。" + }, + "prefs_OptionText_dynamic_menu_order_alphabet": { + "message": "メニュー:アルファベット順に並べる" + }, + "prefs_OptionText_dynamic_menu_order_alphabet_info": { + "message": "チェックすると、メニュー内のプロンプトがアルファベット順に並べられます。" + }, + "prefs_OptionText_chatgpt_win_dims_info": { + "message": "ウィンドウサイズを指定しない場合は0を設定してください。" + }, + "prefs_OpenAIComp_API_Key": { + "message": "OpenAI互換APIキー" + }, + "Optional": { + "message": "オプション" + }, + "OpenChatGPTTab": { + "message": "ChatGPTタブを開く" + }, + "OpenChatGPTTab_Info": { + "message": "ThunderAIウィンドウでログインの問題が発生した場合は、右のボタンで新しいタブにChatGPTを開き、ログインしてからタブを閉じ、ThunderAIの使用を続けてください。" + }, + "OpenChatGPTTab_Info2": { + "message": "ここからChatGPT Webを開くと、モデル、プロジェクト、カスタムGPTの設定が適用されます。" + }, + "placeholder_mail_text_body": { + "message": "メール本文" + }, + "placeholder_mail_html_body": { + "message": "HTMLメール本文" + }, + "placeholder_mail_subject": { + "message": "メール件名" + }, + "placeholder_folder_name": { + "message": "フォルダー名" + }, + "placeholder_folder_path": { + "message": "フォルダーパス" + }, + "placeholder_mail_headers": { + "message": "メールヘッダー" + }, + "placeholder_selected_text": { + "message": "選択テキスト" + }, + "placeholder_selected_html": { + "message": "選択HTML" + }, + "placeholder_additional_text": { + "message": "追加テキスト" + }, + "placeholder_junk_score": { + "message": "迷惑メールスコア" + }, + "placeholder_recipients": { + "message": "宛先" + }, + "placeholder_cc_list": { + "message": "CCリスト" + }, + "placeholder_author": { + "message": "送信者" + }, + "placeholder_account_email_address": { + "message": "アカウントのメールアドレス" + }, + "prefs_OptionText_placeholders_use_default_value": { + "message": "プレースホルダー:デフォルト値を使用" + }, + "prefs_OptionText_placeholders_use_default_value_info": { + "message": "チェックすると、値が指定されていない場合にプレースホルダーにデフォルト値が入力されます。チェックしない場合、プレースホルダーはそのまま残ります。" + }, + "prefs_OptionText_max_prompt_length": { + "message": "最大プロンプト長" + }, + "prefs_OptionText_max_prompt_length_Info": { + "message": "プロンプトで使用できる最大文字数です。超過するとエラーメッセージが表示されます。ChatGPT Webインターフェースでは値を編集できません。チェックを無効にするには0を設定してください。" + }, + "prefs_OptionText_chatgpt_web_model": { + "message": "ChatGPT Webモデル" + }, + "prefs_OptionText_chatgpt_web_model_info": { + "message": "ChatGPT Webインターフェースで強制されるモデルです。指定されていないか不正な場合、Webページ上でChatGPTによりデフォルトモデルが設定されます。この設定はChatGPT無料アカウントでは機能しません。" + }, + "prefs_OptionText_chatgpt_web_tempchat": { + "message": "ChatGPT Web一時チャット" + }, + "prefs_OptionText_chatgpt_web_tempchat_info": { + "message": "チェックすると、ChatGPT Webインターフェースで一時チャットが使用されます。" + }, + "chatgpt_btn_model": { + "message": "現在のモデルを使用" + }, + "SendingPrompt": { + "message": "プロンプトを送信中..." + }, + "AllowedValues": { + "message": "許可される値" + }, + "prefs_OptionText_btnManagePrompts_infoline": { + "message": "追加のデータプレースホルダーを使用できます。" + }, + "prefs_OptionText_openai_comp_use_v1": { + "message": "「v1」互換性を維持する" + }, + "prefs_OptionText_openai_comp_use_v1_info": { + "message": "チェックすると、APIコールのパスに「v1」セグメントが維持されます(例:「http://localhost:1234/v1/chat/completions」)。" + }, + "prefs_OptionText_openai_comp_info_remote": { + "message": "ここにリモートサーバーのアドレスも入力できます。" + }, + "prefs_OptionText_owl_warning": { + "message": "アカウントの少なくとも1つがOwl for Exchangeアドオンを使用しているようです。ThunderbirdとOwlの間には既知の問題があり、現在対処中です。現時点では、メール作成時にはThunderAIを使用できますが、閲覧時には使用できません。" + }, + "prefs_OptionText_chatgpt_web_model_tooltip": { + "message": "クリックして値を設定してください。" + }, + "prompt_reply_full_text": { + "message": "以下のメールに返信してください。必要なテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_reply_additional_text": { + "message": "返信に件名を含めないでください。" + }, + "reply_same_lang": { + "message": "同じ言語で返信してください。" + }, + "sign_msg_as": { + "message": "署名名:" + }, + "prompt_reply_advanced_full_text": { + "message": "以下のメール「{%selected_text%}」に返信してください。これはメールスレッド全体「{%mail_html_body%}」を考慮しています。必要なテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_reply_custom_command_full_text": { + "message": "以下のメール「{%mail_text_body%}」に返信してください。{%additional_text%}。必要なテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_rewrite_full_text": { + "message": "以下のテキストをより丁寧に書き直してください。書き直したテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_rewrite_formal_full_text": { + "message": "以下のテキストをよりフォーマルに書き直してください。書き直したテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_classify_full_text": { + "message": "以下のテキストを丁寧さ、温かさ、フォーマルさ、自己主張、攻撃性の観点から分類し、各カテゴリのパーセンテージを示してください。カテゴリとスコアのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prompt_summarize_this_full_text": { + "message": "以下のメールを箇条書きリストに要約してください。" + }, + "prompt_translate_this_full_text": { + "message": "以下のメールを次の言語に翻訳してください:" + }, + "prompt_this_full_text": { + "message": "必要なテキストのみで、余分なコメントや他のテキストなしで返信してください。" + }, + "prefs_OptionText_add_tags": { + "message": "メールにタグを追加" + }, + "prefs_OptionText_add_tags_Info": { + "message": "チェックすると、メールにタグを適用するアイテムがメニューに追加されます。" + }, + "prompt_add_tags": { + "message": "このメールにタグを追加" + }, + "prompt_add_tags_full_text": { + "message": "以下のメールテキストを分析し、その内容を要約するタグのJSON配列を生成してください。テーマ、主要なトピック、関連する説明をタグとして使用してください。タグは簡潔でメールの内容に関連するものにしてください。\nメールテキスト:{%mail_text_body%}\nコンテキストのために以下の詳細を考慮してください:\n- 送信者:{%author%}\n- 宛先:{%recipients%}\n- CCリスト:{%cc_list%}\n- メール件名:{%mail_subject%}\nメールのテキストとコンテキストに基づいてタグを作成し、不要な情報や些細な詳細は無視してください。\nJSON形式のみで応答を生成してください。出力は追加のコメントやテキストなしのタグのJSON配列のみにしてください。使用するJSONフォーマットの例:\n{\n\"tags\": [\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]\n}" + }, + "prompt_proofread_this": { + "message": "このメールを校正" + }, + "prompt_proofread_this_full_text": { + "message": "以下のメールを校正し、スペルや文法の誤りを修正してください。修正したテキストのみで、余分なコメントや他のテキストなしで返信してください。\n\n「{%mail_typed_text%}」" + }, + "placeholder_tags_current_email": { + "message": "メールタグ" + }, + "placeholder_tags_full_list": { + "message": "既存のタグ" + }, + "prefs_OptionText_add_tags_maxnum": { + "message": "最大タグ数" + }, + "prefs_OptionText_add_tags_maxnum_Info": { + "message": "AIが提案するタグの最大数。タグ数を制限しない場合は0を設定してください。" + }, + "prompt_add_tags_maxnum": { + "message": "タグ数を次に制限:" + }, + "prefs_OptionText_add_tags_hide_exclusions": { + "message": "除外タグを非表示" + }, + "prefs_OptionText_add_tags_hide_exclusions_Info": { + "message": "チェックすると、除外リストにあるタグが確認ダイアログで非表示になります。" + }, + "prefs_OptionText_btnManageTagsInfo": { + "message": "タグ設定を管理" + }, + "AddTags_PageTitle": { + "message": "タグ設定の管理" + }, + "AddTags_info_default": { + "message": "このページでは、メールにタグを追加するためのデフォルトプロンプトの変更と除外リストの管理ができます。" + }, + "AddTags_prompt_text_title": { + "message": "現在のプロンプトテキスト" + }, + "AddTags_excl_list_title": { + "message": "除外リスト" + }, + "AddTags_excl_list_infoline": { + "message": "メールに追加できないタグのリストです。" + }, + "save": { + "message": "保存" + }, + "addtags_info_additional_statements": { + "message": "この文はプロンプトの最後に追加されます:" + }, + "reset_default": { + "message": "デフォルトにリセット" + }, + "reset": { + "message": "リセット" + }, + "addtags_excl_list_infoline2": { + "message": "1行に1語、またはカンマ区切りで追加してください。" + }, + "addtags_dialog_title": { + "message": "メールにタグを追加" + }, + "addtags_exclude_tag": { + "message": "タグを除外" + }, + "addtags_no_tags_received": { + "message": "AIからタグを受信できませんでした。" + }, + "addtags_no_valid_tags": { + "message": "除外リストでフィルタリング後、有効なタグが見つかりませんでした。" + }, + "thunderai_error_title": { + "message": "ThunderAI エラー" + }, + "thunderai_warning_title": { + "message": "ThunderAI 警告" + }, + "prefs_OptionText_add_tags_first_uppercase": { + "message": "最初の文字を大文字に" + }, + "prefs_OptionText_add_tags_first_uppercase_Info": { + "message": "チェックすると、タグのラベルは最初の文字のみ大文字で、残りは小文字になります。" + }, + "AddTags_prompt_prefs_title": { + "message": "タグ追加オプション" + }, + "prefs_SurveyLinkText": { + "message": "フィードバックを共有してThunderAIの改善にご協力ください!" + }, + "prefs_SurveyLinkText2": { + "message": "ここをクリック、1分で完了!" + }, + "prefs_OpenAIComp_ForceModel": { + "message": "モデルを手動で入力" + }, + "OpenAIComp_force_model_ask": { + "message": "使用するモデル名をここに入力してください。" + }, + "prefs_OptionText_add_tags_force_lang": { + "message": "言語を強制する" + }, + "prefs_OptionText_add_tags_force_lang_Info": { + "message": "チェックすると、タグの言語がThunderAIオプションページで指定された言語に強制されます。" + }, + "prompt_add_tags_force_lang": { + "message": "タグは次の言語で書く必要があります:" + }, + "prefs_Connection_type_Google_Gemini_API": { + "message": "Google Gemini API" + }, + "prefs_GoogleGemini_API_Key": { + "message": "APIキー" + }, + "GoogleGemini_Models": { + "message": "Google Gemini APIモデル" + }, + "GoogleGemini_Models_Fetch": { + "message": "Google Geminiモデルリストを更新" + }, + "GoogleGemini_Models_Error_fetching": { + "message": "Google Geminiモデルの取得中にエラー" + }, + "google_gemini_api_request_failed": { + "message": "Google Gemini APIリクエストが失敗しました" + }, + "google_gemini_empty_apikey": { + "message": "Google Gemini APIのAPIキーが設定されていません。オプションページで設定してください。" + }, + "google_gemini_empty_model": { + "message": "Google Gemini APIのモデルが選択されていません。オプションページで選択してください。" + }, + "GoogleGemini_SystemInstruction": { + "message": "システム指示" + }, + "GoogleGemini_SystemInstruction_Info": { + "message": "システム指示を設定すると、モデルにタスクを理解するための追加コンテキストを提供し、よりカスタマイズされた応答を提供し、送信されるプロンプトに対して特定のガイドラインに従わせることができます。" + }, + "ChatGPT_Developer_Messages": { + "message": "開発者メッセージ" + }, + "ChatGPT_Developer_Messages_Info": { + "message": "開発者メッセージを設定すると、モデルにタスクを理解するための追加コンテキストを提供し、よりカスタマイズされた応答を提供し、送信されるプロンプトに対して特定のガイドラインに従わせることができます。" + }, + "prefs_OptionText_btnManagePrompts_infoline3": { + "message": "プロンプトで{%tags_full_list%}データプレースホルダーを使用して、使用可能なタグをリストできます。適切なプロンプトを使用すると、既存のタグリストからのみタグを選択させることができます。" + }, + "placeholder_mail_typed_text": { + "message": "引用メール本文の前に入力されたテキスト" + }, + "placeholder_mail_quoted_text": { + "message": "メール本文の引用テキスト" + }, + "prompt_get_calendar_event": { + "message": "新しいカレンダーイベントを追加" + }, + "prompt_get_calendar_event_full_text": { + "message": "以下のテキストからカレンダーイベントを生成するために必要なすべての関連詳細を抽出してください。抽出情報には以下を含めてください:\n- イベントタイトル\n- 開始日時(指定されている場合はタイムゾーンを含む)\n- 終了日時(指定されている場合はタイムゾーンを含む)\n- 終日(言及されている場合)\n- 出席者\nデータはカレンダーイベントの作成に直接使用できるよう、明確かつ一貫した形式にしてください。\n相対的な時間参照がある場合、メールの日時は「{%mail_datetime%}」であることを考慮してください。この参照に基づいて開始日時を計算してください。計算された開始日時が「{%current_datetime%}」より前の場合、「{%current_datetime%}」を基準として開始日時を再計算してください。\n期間が指定されていない場合は、1時間に設定してください。\n出席者:{%author%}、{%recipients%}、{%cc_list%}。存在する場合、私のアドレス{%account_email_address%}を除外してください。\n必要な情報の1つ以上を取得できない場合は、空の文字列で応答してください。\nJSON形式のみで応答を生成してください。追加のテキストや説明は含めず、JSONのみを提供してください。使用する形式:\n{\n\"startDate\": \"YYYYMMDDTHHMMSS\",\n\"endDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"カレンダーイベントの概要をここに\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nテキスト:「{%selected_text%}」" + }, + "prompt_get_task": { + "message": "新しいタスクを追加" + }, + "prompt_get_task_full_text": { + "message": "以下のテキストからタスクを生成するために必要なすべての関連詳細を抽出してください。抽出情報には以下を含めてください:\n- 期限日時(指定されている場合はタイムゾーンを含む)\n- タスクの概要\n- 開始日時(指定されている場合はタイムゾーンを含む)\nデータはタスクの作成に直接使用できるよう、明確かつ一貫した形式にしてください。\n相対的な時間参照がある場合、メールの日時は「{%mail_datetime%}」であることを考慮してください。この参照に基づいて開始日時を計算してください。計算された開始日時が「{%current_datetime%}」より前の場合、「{%current_datetime%}」を基準として開始日時を再計算してください。\n必要な情報の1つ以上を取得できない場合は、空の文字列で応答してください。\nJSON形式のみで応答を生成してください。追加のテキストや説明は含めず、JSONのみを提供してください。使用する形式:\n{\n\"InitialDate\": \"YYYYMMDDTHHMMSS\",\n\"dueDate\": \"YYYYMMDDTHHMMSS\",\n\"summary\": \"タスクの概要をここに\"\n}\n日付に関する情報がない場合は、それらを削除してください。\nテキスト:「{%selected_text%}」" + }, + "prefs_OptionText_get_calendar_event": { + "message": "選択テキストから新しいカレンダーイベントを追加" + }, + "prefs_OptionText_get_calendar_event_Info": { + "message": "チェックすると、選択テキストからカレンダーイベント情報を取得するアイテムがメニューに追加されます。" + }, + "get_calendar_event_prompt_prefs_title": { + "message": "カレンダーイベントオプション" + }, + "prefs_OptionText_get_task": { + "message": "選択テキストから新しいタスクを追加" + }, + "prefs_OptionText_get_task_Info": { + "message": "チェックすると、選択テキストからタスク情報を取得するアイテムがメニューに追加されます。" + }, + "get_task_prompt_prefs_title": { + "message": "タスクオプション" + }, + "Select_your_timezone": { + "message": "タイムゾーンを選択" + }, + "prefs_OptionText_calendar_enforce_timezone": { + "message": "指定したタイムゾーンを強制" + }, + "prefs_OptionText_calendar_enforce_timezone_Info": { + "message": "チェックすると、指定したタイムゾーンがカレンダーイベントとタスクに強制されます。" + }, + "prefs_OptionText_btnManageCalendarEventInfo": { + "message": "カレンダーイベント設定を管理" + }, + "GetCalendarEvent_PageTitle": { + "message": "カレンダーイベント設定の管理" + }, + "GetCalendarEvent_info_default": { + "message": "このページでは、選択テキストからカレンダーイベントを取得するためのデフォルトプロンプトを変更できます。" + }, + "GetCalendarEvent_prompt_text_title": { + "message": "現在のプロンプトテキスト" + }, + "prefs_OptionText_AdvancedPromptResponse_infoline2": { + "message": "プロンプトは自由に変更できますが、AIからの応答はデフォルトプロンプトで指定されたJSON形式である必要があります!" + }, + "prefs_OptionText_get_calendar_event_Sparks_not_present": { + "message": "カレンダーイベントとタスク機能を使用するには、ThunderAI Sparksアドオンをインストールしてください。" + }, + "prefs_OptionText_get_calendar_event_Sparks_wrong_version": { + "message": "カレンダーイベントとタスク機能を使用するには、ThunderAI Sparksアドオンの更新版をインストールしてください。" + }, + "GetTask_PageTitle": { + "message": "タスク設定の管理" + }, + "GetTask_info_default": { + "message": "このページでは、選択テキストからタスクを取得するためのデフォルトプロンプトを変更できます。" + }, + "prefs_OptionText_btnManageTaskInfo": { + "message": "タスク設定を管理" + }, + "prefs_OptionText_download_now": { + "message": "今すぐThunderAI Sparksをダウンロード!" + }, + "placeholder_mail_datetime": { + "message": "メールの日時" + }, + "placeholder_current_datetime": { + "message": "現在の日時" + }, + "calendar_getting_data_error": { + "message": "カレンダーイベントデータの取得エラー" + }, + "calendar_opening_dialog_error": { + "message": "カレンダーイベントダイアログを開く際のエラー" + }, + "task_getting_data_error": { + "message": "タスクデータの取得エラー" + }, + "task_opening_dialog_error": { + "message": "タスクダイアログを開く際のエラー" + }, + "no_valid_data_received": { + "message": "AIから有効なデータを受信できませんでした。" + }, + "prefs_OptionText_add_tags_auto": { + "message": "タグを自動追加" + }, + "prefs_OptionText_add_tags_auto_Info": { + "message": "チェックすると、AIが新着メールに自動的にタグを追加します。" + }, + "prefs_OptionText_add_tags_auto_Info2": { + "message": "このページの下部で、この機能を有効にするアカウントを選択してください。" + }, + "prefs_OptionText_add_tags_auto_force_existing": { + "message": "既存のタグを強制" + }, + "prefs_OptionText_add_tags_auto_force_existing_Info": { + "message": "チェックすると、AIは既存のタグのみを追加し、新しいタグは作成しません。" + }, + "prefs_OptionText_add_tags_auto_uselist": { + "message": "これらのタグのみを使用" + }, + "prefs_OptionText_add_tags_auto_uselist_Info": { + "message": "チェックすると、AIは以下のリストのタグのみを追加します。" + }, + "prefs_OptionText_add_tags_auto_uselist_list_Info": { + "message": "リストには少なくとも1つのタグが必要です。1行に1タグ、またはカンマ区切りで追加してください。" + }, + "prompt_add_tags_use_list": { + "message": "このカンマ区切りリストのタグのみを使用" + }, + "prefs_OptionText_add_tags_auto_only_inbox": { + "message": "受信トレイのメールにのみタグを追加" + }, + "prefs_OptionText_add_tags_auto_only_inbox_Info": { + "message": "チェックすると、AIは受信トレイフォルダーで受信したメールにのみタグを追加します。" + }, + "prefs_OptionText_add_tags_use_specific_integration_Info": { + "message": "チェックすると、ThunderAIオプションページで選択されたものに関わらず、以下で指定されたモデルとAPIがメールへのタグ追加に使用されます。" + }, + "placeholder_thunderai_def_sign": { + "message": "ThunderAIオプションで定義されたデフォルトの署名。" + }, + "thunderai_def_lang": { + "message": "ThunderAIオプションで定義されたデフォルト言語。" + }, + "placeholder_mail_attachments_info": { + "message": "メール内の添付ファイルに関する情報" + }, + "empty": { + "message": "このプレースホルダーはテキストを追加しませんが、メール本文がプロンプトの最後に自動的に追加されるのを防ぎます。" + }, + "prefs_OptionText_spamfilter": { + "message": "自動スパムフィルター" + }, + "prefs_OptionText_spamfilter_Info": { + "message": "チェックすると、ThunderAIがスパムメールを自動的にスパムフォルダーに移動します。" + }, + "prefs_OptionText_btnManageSpamFilterInfo": { + "message": "スパムフィルター設定を管理" + }, + "SpamFilter_PageTitle": { + "message": "スパムフィルター設定の管理" + }, + "SpamFilter_info_default": { + "message": "このページでは、スパムメールを検出するためのデフォルトプロンプトを変更できます。" + }, + "SpamFilter_prompt_text_title": { + "message": "現在のプロンプトテキスト" + }, + "prompt_spamfilter": { + "message": "スパムメールを検出" + }, + "prompt_spamfilter_full_text": { + "message": "以下のメールを分析し、スパムかどうかを判断してください。不審なキーワード、過度な宣伝文句、誤解を招く件名、個人情報の要求、不審な送信者アドレスなどの要素を考慮してください。\n0(スパムではない)から100(スパム)までの値と、10語以内の説明を提供してください。\nメッセージデータが欠落している場合は、値を0(スパムではない)に設定し、理由を示してください。\nJSON形式のみで応答を生成してください。追加のテキストや説明は含めず、JSONのみを提供してください。使用する形式:\n{\n\"spamValue\": <0から100の整数>,\n\"explanation\": \"判断理由の簡単な説明\"\n}\n以下がメール情報です:\n送信者:「{%author%}」\n件名:「{%mail_subject%}」\nHTML本文:「{%mail_html_body%}」" + }, + "SpamFilter_prompt_prefs_title": { + "message": "スパムフィルターオプション" + }, + "prefs_OptionText_use_specific_integration": { + "message": "特定のモデルとAPIを使用" + }, + "prefs_OptionText_spamfilter_use_specific_integration_Info": { + "message": "チェックすると、ThunderAIオプションページで選択されたものに関わらず、以下で指定されたモデルとAPIがスパムフィルターに使用されます。" + }, + "prefs_OptionText_spamfilter_threshold": { + "message": "スパムしきい値" + }, + "prefs_OptionText_spamfilter_threshold_Info": { + "message": "AIが返す値がこのしきい値を超えた場合、メールはスパムフォルダーに移動されます。" + }, + "spamfilter_threshold_too_low": { + "message": "スパムしきい値が低すぎます!多くのメールがスパムと判定される可能性があります!" + }, + "spamfilter_threshold_zero": { + "message": "スパムしきい値がゼロです!すべてのメールがスパムと判定されます!" + }, + "spamfilter_no_reports": { + "message": "まだスパムスクリーニングされたメッセージはありません。ここには現在のセッションの最新100件のスパムレポートが表示されます。" + }, + "SpamReport_Title": { + "message": "スパムフィルターレポート" + }, + "Date": { + "message": "日付" + }, + "From": { + "message": "送信者" + }, + "Subject": { + "message": "件名" + }, + "Spam_Value": { + "message": "スパム値" + }, + "Moved_to_Spam": { + "message": "スパムに移動" + }, + "Explanation": { + "message": "説明" + }, + "Report_Date": { + "message": "レポート日" + }, + "spamfilter_moved": { + "message": "はい" + }, + "spamfilter_not_moved": { + "message": "いいえ" + }, + "context_menu_mzta-add-tags": { + "message": "タグを追加" + }, + "context_menu_mzta-spamfilter": { + "message": "スパムを分析" + }, + "prefs_OptionText_add_tags_context_menu": { + "message": "「タグを追加」コンテキストメニュー項目を表示" + }, + "prefs_OptionText_add_tags_context_menu_Info": { + "message": "チェックすると、メッセージリストでメールを右クリックした際に「タグを追加」コンテキストメニュー項目が表示されます。" + }, + "prefs_OptionText_spamfilter_context_menu": { + "message": "「スパムを分析」コンテキストメニュー項目を表示" + }, + "prefs_OptionText_spamfilter_context_menu_Info": { + "message": "チェックすると、メッセージリストでメールを右クリックした際に「スパムを分析」コンテキストメニュー項目が表示されます。" + }, + "noActiveCalendar": { + "message": "編集可能なカレンダーが見つかりません!" + }, + "btn_show_differences": { + "message": "差分を表示" + }, + "chatgpt_win_diff_title": { + "message": "元のテキストと変更後のテキストの差分" + }, + "apiwebchat_you": { + "message": "あなた" + }, + "apiwebchat_info": { + "message": "情報" + }, + "apiwebchat_error": { + "message": "エラー" + }, + "apiwebchat_use_this_answer": { + "message": "この回答を使用" + }, + "apiwebchat_stopping": { + "message": "停止中" + }, + "apiwebchat_receiving_data": { + "message": "データ受信中" + }, + "hyprland_warning": { + "message": "AIチャットウィンドウを開く際に問題が発生した場合は、高さと幅の値を0に設定してみてください。この問題は、Hyprlandを使用している場合など、特定の環境のLinuxで発生することがあります。" + }, + "remember_CORS": { + "message": "サーバーでCORS設定を行う必要があることを忘れないでください!" + }, + "maybe_CORS_openai_comp": { + "message": "OpenAI互換APIを使用するには、サーバーでCORS設定が必要な場合があります。" + }, + "CORS_alternative_1": { + "message": "CORS設定に問題がありますか?" + }, + "CORS_alternative_2": { + "message": "下のボタンを押して権限を付与し、CORSの問題を回避してください。" + }, + "CORS_give_allurls_perm": { + "message": "「すべてのURL」権限を付与" + }, + "prefs_OptionText_composing_plain_text": { + "message": "プレーンテキストで作成" + }, + "prefs_OptionText_composing_plain_text_Info": { + "message": "メールをプレーンテキスト形式で作成している場合は、このオプションをチェックしてください。" + }, + "Replace_No_Selected_Text": { + "message": "テキストが選択されていません。AIの応答をメールの先頭に挿入しますか?" + }, + "prefs_ollama_num_ctx": { + "message": "コンテキストトークン数" + }, + "prefs_ollama_num_ctx_Info": { + "message": "Ollama APIで使用するコンテキストトークンの数。サーバーにパラメーターとして渡したくない場合は0を設定してください。" + }, + "ask_chatgptweb_permission_1": { + "message": "ChatGPT Web連携を使用するには、必要な権限を付与する必要があります。" + }, + "ask_anthropic_api_permission_1": { + "message": "Claude API連携を使用するには、必要な権限を付与する必要があります。" + }, + "ask_openai_api_permission_1": { + "message": "OpenAI API連携を使用するには、必要な権限を付与する必要があります。" + }, + "ask_integration_permission_2_popup": { + "message": "ここをクリックして新しいタブを開き、指示に従ってください。" + }, + "ask_integration_permission_2": { + "message": "ここをクリックして続行してください。" + }, + "ask_integration_permission_ok": { + "message": "権限が付与されました。ここをクリックしてこのタブを閉じ、メインウィンドウに戻ることができます。" + }, + "AccountSelector_AutoTags": { + "message": "自動タグ付けを有効にするアカウントを選択" + }, + "AccountSelector_AutoTags_infoline": { + "message": "各変更は即座に保存されます。" + }, + "AccountSelector_Spamfilter": { + "message": "スパムフィルターを有効にするアカウントを選択" + }, + "prefs_OptionText_chatgpt_web_project": { + "message": "ChatGPT Webプロジェクト" + }, + "prefs_OptionText_chatgpt_web_project_info": { + "message": "ChatGPT Webインターフェースで強制されるプロジェクトです。" + }, + "prefs_OptionText_chatgpt_web_custom_gpt": { + "message": "ChatGPT WebカスタムGPT" + }, + "prefs_OptionText_chatgpt_web_custom_gpt_info": { + "message": "ChatGPT Webインターフェースで強制されるカスタムGPTです。" + }, + "prefs_OptionText_chatgpt_web_custom_data_info": { + "message": "次の形式である必要があります:" + }, + "prefs_OptionText_chatgpt_web_custom_data_info2": { + "message": "関連するChatGPTページを開いたときに、ブラウザのURLフィールドで正しい値を確認できます。" + }, + "customPrompts_Properties": { + "message": "プロパティ" + }, + "customPrompts_show_additional_info": { + "message": "追加プロパティを表示" + }, + "customPrompts_hide_additional_info": { + "message": "追加プロパティを非表示" + }, + "customPrompts_show_additional_info_show": { + "message": "追加プロパティ" + }, + "prefs_OptionText_CustomGPT_Warn": { + "message": "オプションまたはプロンプトでプロジェクトが指定されている場合、カスタムGPT設定が上書きされます。" + }, + "prefs_OptionText_Project_No_temporary_chat_warn": { + "message": "オプションまたはプロンプトでプロジェクトが指定されている場合、一時チャットは使用されません。" + }, + "prefs_Anthropic_API_Key": { + "message": "Claude APIキー" + }, + "prefs_Connection_type_Anthropic_API": { + "message": "Claude API" + }, + "Anthropic_Models": { + "message": "Claudeモデル" + }, + "Anthropic_Models_Fetch": { + "message": "Claudeモデルリストを更新" + }, + "Anthropic_Models_Error_fetching": { + "message": "Claudeモデルの取得中にエラー" + }, + "Anthropic_Version": { + "message": "Claude APIバージョン" + }, + "Anthropic_Version_Info": { + "message": "必須。何をしているか分からない限り、この値を変更しないでください。詳細:" + }, + "prefs_OptionText_anthropic_max_tokens": { + "message": "最大トークン数" + }, + "prefs_OptionText_anthropic_max_tokens_Info": { + "message": "補完で生成するトークンの最大数。プロンプトのトークン数とmax_tokensの合計は、モデルのコンテキスト長を超えることはできません。" + }, + "anthropic_empty_apikey": { + "message": "Claude APIのAPIキーが設定されていません。オプションページで設定してください。" + }, + "anthropic_empty_model": { + "message": "Claude APIのモデルが選択されていません。オプションページで選択してください。" + }, + "anthropic_empty_version": { + "message": "Claude APIのバージョン文字列が設定されていません。オプションページで設定してください。" + }, + "anthropic_api_request_failed": { + "message": "Claude APIリクエストが失敗しました" + }, + "_api_connecting": { + "message": "$api_string$に以下の設定で接続を試みています...", + "placeholders": { + "api_string": { + "content": "$1" + } + } + }, + "_api_connecting_model": { + "message": "モデル" + }, + "_api_connecting_host": { + "message": "ホスト" + }, + "_api_connecting_version": { + "message": "バージョン" + }, + "prefs_OpenAIComp_AvailableServices": { + "message": "利用可能なサービス" + }, + "prefs_OpenAIComp_AvailableServices_Info": { + "message": "OpenAI互換APIで利用可能なサービスから1つを選択するか、手動で入力してください。" + }, + "Custom": { + "message": "カスタム" + }, + "OpenAIComp_Configs_ConfirmApply": { + "message": "設定「$config_name$」を適用してもよろしいですか?", + "placeholders": { + "config_name": { + "content": "$1" + } + } + }, + "apiwebchat_selection_info": { + "message": "テキストを選択すると、その部分のみが考慮されます。" + }, + "ChatGPT_chatgpt_api_store": { + "message": "ストレージを使用" + }, + "ChatGPT_chatgpt_api_store_info": { + "message": "チェックすると、チャットがOpenAIに保存されます。" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "使用するサンプリング温度(0から2の間)。0.8のような高い値は出力をよりランダムにし、0.2のような低い値はより集中的で決定論的にします。" + }, + "prefs_ollama_temperature_Info": { + "message": "モデルの温度。温度を上げると、モデルはより創造的に回答します。デフォルト値は0.8です。0から1の間の値を使用することをお勧めします。" + }, + "prefs_ollama_think": { + "message": "思考を有効にする" + }, + "prefs_ollama_think_Info": { + "message": "チェックすると、モデルは回答前に思考します。このオプションは「think」機能をサポートするモデルでのみ機能します。" + }, + "chatgpt_win_change_reply_type": { + "message": "クリックして返信タイプを変更" + }, + "prefs_OptionText_add_tags_exclusions_exact_match": { + "message": "除外の完全一致" + }, + "prefs_OptionText_add_tags_exclusions_exact_match_Info": { + "message": "チェックすると、除外リストの単語がタグと完全に一致した場合のみ除外されます。チェックしない場合、タグに含まれている場合も一致します。" + }, + "customDataPH_manageDataPH": { + "message": "データプレースホルダーを管理" + }, + "customDataPH_manageDataPH_info_default_3": { + "message": "カスタムプロンプトを作成するときと同様に、オートコンプリートでデフォルトのデータプレースホルダーを使用することもできます。" + }, + "customDataPH_manageDataPH_info_default": { + "message": "このページでは、カスタムプロンプトで使用するカスタムデータプレースホルダーを定義できます。" + }, + "customDataPH_manageDataPH_info_default_2": { + "message": "同じIDの既存のデータプレースホルダーは上書きされます。新しいIDのプレースホルダーは追加されます。" + }, + "customDataPH_ExportAll": { + "message": "すべてのカスタムデータプレースホルダーをエクスポート" + }, + "customDataPH_Import": { + "message": "新しいデータプレースホルダーをインポート" + }, + "customDataPH_form_label_Text": { + "message": "データプレースホルダーテキスト" + }, + "customDataPH_saving_custom": { + "message": "カスタムデータプレースホルダーを保存中..." + }, + "customDataPH_saved": { + "message": "カスタムデータプレースホルダーを保存しました!" + }, + "customDataPH_btnAddNewCommit": { + "message": "データプレースホルダーを追加" + }, + "importCustomDataPH_confirmText": { + "message": "新しいカスタムデータプレースホルダーをインポートしようとしています。" + }, + "importCustomDataPH_start_import": { + "message": "カスタムデータプレースホルダーのインポートを開始中..." + }, + "importCustomDataPH_import_completed": { + "message": "カスタムデータプレースホルダーのインポートが完了しました!「すべて保存」ボタンをクリックして変更を保存してください。" + }, + "importCustomDataPH_invalidFile": { + "message": "インポートしようとしているファイルは有効なカスタムデータプレースホルダーファイルではありません。" + }, + "importCustomDataPH_invalidDataPHs": { + "message": "インポートしようとしているファイルには有効なカスタムデータプレースホルダーが含まれていません。" + }, + "customDataPH_add_to_menu": { + "message": "メニューに追加されたプロンプトで使用可能" + }, + "prefs_OptionText_chatgpt_web_br_replace_info": { + "message": "AIの応答に含まれる
                    タグは改行に置換されます。" + }, + "prefs_OpenAIComp_ClearModelsList": { + "message": "モデルリストをクリア" + }, + "OpenAIComp_ClearModelsList_Confirm": { + "message": "モデルリストをクリアしてもよろしいですか?この操作は元に戻せません。" + }, + "prefs_api_temperature": { + "message": "温度" + }, + "prefs_openai_comp_temperature_Info": { + "message": "使用するサンプリング温度(0から2の間)。0.8のような高い値は出力をよりランダムにし、0.2のような低い値はより集中的で決定論的にします。" + }, + "chatgpt_click_force_completion": { + "message": "ChatGPTが完了したかどうかを確認できないようです。ここをクリックしてジョブの完了を強制してください。" + }, + "warn_API_needed": { + "message": "この機能を使用するには、ChatGPT Web連携ではなくAPI連携が必要です。上のチェックボックスをチェックしてから左のボタンをクリックすると、機能設定ページで特定のAPIを定義できます。" + }, + "prefs_google_gemini_thinking_budget": { + "message": "思考バジェット" + }, + "prefs_google_gemini_thinking_budget_Info": { + "message": "思考に使用するトークン数を定義します。選択したモデルが思考をサポートしていない場合、またはデフォルトの方法を使用したい場合は、このフィールドを空白のままにしてください。思考を無効にするには0を、動的思考を有効にするには-1を入力してください。" + }, + "prefs_google_gemini_temperature_Info": { + "message": "このパラメーターは0.0から2.0の間の数値である必要があります。出力のランダム性を制御します。デフォルト値はモデルによって異なります。APIコールでパラメーターを設定しない場合は空のままにしてください。" + }, + "SelectAll": { + "message": "すべて選択" + }, + "DeselectAll": { + "message": "すべて解除" + }, + "Anthropic_System_Prompt": { + "message": "システムプロンプト" + }, + "Anthropic_System_Prompt_Info": { + "message": "システムプロンプトを使用してClaudeに役割を与えることで、パフォーマンスを向上させることができます。ロールプロンプティングと呼ばれるこの技術は、Claudeでシステムプロンプトを使用する最も強力な方法です。適切な役割により、Claudeを一般的なアシスタントから仮想的な専門家に変えることができます。" + }, + "prefs_anthropic_temperature_Info": { + "message": "応答に注入されるランダム性の量。デフォルトは1.0。0.0から1.0の範囲。分析的/多肢選択には0.0に近い値を、創造的で生成的なタスクには1.0に近い値を使用してください。温度が0.0でも、結果は完全に決定論的にはなりません。" + }, + "Optional_Permission_Denied_Model_Fetching": { + "message": "この連携のモデルを取得するために必要なオプション権限が拒否されました。" } } From 6484e48964404625440b73847394115eb654f0c6 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Jan 2026 22:37:34 +0100 Subject: [PATCH 048/123] correctly not setting the conn_type calue for new prompts. See #623 --- pages/_lib/connection-ui.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 7e668e50..eb9f62de 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -31,7 +31,11 @@ import { sanitizeChatGPTWebCustomData } from '../../js/mzta-utils.js'; import { openAICompConfigs } from '../../js/api/openai_comp_configs.js'; -import { loadPrompt, savePrompt, clearPromptAPI } from '../../js/mzta-prompts.js'; +import { + loadPrompt, + savePrompt, + clearPromptAPI +} from '../../js/mzta-prompts.js'; export const varConnectionUI = { permission_all_urls: false @@ -1204,6 +1208,8 @@ function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { if (options.some(o => o.value === prevValue)) { conntype_select.value = prevValue; + } else if (no_chatgpt_web) { + conntype_select.value = ""; } } From facc0bce749ca5c51ee11e6401794030a97d21d5 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Jan 2026 22:38:30 +0100 Subject: [PATCH 049/123] resetApiSettings method added. showing the reset button also in the new prompt form. see #623 --- pages/customprompts/mzta-custom-prompts.js | 84 ++++++++++++---------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index a85a5053..9ce27807 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -145,7 +145,11 @@ document.addEventListener('DOMContentLoaded', async () => { afterTrId: 'api_ui_anchor', selectId: 'new_prompt_api_type', no_chatgpt_web: true, - taLog: taLog + taLog: taLog, + customButtonLabel: browser.i18n.getMessage("Reset"), + customButtonCallback: () => { + resetApiSettings('new_prompt_api_type'); + } }); // Fill defaults for new prompt form @@ -477,42 +481,7 @@ function handleEditClick(e) { taLog: taLog, customButtonLabel: browser.i18n.getMessage("Reset"), customButtonCallback: () => { - const selectEl = document.getElementById(selectId); - if (selectEl) { - selectEl.value = ''; - selectEl.dispatchEvent(new Event('change')); - } - - // Clear UI inputs - for (const [integration, options] of Object.entries(integration_options_config)) { - for (const key of Object.keys(options)) { - const propName = `${integration}_${key}`; - const inputId = `${prefix}${propName}`; - const inputEl = document.getElementById(inputId); - if (inputEl) { - if (inputEl.type === 'checkbox') { - inputEl.checked = false; - } else { - inputEl.value = ''; - } - } - } - } - - // Update promptsList - const item = promptsList.get('id', id)[0]; - if (item) { - let newValues = item.values(); - newValues.api_type = ''; - for (const [integration, options] of Object.entries(integration_options_config)) { - for (const key of Object.keys(options)) { - const propName = `${integration}_${key}`; - newValues[propName] = ''; - } - } - item.values(newValues); - } - setSomethingChanged(); + resetApiSettings(selectId, id); } }).then(() => { populateConnectionUI(tr, id, prefix, selectId); @@ -535,6 +504,47 @@ function handleEditClick(e) { toggleAdditionalPropertiesShow(tr); } +function resetApiSettings(selectId, id = null) { + let prefix = ''; + if (id) prefix = `prompt_${id}_`; + const selectEl = document.getElementById(selectId); + if (selectEl) { + selectEl.value = ''; + selectEl.dispatchEvent(new Event('change')); + } + + // Clear UI inputs + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + const inputId = `${prefix}${propName}`; + const inputEl = document.getElementById(inputId); + if (inputEl) { + if (inputEl.type === 'checkbox') { + inputEl.checked = false; + } else { + inputEl.value = ''; + } + } + } + } + + // Update promptsList + const item = promptsList.get('id', id)[0]; + if (item) { + let newValues = item.values(); + newValues.api_type = ''; + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + newValues[propName] = ''; + } + } + item.values(newValues); + } + setSomethingChanged(); +} + function populateConnectionUI(tr, id, prefix, selectId) { const item = promptsList.get('id', id)[0]; const itemValues = item.values(); From 04afa25aa44a7cd9e158719c6b13b1e1c2de398c Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Jan 2026 22:47:19 +0100 Subject: [PATCH 050/123] version set to 3.8.3. release notes updated --- CHANGELOG.md | 4 ++++ manifest.json | 2 +- options/mzta-release-notes.html | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b6ce47f..3e377ba5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

                    Version 3.8.3 - 22/01/2026

                    +
                      +
                    • Fix: Correctly saving the API settings in new custom prompts [#623].
                    • +

                    Version 3.8.2 - 20/01/2026

                    • Fix: Correctly saving the enabled status in custom prompts [#621].
                    • diff --git a/manifest.json b/manifest.json index b3dacaa4..c70f8713 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.2", + "version": "3.8.3", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 16f4dd6c..77bbb729 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

                      ThunderAI Release Notes

                      +

                      Version 3.8.3 - 22/01/2026

                      +
                        +
                      • Fix: Correctly saving the API settings in new custom prompts [#623].
                      • +

                      Version 3.8.2 - 20/01/2026

                      • Fix: Correctly saving the enabled status in custom prompts [#621].
                      • From bf9e37dda1b55d8d4132a310f7e4ec4c8ce6a571 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Jan 2026 22:51:13 +0100 Subject: [PATCH 051/123] release notes udpated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e377ba5..31d24e43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@

                        Version 3.8.3 - 22/01/2026

                        • Fix: Correctly saving the API settings in new custom prompts [#623].
                        • +
                        • Japanese (ja) translation added, thanks to Taichi Ito.

                        Version 3.8.2 - 20/01/2026

                          diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 77bbb729..c87ef83c 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -10,6 +10,7 @@

                          Version 3.8.3 - 22/01/2026

                          • Fix: Correctly saving the API settings in new custom prompts [#623].
                          • +
                          • Japanese (ja) translation added, thanks to Taichi Ito.

                          Version 3.8.2 - 20/01/2026

                            From 84c003f2a6ef4bc58e92861a0087e6bcc3b5ca5e Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 22 Jan 2026 23:01:50 +0100 Subject: [PATCH 052/123] LANG.md updated --- LANG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/LANG.md b/LANG.md index 48e6e12d..73a39f9a 100644 --- a/LANG.md +++ b/LANG.md @@ -6,6 +6,7 @@ es fr hr it +ja pl pt-br ru From 607708930f168b4c2d11e61eda0413b3d15dc7c1 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 22 Jan 2026 23:06:27 +0100 Subject: [PATCH 053/123] Add Japanese translation contributor to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0c2500ed..d66504b2 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ Are you using this addon in your Thunderbird? - German (de): Generated automatically - Greek (el): [ChristosK.](https://github.com/christoskaterini) - Italian (it): [Mic](https://github.com/micz) +- Japanese (ja): [Taichi Ito](https://github.com/watya1) - Polski (pl): [neexpl](https://github.com/neexpl), [makkacprzak](https://github.com/makkacprzak) - Português Brasileiro (pt-br): Bruno Pereira de Souza - Russian (ru): [Maksim](https://hosted.weblate.org/user/law820314/) From 5fc77c395e03ed1a2541137f66d28acba0e92c46 Mon Sep 17 00:00:00 2001 From: Mic Date: Fri, 23 Jan 2026 21:01:47 +0100 Subject: [PATCH 054/123] Update translations section in README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d66504b2..95d1828f 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,9 @@ Are you using this addon in your Thunderbird? ## Attributions ### Translations -- Chinese (Simplified): [jeklau](https://github.com/jeklau) -- Chinese (Traditional): [evez](https://github.com/evez) +- Chinese (Simplified) (zh_Hans): [jeklau](https://github.com/jeklau) +- Chinese (Traditional) (zh_Hant): [evez](https://github.com/evez) +- Croatian (hr): Petar Jedvaj - Czech (cs): [Fjuro](https://hosted.weblate.org/user/Fjuro/), [Jaroslav Staněk](https://hosted.weblate.org/user/jaroush/) - French (fr): Generated automatically, [Noam](https://github.com/noam-sc) - German (de): Generated automatically From 4576549bab8a14dd9381c8506d1a4bb69533b4f0 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 29 Jan 2026 22:53:33 +0100 Subject: [PATCH 055/123] version set to 4.0.0 --- CHANGELOG.md | 4 ++++ manifest.json | 2 +- options/mzta-release-notes.html | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31d24e43..7c0d2847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

                            Version 4.0.0 - ??/??/2026

                            +
                              +
                            • ...
                            • +

                            Version 3.8.3 - 22/01/2026

                            • Fix: Correctly saving the API settings in new custom prompts [#623].
                            • diff --git a/manifest.json b/manifest.json index c70f8713..961a7d9e 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.3", + "version": "4.0.0", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index c87ef83c..6c27cd96 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

                              ThunderAI Release Notes

                              +

                              Version 4.0.0 - ??/??/2026

                              +
                                +
                              • ...
                              • +

                              Version 3.8.3 - 22/01/2026

                              • Fix: Correctly saving the API settings in new custom prompts [#623].
                              • From 63b80d4e42f43d64cf35541a35dd1f09f8f4d1ca Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 29 Jan 2026 23:29:27 +0100 Subject: [PATCH 056/123] summarize icon added. see #615 --- README.md | 1 + images/summarize.png | Bin 0 -> 1131 bytes js/mzta-utils.js | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 images/summarize.png diff --git a/README.md b/README.md index 95d1828f..847034c6 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ _The language status represents the percentage of translated strings in the late - [JessiGue](https://www.flaticon.com/authors/jessigue) for the show/hide icon for api key fields - [Iconka.com](https://www.iconarchive.com/artist/iconka.html) for the autotag context menu icon - [Icojam](https://www.iconarchive.com/artist/icojam.html) for the spam filter context menu icon +- [Roundicons](https://www.flaticon.com/authors/roundicons) for the summarize context menu icon
                                diff --git a/images/summarize.png b/images/summarize.png new file mode 100644 index 0000000000000000000000000000000000000000..9c829f0e7973c4edd301a37369a651dd57285e0f GIT binary patch literal 1131 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjR6 zFfbkhVa69WwIM)3$r9IylHmNblJdl&REF~Ma=pyF?Be9af>gcyqV(DCY@`?%n3Mv1 zLR|m<{|{7;2Kf2;1q1}FfxyZND8<9W!^_Ld$jHdb$_gae*w|E6R1_5zPZfim-yJu%?lSvWBRnl&G4nn1;TXy}!7m zl$3?Dlxvu@jI6YUv$UO$bYQxSyn>8Vkc>-+Tu{1PY?)kKxqNi7e0+s`QjJ1Jt71-< zQhu+ps+zKfwpz_R^|}QbjY~9|muYpb)78<@Gcwkjx>w)8P=ERXgV{$7W*;+{d)#pT zDZ}}vjTW6VUUI>B=_M0mV@nGQOKTe|I|qA5XL~0XCubKIXJ=OrPY-WjA1^N-KmU-B z(9rOR_}JL^xVZSZ_{5~-q=dwz#KfGetfGQ~lET8u^75+k^6JXU)~2Se_V%v!j=r9r z34MJN`}!vJ_fMWMVcO)$^JdSUKWEOe#fz6OS+aV?iZv@&u3fci-Rjlr*R0vFX3h4^ zn|E#7wr}_DgM0TL+PCk>fdj`59Xfva@Y$0m&z(AT{?w_9XU<%`c=6h$OE<1uxpnQ@ z?d#X?-n@D5=FJDUZ$G?q=kdLJPaiyZ_VD5JM~_}Se*E&ulb27QzIyiT&5IXrU%Ytt z^5y$iuRgqf{ps!7&+p!SdH??Uft?3|ai&%h(^hteEs_U$IoBCe*gV@Db~CK7|ETUE{-7)hm#W$9ti{oDs!*!C@?fOF!*@N zH*#;E&W56(RT{#~tDl5@I=D>4kL{nNh{T4i(Q_QrlvUZzgr@~8aruAEb=6|F9w`TI z=3lF4PY*~q@GQo*TKn+IC(;*^W=)v$M$%y)qov)+lP5n`6+6CRo&2%E(t_v2cP1%; z)q4ewtm8P&{ApW)`GUJDR+c9%yP6_2u9ldT&2;rN@ymZ5X*^4u?M{QMw1&}w>yFN= zYjl6I`CR|n$8DyscE3T$JRy!FINo&|QfGjhrdLpfNwhTtP0z85oTWp00i_>zopr0Q-8u-v9sr literal 0 HcmV?d00001 diff --git a/js/mzta-utils.js b/js/mzta-utils.js index eb4f8d49..dca1a52a 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -29,7 +29,7 @@ export const contextMenuID_Summarize = 'mzta-summarize'; export const contextMenuIconsPath = { [contextMenuID_AddTags]: 'moz-extension:images/autotags.png', [contextMenuID_Spamfilter]: 'moz-extension:images/spamfilter.png', - // [contextMenuID_Summarize]: 'moz-extension:images/summarize.png', + [contextMenuID_Summarize]: 'moz-extension:images/summarize.png', }; export function getLanguageDisplayName(languageCode) { From f489e65483d63b8c93e32176a0c43da0860e0385 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 29 Jan 2026 23:36:00 +0100 Subject: [PATCH 057/123] correctly adding context menu item for summarize when activating the feature. fixes #626 --- mzta-background.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index 1f009330..d7a6f629 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -885,6 +885,7 @@ function setupStorageChangeListener() { if(newConnectionType === "chatgpt_web"){ removeContextMenu(contextMenuID_AddTags); removeContextMenu(contextMenuID_Spamfilter); + removeContextMenu(contextMenuID_Summarize); } addContextMenuItems(); } @@ -924,11 +925,9 @@ function setupStorageChangeListener() { } if (changes.summarize) { if (changes.summarize.newValue){ - if (prefs_init.summarize){ - addContextMenu(contextMenuID_Summarize); - } + addContextMenu(contextMenuID_Summarize); } else { - removeContextMenu(contextMenuID_Summarize); + removeContextMenu(contextMenuID_Summarize); } } reload_pref_init(); @@ -993,7 +992,7 @@ function addContextMenuItems() { } // Add Context menu: Summarize - if(prefs_init.summarize && checkAPIIntegration(prefs_init.connection_type && prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { + if(prefs_init.summarize && checkAPIIntegration(prefs_init.connection_type, prefs_init.summarize_use_specific_integration, prefs_init.summarize_connection_type)) { addContextMenu(contextMenuID_Summarize); } } From 3ba98c7d90156b59bf1555578d51881883a7f697 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 29 Jan 2026 23:45:00 +0100 Subject: [PATCH 058/123] Removed the spamfilter_context_menu and add_tags_context_menu options and always show the context menu when the corresponding feature is active. See #609 --- _locales/en/messages.json | 16 -------------- mzta-background.js | 30 +++++---------------------- options/mzta-options-default.js | 2 -- pages/addtags/mzta-add-tags.html | 10 +-------- pages/spamfilter/mzta-spamfilter.html | 10 +-------- 5 files changed, 7 insertions(+), 61 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 3ce55cc4..307b30e6 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1371,22 +1371,6 @@ "message": "Summarize", "description": "" }, - "prefs_OptionText_add_tags_context_menu": { - "message": "Show the \"Add tags\" context menu item", - "description": "" - }, - "prefs_OptionText_add_tags_context_menu_Info": { - "message": "If checked, the \"Add tags\" context menu item will be shown when right-clicking on an email in the messages list.", - "description": "" - }, - "prefs_OptionText_spamfilter_context_menu": { - "message": "Show the \"Analyze for spam\" context menu item", - "description": "" - }, - "prefs_OptionText_spamfilter_context_menu_Info": { - "message": "If checked, the \"Analyze for spam\" context menu item will be shown when right-clicking on an email in the messages list.", - "description": "" - }, "noActiveCalendar": { "message": "No editable calendar found!", "description": "" diff --git a/mzta-background.js b/mzta-background.js index d7a6f629..1b5d9bde 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -809,8 +809,6 @@ async function reload_pref_init(){ summarize: prefs_default.summarize, spamfilter_threshold: prefs_default.spamfilter_threshold, dynamic_menu_force_enter: prefs_default.dynamic_menu_force_enter, - add_tags_context_menu: prefs_default.add_tags_context_menu, - spamfilter_context_menu: prefs_default.spamfilter_context_menu, ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); _process_incoming = prefs_init.add_tags_auto || prefs_init.spamfilter; @@ -891,34 +889,16 @@ function setupStorageChangeListener() { } // context menu changes for add_tags and spamfilter - if (changes.add_tags_context_menu) { - if(changes.add_tags_context_menu.newValue){ + if (changes.add_tags) { + if(changes.add_tags.newValue){ addContextMenu(contextMenuID_AddTags); }else{ removeContextMenu(contextMenuID_AddTags); } } - if (changes.add_tags) { - if(changes.add_tags.newValue){ - if(prefs_init.add_tags_context_menu){ - addContextMenu(contextMenuID_AddTags); - } - }else{ - removeContextMenu(contextMenuID_AddTags); - } - } - if (changes.spamfilter_context_menu) { - if(changes.spamfilter_context_menu.newValue){ - addContextMenu(contextMenuID_Spamfilter); - }else{ - removeContextMenu(contextMenuID_Spamfilter); - } - } if (changes.spamfilter) { if(changes.spamfilter.newValue){ - if(prefs_init.spamfilter_context_menu){ - addContextMenu(contextMenuID_Spamfilter); - } + addContextMenu(contextMenuID_Spamfilter); }else{ removeContextMenu(contextMenuID_Spamfilter); } @@ -982,12 +962,12 @@ function removeContextMenu(menu_id) { function addContextMenuItems() { // Add Context menu: Add tags - if(prefs_init.add_tags && prefs_init.add_tags_context_menu && checkAPIIntegration(prefs_init.connection_type, prefs_init.add_tags_use_specific_integration,prefs_init.add_tags_connection_type)){ + if(prefs_init.add_tags && checkAPIIntegration(prefs_init.connection_type, prefs_init.add_tags_use_specific_integration,prefs_init.add_tags_connection_type)){ addContextMenu(contextMenuID_AddTags); } // Add Context menu: Spamfilter - if(prefs_init.spamfilter && prefs_init.spamfilter_context_menu && checkAPIIntegration(prefs_init.connection_type, prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type)){ + if(prefs_init.spamfilter && checkAPIIntegration(prefs_init.connection_type, prefs_init.spamfilter_use_specific_integration,prefs_init.spamfilter_connection_type)){ addContextMenu(contextMenuID_Spamfilter); } diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index d5ccf9b2..164cd511 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -123,7 +123,6 @@ export const prefs_default = { add_tags_auto_only_inbox: true, add_tags_auto_uselist: false, add_tags_auto_uselist_list: '', - add_tags_context_menu: true, add_tags_enabled_accounts: [], get_calendar_event: true, get_task: true, @@ -131,7 +130,6 @@ export const prefs_default = { calendar_timezone: '', spamfilter: false, spamfilter_threshold: 70, - spamfilter_context_menu: true, spamfilter_enabled_accounts: [], summarize: false, ...generated_prefs diff --git a/pages/addtags/mzta-add-tags.html b/pages/addtags/mzta-add-tags.html index b6c35fd6..59104df0 100644 --- a/pages/addtags/mzta-add-tags.html +++ b/pages/addtags/mzta-add-tags.html @@ -101,15 +101,7 @@ - - __MSG_prefs_OptionText_add_tags_context_menu__ - - - - + __MSG_prefs_OptionText_add_tags_auto_force_existing__ diff --git a/pages/spamfilter/mzta-spamfilter.html b/pages/spamfilter/mzta-spamfilter.html index 271b4264..c8ad47f4 100644 --- a/pages/spamfilter/mzta-spamfilter.html +++ b/pages/spamfilter/mzta-spamfilter.html @@ -35,15 +35,7 @@ - - __MSG_prefs_OptionText_spamfilter_context_menu__ - - - - +
                                __MSG_SpamFilter_prompt_text_title__ From 0b7e81cd7b93a07478a9730608e1225aad128806 Mon Sep 17 00:00:00 2001 From: Mic Date: Fri, 30 Jan 2026 22:09:04 +0100 Subject: [PATCH 059/123] GEMINI.MD file added --- GEMINI.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 GEMINI.md diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 00000000..1eb93734 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,36 @@ +# ThunderAI Project Agent Context + +## Project Overview +ThunderAI is a Mozilla Thunderbird add-on that integrates Large Language Models (LLMs) such as ChatGPT, Gemini, Claude, and Ollama for advanced email management. It allows users to analyze, draft, correct, tag, and create calendar events directly from the email client. + +## Technical Stack +- **Languages:** JavaScript (ES6+), HTML5, CSS3. +- **Environment:** Thunderbird MailExtension API (based on WebExtensions). +- **Core Logic:** Primarily located in `background.js` and UI-specific scripts. +- **API Integrations:** Specific logic is contained within dedicated API provider files (e.g., `api_openai.js`, `api_google_gemini.js`). + +## Development Rules & Style Guide +- **Code Style:** Use modern JavaScript. Prefer `async/await` over chained Promises. +- **Naming Conventions:** Use `camelCase` for variables and functions. +- **Security:** - Never hardcode API keys in the source code. + - Use `messenger.storage.local` for data persistence. + - Strictly adhere to CORS policies for external API calls. +- **i18n:** + - The project supports multiple languages via `_locales/`. When adding UI strings, always use `messenger.i18n.getMessage()`. + - When you need to modify language file, modify only the english version. + +## Files & Directories Structure +- `manifest.json`: Extension entry point and permission definitions. +- `api_*.js`: Modules for integration with different AI providers. +- `options/`: Configuration and settings pages. +- `_locales/`: Translation files (JSON format). +- `graphics/`: Visual assets and icons. + +## Important Commands & Workflow +- **Testing:** Since this is a Thunderbird add-on, testing is performed by loading the extension as a "Temporary Add-on" via Thunderbird's `Debug Add-ons` menu. +- **Build:** The project does not use complex build tools (no Webpack/Vite by default); it is a "pure" MailExtension. + +## Agent Instructions +1. **Context Awareness:** When modifying API-related files, ensure compatibility with the existing placeholder system (e.g., `{%mail_body%}`, `{%additional_text%}`). +2. **Permission Review:** Before modifying `manifest.json`, verify that any new permissions requested are strictly necessary for the feature. +3. **Compatibility:** Ensure code is compatible with the latest Thunderbird ESR (Extended Support Release) versions. \ No newline at end of file From 310dbf88189a1ff3443d5bc1175b56a3e9122668 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 30 Jan 2026 22:21:37 +0100 Subject: [PATCH 060/123] release notes updated --- CHANGELOG.md | 2 ++ options/mzta-release-notes.html | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0d2847..f63c2394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@

                                Version 4.0.0 - ??/??/2026

                                  +
                                • [All APIs] Added a special prompt to summarize one or more emails, using a context menu command [#615]. Thanks to Guido Kraemer for his great work on this feature.
                                • +
                                • [All APIs] "Analyze for spam" and "Add tags" context menu items are always shown when the corresponding feature is enabled [#609].
                                • ...

                                Version 3.8.3 - 22/01/2026

                                diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 6c27cd96..6248de5d 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -9,6 +9,8 @@

                                ThunderAI Release Notes

                                Version 4.0.0 - ??/??/2026

                                  +
                                • [All APIs] Added a special prompt to summarize one or more emails, using a context menu command [#615]. Thanks to Guido Kraemer for his great work on this feature.
                                • +
                                • [All APIs] "Analyze for spam" and "Add tags" context menu items are always shown when the corresponding feature is enabled [#609].
                                • ...

                                Version 3.8.3 - 22/01/2026

                                From 72737d538b2d998ed018097812a7a2e10b423435 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 30 Jan 2026 22:22:59 +0100 Subject: [PATCH 061/123] strict_min_version set to 140.0. see #616 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 961a7d9e..8014a58a 100644 --- a/manifest.json +++ b/manifest.json @@ -8,7 +8,7 @@ "browser_specific_settings": { "gecko": { "id": "thunderai@micz.it", - "strict_min_version": "115.0" + "strict_min_version": "140.0" } }, "message_display_action": { From 6463e180af634043dca83a76c60c56f0130062b2 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 30 Jan 2026 22:24:17 +0100 Subject: [PATCH 062/123] tb115 segmenter removed. see #616 --- js/tb115_segmenter/tb115_loader.js | 65 ---------------------------- js/tb115_segmenter/tb115_polyfill.js | 49 --------------------- manifest.json | 2 +- 3 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 js/tb115_segmenter/tb115_loader.js delete mode 100644 js/tb115_segmenter/tb115_polyfill.js diff --git a/js/tb115_segmenter/tb115_loader.js b/js/tb115_segmenter/tb115_loader.js deleted file mode 100644 index df476c7c..00000000 --- a/js/tb115_segmenter/tb115_loader.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2026 Mic (m@micz.it) - - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -// Firefox 115 and, consequently, Thunderbird 115 are not compatible with Intl.Segmenter. -// ChatGPT is using Intl.Segmenter, so we have to do something about it or it won't work... - -// console.log("[ThunderAI] Intl.Segmenter: " + Intl.Segmenter); - -(function() { - if('Segmenter' in Intl){ - // console.log('[ThunderAI] TB128+ detected. Intl.Segmenter is already supported.'); - return; - } - // Creates a