From 5d75226f40266afff498ecc1123d656394df75b2 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 28 Aug 2025 20:44:00 +0200 Subject: [PATCH 001/146] implemented the new api call, no response elaboration yet --- api_webchat/controller.js | 2 +- js/api/openai_responses.js | 111 ++++++++++++++++++ js/mzta-special-commands.js | 2 +- js/workers/model-worker-openai_responses.js | 124 ++++++++++++++++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 js/api/openai_responses.js create mode 100644 js/workers/model-worker-openai_responses.js diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 7434816e..809c7a1f 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -46,7 +46,7 @@ let worker = null; switch (llm) { case "chatgpt_api": - worker = new Worker('../js/workers/model-worker-openai.js', { type: 'module' }); + worker = new Worker('../js/workers/model-worker-openai_responses.js', { type: 'module' }); break; case "google_gemini_api": worker = new Worker('../js/workers/model-worker-google_gemini.js', { type: 'module' }); diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js new file mode 100644 index 00000000..9066132e --- /dev/null +++ b/js/api/openai_responses.js @@ -0,0 +1,111 @@ +/* + * 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 . + */ + +// Some original methods derived from https://github.com/ali-raheem/Aify/blob/4ece286095ea7a6cf89d696902e6b81b5d1c3a4b/plugin/html/API.js + + +export class OpenAI { + + apiKey = ''; + model = ''; + developer_messages = ''; + stream = false; + store = false; + + constructor(apiKey, model, developer_messages, stream, store) { + this.apiKey = apiKey; + this.model = model; + this.developer_messages = developer_messages; + this.stream = stream; + this.store = store; + } + + + fetchModels = async () => { + try{ + const response = await fetch("https://api.openai.com/v1/models", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer "+ this.apiKey + }, + }); + + if (!response.ok) { + const errorDetail = await response.text(); + let err_msg = "[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail; + console.error(err_msg); + let output = {}; + output.ok = false; + output.error = errorDetail; + return output; + } + + let output = {}; + output.ok = true; + let output_response = await response.json(); + output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id)); + + return output; + }catch (error) { + console.error("[ThunderAI] OpenAI API request failed: " + error); + let output = {}; + output.is_exception = true; + output.ok = false; + output.error = "OpenAI API request failed: " + error; + return output; + } + } + + fetchResponse = async (messages, maxTokens = 0) => { + + let request_body = { + model: this.model, + input: messages, + stream: this.stream, + store: this.store, + ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {}) + } + + if(this.developer_messages !== ''){ + request_body.instructions = this.developer_messages; + } + + // console.log(">>>>>>>>>>> OpenAI API request: " + JSON.stringify(messages)); + + try { + const response = await fetch("https://api.openai.com/v1/responses", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer "+ this.apiKey + }, + body: JSON.stringify(request_body), + }); + return response; + }catch (error) { + console.error("[ThunderAI] OpenAI Responses API request failed: " + error); + let output = {}; + output.is_exception = true; + output.ok = false; + output.error = "OpenAI Responses API request failed: " + error; + return output; + } + } + +} \ No newline at end of file diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 2ac7ac38..bf0671f0 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -37,7 +37,7 @@ this.do_debug = do_debug; switch (this.llm) { case "chatgpt_api": - this.worker = new Worker(new URL('./workers/model-worker-openai.js', import.meta.url), { type: 'module' }); + this.worker = new Worker(new URL('./workers/model-worker-openai_responses.js', import.meta.url), { type: 'module' }); break; case "google_gemini_api": this.worker = new Worker(new URL('./workers/model-worker-google_gemini.js', import.meta.url), { type: 'module' }); diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js new file mode 100644 index 00000000..2e58e08b --- /dev/null +++ b/js/workers/model-worker-openai_responses.js @@ -0,0 +1,124 @@ +/* + * 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 . + * + * + * This file contains a modified version of the code from the project at https://github.com/boxabirds/chatgpt-frontend-nobuild + * The original code has been released under the Apache License, Version 2.0. + */ + +import { OpenAI } from '../api/openai_responses.js'; +import { taLogger } from '../mzta-logger.js'; + +let chatgpt_api_key = null; +let chatgpt_model = ''; +let openai = null; +let stopStreaming = false; +let i18nStrings = null; +let do_debug = false; +let taLog = null + +let conversationHistory = []; +let assistantResponseAccumulator = ''; +let previous_response_id = -1; + +self.onmessage = async function(event) { + if (event.data.type === 'init') { + chatgpt_api_key = event.data.chatgpt_api_key; + chatgpt_model = event.data.chatgpt_model; + openai = new OpenAI(chatgpt_api_key, chatgpt_model, event.data.chatgpt_developer_messages, true, event.data.chatgpt_api_store); + do_debug = event.data.do_debug; + i18nStrings = event.data.i18nStrings; + taLog = new taLogger('model-worker-openai_responses', do_debug); + } else if (event.data.type === 'chatMessage') { + conversationHistory.push({ role: 'user', content: event.data.message }); + + const response = await openai.fetchResponse(conversationHistory); //4096); + postMessage({ type: 'messageSent' }); + + if (!response.ok) { + let error_message = ''; + let errorDetail = ''; + if(response.is_exception === true){ + error_message = response.error; + }else{ + try{ + const errorJSON = await response.json(); + errorDetail = JSON.stringify(errorJSON); + error_message = errorJSON.error.message; + }catch(e){ + error_message = response.statusText; + } + taLog.log("error_message: " + JSON.stringify(error_message)); + } + postMessage({ type: 'error', payload: i18nStrings["chatgpt_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail }); + throw new Error("[ThunderAI] OpenAI ChatGPT API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail); + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder("utf-8"); + let buffer = ''; + + while (true) { + if (stopStreaming) { + stopStreaming = false; + reader.cancel(); + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); + break; + } + const { done, value } = await reader.read(); + if (done) { + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); + break; + } + // lots of low-level OpenAI response parsing stuff + const chunk = decoder.decode(value); + buffer += chunk; + taLog.log("buffer " + buffer); + const lines = buffer.split("\n"); + buffer = lines.pop(); + let parsedLines = []; + try{ + parsedLines = lines + .map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix + .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" + // .map((line) => JSON.parse(line)); // Parse the JSON string + .map((line) => { + taLog.log("line: " + JSON.stringify(line)); + return JSON.parse(line); + }); + }catch(e){ + taLog.error("Error parsing lines: " + e); + } + + for (const parsedLine of parsedLines) { + console.log(">>>>>>>>>> parsedLine: " + JSON.stringify(parsedLine)); + const { content } = parsedLine; + // Update the UI with the new content + if (content) { + assistantResponseAccumulator += content; + postMessage({ type: 'newToken', payload: { token: content } }); + } + } + } + } else if (event.data.type === 'stop') { + stopStreaming = true; + } +}; From c00e784059a0d2882e7ecab37f4d67bf3d6da31f Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 22 Dec 2025 23:33:31 +0100 Subject: [PATCH 002/146] version set to 3.8.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 ce925d7a..3c70b39b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ +

Version 3.8.0 - ??/??/2025

+
    +
  • ...
  • +

Version 3.7.8 - 18/12/2025

  • Greek (el) translation added, thanks to ChristosK..
  • diff --git a/manifest.json b/manifest.json index a3cef247..92a30fb3 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.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 d021cc39..ba1fe7f5 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,6 +7,10 @@

    ThunderAI Release Notes

    +

    Version 3.8.0 - ??/??/2025

    +
      +
    • ...
    • +

    Version 3.7.8 - 18/12/2025

    • Greek (el) translation added, thanks to ChristosK..
    • From 8e04393c191dd103009966b9da7a02d41d10f0c1 Mon Sep 17 00:00:00 2001 From: Mic Date: Thu, 28 Aug 2025 20:44:00 +0200 Subject: [PATCH 003/146] implemented the new api call, no response elaboration yet --- api_webchat/controller.js | 2 +- js/api/openai_responses.js | 111 ++++++++++++++++++ js/mzta-special-commands.js | 2 +- js/workers/model-worker-openai_responses.js | 124 ++++++++++++++++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 js/api/openai_responses.js create mode 100644 js/workers/model-worker-openai_responses.js diff --git a/api_webchat/controller.js b/api_webchat/controller.js index d4a9cc52..5f29526a 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -49,7 +49,7 @@ let worker = null; switch (llm) { case "chatgpt_api": - worker = new Worker('../js/workers/model-worker-openai.js', { type: 'module' }); + worker = new Worker('../js/workers/model-worker-openai_responses.js', { type: 'module' }); break; case "google_gemini_api": worker = new Worker('../js/workers/model-worker-google_gemini.js', { type: 'module' }); diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js new file mode 100644 index 00000000..9066132e --- /dev/null +++ b/js/api/openai_responses.js @@ -0,0 +1,111 @@ +/* + * 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 . + */ + +// Some original methods derived from https://github.com/ali-raheem/Aify/blob/4ece286095ea7a6cf89d696902e6b81b5d1c3a4b/plugin/html/API.js + + +export class OpenAI { + + apiKey = ''; + model = ''; + developer_messages = ''; + stream = false; + store = false; + + constructor(apiKey, model, developer_messages, stream, store) { + this.apiKey = apiKey; + this.model = model; + this.developer_messages = developer_messages; + this.stream = stream; + this.store = store; + } + + + fetchModels = async () => { + try{ + const response = await fetch("https://api.openai.com/v1/models", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer "+ this.apiKey + }, + }); + + if (!response.ok) { + const errorDetail = await response.text(); + let err_msg = "[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail; + console.error(err_msg); + let output = {}; + output.ok = false; + output.error = errorDetail; + return output; + } + + let output = {}; + output.ok = true; + let output_response = await response.json(); + output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id)); + + return output; + }catch (error) { + console.error("[ThunderAI] OpenAI API request failed: " + error); + let output = {}; + output.is_exception = true; + output.ok = false; + output.error = "OpenAI API request failed: " + error; + return output; + } + } + + fetchResponse = async (messages, maxTokens = 0) => { + + let request_body = { + model: this.model, + input: messages, + stream: this.stream, + store: this.store, + ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {}) + } + + if(this.developer_messages !== ''){ + request_body.instructions = this.developer_messages; + } + + // console.log(">>>>>>>>>>> OpenAI API request: " + JSON.stringify(messages)); + + try { + const response = await fetch("https://api.openai.com/v1/responses", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: "Bearer "+ this.apiKey + }, + body: JSON.stringify(request_body), + }); + return response; + }catch (error) { + console.error("[ThunderAI] OpenAI Responses API request failed: " + error); + let output = {}; + output.is_exception = true; + output.ok = false; + output.error = "OpenAI Responses API request failed: " + error; + return output; + } + } + +} \ No newline at end of file diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 0bbab812..a6ddaad3 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -44,7 +44,7 @@ this.do_debug = do_debug; switch (this.llm) { case "chatgpt_api": - this.worker = new Worker(new URL('./workers/model-worker-openai.js', import.meta.url), { type: 'module' }); + this.worker = new Worker(new URL('./workers/model-worker-openai_responses.js', import.meta.url), { type: 'module' }); break; case "google_gemini_api": this.worker = new Worker(new URL('./workers/model-worker-google_gemini.js', import.meta.url), { type: 'module' }); diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js new file mode 100644 index 00000000..2e58e08b --- /dev/null +++ b/js/workers/model-worker-openai_responses.js @@ -0,0 +1,124 @@ +/* + * 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 . + * + * + * This file contains a modified version of the code from the project at https://github.com/boxabirds/chatgpt-frontend-nobuild + * The original code has been released under the Apache License, Version 2.0. + */ + +import { OpenAI } from '../api/openai_responses.js'; +import { taLogger } from '../mzta-logger.js'; + +let chatgpt_api_key = null; +let chatgpt_model = ''; +let openai = null; +let stopStreaming = false; +let i18nStrings = null; +let do_debug = false; +let taLog = null + +let conversationHistory = []; +let assistantResponseAccumulator = ''; +let previous_response_id = -1; + +self.onmessage = async function(event) { + if (event.data.type === 'init') { + chatgpt_api_key = event.data.chatgpt_api_key; + chatgpt_model = event.data.chatgpt_model; + openai = new OpenAI(chatgpt_api_key, chatgpt_model, event.data.chatgpt_developer_messages, true, event.data.chatgpt_api_store); + do_debug = event.data.do_debug; + i18nStrings = event.data.i18nStrings; + taLog = new taLogger('model-worker-openai_responses', do_debug); + } else if (event.data.type === 'chatMessage') { + conversationHistory.push({ role: 'user', content: event.data.message }); + + const response = await openai.fetchResponse(conversationHistory); //4096); + postMessage({ type: 'messageSent' }); + + if (!response.ok) { + let error_message = ''; + let errorDetail = ''; + if(response.is_exception === true){ + error_message = response.error; + }else{ + try{ + const errorJSON = await response.json(); + errorDetail = JSON.stringify(errorJSON); + error_message = errorJSON.error.message; + }catch(e){ + error_message = response.statusText; + } + taLog.log("error_message: " + JSON.stringify(error_message)); + } + postMessage({ type: 'error', payload: i18nStrings["chatgpt_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail }); + throw new Error("[ThunderAI] OpenAI ChatGPT API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail); + } + + const reader = response.body.getReader(); + const decoder = new TextDecoder("utf-8"); + let buffer = ''; + + while (true) { + if (stopStreaming) { + stopStreaming = false; + reader.cancel(); + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); + break; + } + const { done, value } = await reader.read(); + if (done) { + conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); + assistantResponseAccumulator = ''; + postMessage({ type: 'tokensDone' }); + break; + } + // lots of low-level OpenAI response parsing stuff + const chunk = decoder.decode(value); + buffer += chunk; + taLog.log("buffer " + buffer); + const lines = buffer.split("\n"); + buffer = lines.pop(); + let parsedLines = []; + try{ + parsedLines = lines + .map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix + .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" + // .map((line) => JSON.parse(line)); // Parse the JSON string + .map((line) => { + taLog.log("line: " + JSON.stringify(line)); + return JSON.parse(line); + }); + }catch(e){ + taLog.error("Error parsing lines: " + e); + } + + for (const parsedLine of parsedLines) { + console.log(">>>>>>>>>> parsedLine: " + JSON.stringify(parsedLine)); + const { content } = parsedLine; + // Update the UI with the new content + if (content) { + assistantResponseAccumulator += content; + postMessage({ type: 'newToken', payload: { token: content } }); + } + } + } + } else if (event.data.type === 'stop') { + stopStreaming = true; + } +}; From 65ee959f0de16a912c1560bd70fbde4d8c612fc4 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 22 Dec 2025 23:46:33 +0100 Subject: [PATCH 004/146] improved openai responses see #407 --- js/api/openai_responses.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js index 9066132e..f84c0f4e 100644 --- a/js/api/openai_responses.js +++ b/js/api/openai_responses.js @@ -27,7 +27,13 @@ export class OpenAI { stream = false; store = false; - constructor(apiKey, model, developer_messages, stream, store) { + constructor({ + apiKey = '', + model = '', + developer_messages = '', + stream = false, + store = false + } = {}) { this.apiKey = apiKey; this.model = model; this.developer_messages = developer_messages; @@ -59,7 +65,7 @@ export class OpenAI { let output = {}; output.ok = true; let output_response = await response.json(); - output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id)); + output.response = output_response.data.filter(item => item.id.startsWith('gpt-') || item.id.startsWith('o1-') || item.id.startsWith('o4-') || item.id.startsWith('o3-')).sort((a, b) => b.id.localeCompare(a.id)); return output; }catch (error) { @@ -79,7 +85,7 @@ export class OpenAI { input: messages, stream: this.stream, store: this.store, - ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {}) + ...(maxTokens > 0 ? { 'max_completion_tokens': parseInt(maxTokens) } : {}) } if(this.developer_messages !== ''){ From e0f5f263edb6b9fc29b01ab4aad455fdd7e9e56c Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 22 Dec 2025 23:46:58 +0100 Subject: [PATCH 005/146] model filtering improved --- js/api/openai.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/api/openai.js b/js/api/openai.js index 6d589c4c..daadaea0 100644 --- a/js/api/openai.js +++ b/js/api/openai.js @@ -65,7 +65,7 @@ export class OpenAI { let output = {}; output.ok = true; let output_response = await response.json(); - output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id)); + output.response = output_response.data.filter(item => item.id.startsWith('gpt-') || item.id.startsWith('o1-') || item.id.startsWith('o4-') || item.id.startsWith('o3-')).sort((a, b) => b.id.localeCompare(a.id)); return output; }catch (error) { From 87eef12efdf83fe2ed47f3f3bba8efdc36ad2609 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 22 Dec 2025 23:48:03 +0100 Subject: [PATCH 006/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c70b39b..7f370cd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@

      Version 3.8.0 - ??/??/2025

        +
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • ...

      Version 3.7.8 - 18/12/2025

      diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index ba1fe7f5..d66af704 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -9,6 +9,7 @@

      ThunderAI Release Notes

      Version 3.8.0 - ??/??/2025

        +
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • ...

      Version 3.7.8 - 18/12/2025

      From 713415c1d2d43d9964ba9269cbb6602a29d1bb8b Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 23 Dec 2025 00:29:00 +0100 Subject: [PATCH 007/146] now using the openai responses API. see #407 --- js/api/openai_responses.js | 16 +++++--- js/workers/model-worker-openai_responses.js | 42 +++++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js index f84c0f4e..f4f4977a 100644 --- a/js/api/openai_responses.js +++ b/js/api/openai_responses.js @@ -27,13 +27,13 @@ export class OpenAI { stream = false; store = false; - constructor({ + constructor( apiKey = '', model = '', developer_messages = '', stream = false, store = false - } = {}) { + ) { this.apiKey = apiKey; this.model = model; this.developer_messages = developer_messages; @@ -78,14 +78,20 @@ export class OpenAI { } } - fetchResponse = async (messages, maxTokens = 0) => { + fetchResponse = async (messages, maxTokens = 0, previous_response_id = null) => { + + const input = messages.map(msg => ({ + role: msg.role, + content: [{ type: "input_text", text: msg.content }] + })); let request_body = { model: this.model, - input: messages, + input: input, stream: this.stream, store: this.store, - ...(maxTokens > 0 ? { 'max_completion_tokens': parseInt(maxTokens) } : {}) + ...(maxTokens > 0 ? { 'max_output_tokens': parseInt(maxTokens) } : {}), + ...(previous_response_id && this.store ? { 'previous_response_id': previous_response_id } : {}) } if(this.developer_messages !== ''){ diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js index 2e58e08b..cb1562d5 100644 --- a/js/workers/model-worker-openai_responses.js +++ b/js/workers/model-worker-openai_responses.js @@ -29,11 +29,11 @@ let openai = null; let stopStreaming = false; let i18nStrings = null; let do_debug = false; -let taLog = null +let taLog = null; let conversationHistory = []; let assistantResponseAccumulator = ''; -let previous_response_id = -1; +let previous_response_id = null; self.onmessage = async function(event) { if (event.data.type === 'init') { @@ -43,10 +43,19 @@ self.onmessage = async function(event) { do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-openai_responses', do_debug); + previous_response_id = null; } else if (event.data.type === 'chatMessage') { conversationHistory.push({ role: 'user', content: event.data.message }); - const response = await openai.fetchResponse(conversationHistory); //4096); + let messagesToSend = conversationHistory; + if (previous_response_id) { + messagesToSend = [conversationHistory[conversationHistory.length - 1]]; + taLog.log("previous_response_id: " + previous_response_id); + } else { + taLog.log("no previous_response_id"); + } + + const response = await openai.fetchResponse(messagesToSend, 0, previous_response_id); postMessage({ type: 'messageSent' }); if (!response.ok) { @@ -97,24 +106,33 @@ self.onmessage = async function(event) { let parsedLines = []; try{ parsedLines = lines + .map((line) => line.trim()) + .filter((line) => line.startsWith("data:")) .map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" // .map((line) => JSON.parse(line)); // Parse the JSON string .map((line) => { - taLog.log("line: " + JSON.stringify(line)); - return JSON.parse(line); - }); + try { + taLog.log("line: " + JSON.stringify(line)); + return JSON.parse(line); + } catch (e) { + taLog.warn("JSON parse warning, skipped line: " + line + " - " + e.message); + return null; + } + }) + .filter((parsed) => parsed !== null); }catch(e){ taLog.error("Error parsing lines: " + e); } for (const parsedLine of parsedLines) { - console.log(">>>>>>>>>> parsedLine: " + JSON.stringify(parsedLine)); - const { content } = parsedLine; - // Update the UI with the new content - if (content) { - assistantResponseAccumulator += content; - postMessage({ type: 'newToken', payload: { token: content } }); + if (parsedLine.type === 'response.created' && parsedLine.response && parsedLine.response.id){ + previous_response_id = parsedLine.response.id; + } else if (parsedLine.type === 'response.output_text.delta' && parsedLine.delta) { + assistantResponseAccumulator += parsedLine.delta; + postMessage({ type: 'newToken', payload: { token: parsedLine.delta } }); + // } else if (parsedLine.type === 'response.completed' && parsedLine.response && parsedLine.response.id) { + // previous_response_id = parsedLine.response.id; } } } From f6141f88521493c5ddb15b2b3a35d4074b742b1c Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 23 Dec 2025 00:29:00 +0100 Subject: [PATCH 008/146] old openai api files removed. see #407 --- js/api/openai.js | 129 ---------------------------- js/workers/model-worker-openai.js | 136 ------------------------------ 2 files changed, 265 deletions(-) delete mode 100644 js/api/openai.js delete mode 100644 js/workers/model-worker-openai.js diff --git a/js/api/openai.js b/js/api/openai.js deleted file mode 100644 index 6d589c4c..00000000 --- a/js/api/openai.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 . - */ - -// Some original methods derived from https://github.com/ali-raheem/Aify/blob/4ece286095ea7a6cf89d696902e6b81b5d1c3a4b/plugin/html/API.js - - -export class OpenAI { - - apiKey = ''; - model = ''; - developer_messages = ''; - stream = false; - store = false; - - constructor({ - apiKey = '', - model = '', - developer_messages = '', - stream = false, - store = false - } = {}) { - this.apiKey = apiKey; - this.model = model; - this.developer_messages = developer_messages; - this.stream = stream; - this.store = store; - } - - - fetchModels = async () => { - try{ - const response = await fetch("https://api.openai.com/v1/models", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer "+ this.apiKey - }, - }); - - if (!response.ok) { - const errorDetail = await response.text(); - let err_msg = "[ThunderAI] OpenAI API request failed: " + response.status + " " + response.statusText + ", Detail: " + errorDetail; - console.error(err_msg); - let output = {}; - output.ok = false; - output.error = errorDetail; - return output; - } - - let output = {}; - output.ok = true; - let output_response = await response.json(); - output.response = output_response.data.filter(item => item.id.startsWith('gpt-')).sort((a, b) => b.id.localeCompare(a.id)); - - return output; - }catch (error) { - console.error("[ThunderAI] OpenAI API request failed: " + error); - let output = {}; - output.is_exception = true; - output.ok = false; - output.error = "OpenAI API request failed: " + error; - return output; - } - } - - fetchResponse = async (messages, maxTokens = 0) => { - - if(this.developer_messages !== ''){ - messages.push({role: "developer", content: [{"type": "text", "text": this.developer_messages}]}); - } - - // console.log(">>>>>>>>>>> OpenAI API request: " + JSON.stringify(messages)); - - try { - const response = await fetch("https://api.openai.com/v1/chat/completions", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: "Bearer "+ this.apiKey - }, - body: JSON.stringify({ - model: this.model, - messages: messages, - stream: this.stream, - store: this.store, - ...(maxTokens > 0 ? { 'max_tokens': parseInt(maxTokens) } : {}) - }), - }); - return response; - }catch (error) { - console.error("[ThunderAI] OpenAI API request failed: " + error); - let output = {}; - output.is_exception = true; - output.ok = false; - output.error = "OpenAI API request failed: " + error; - return output; - } - } - - async countTokensUsingAPI(model, text) { - const response = await fetch('https://api.openai.com/v1/engines/'+model+'/tokenizer', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + this.apiKey - }, - body: JSON.stringify({ text }) - }); - - const data = await response.json(); - return data.token_count; - } - -} diff --git a/js/workers/model-worker-openai.js b/js/workers/model-worker-openai.js deleted file mode 100644 index 1cd9055b..00000000 --- a/js/workers/model-worker-openai.js +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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 . - * - * - * This file contains a modified version of the code from the project at https://github.com/boxabirds/chatgpt-frontend-nobuild - * The original code has been released under the Apache License, Version 2.0. - */ - -import { OpenAI } from '../api/openai.js'; -import { taLogger } from '../mzta-logger.js'; - -let chatgpt_api_key = null; -let chatgpt_model = ''; -let openai = null; -let stopStreaming = false; -let i18nStrings = null; -let do_debug = false; -let taLog = null; - -let conversationHistory = []; -let assistantResponseAccumulator = ''; - -self.onmessage = async function(event) { - if (event.data.type === 'init') { - chatgpt_api_key = event.data.chatgpt_api_key; - chatgpt_model = event.data.chatgpt_model; - openai = new OpenAI({ - apiKey: chatgpt_api_key, - model: chatgpt_model, - developer_messages: event.data.chatgpt_developer_messages, - stream: true, - store: event.data.chatgpt_api_store - }); - do_debug = event.data.do_debug; - i18nStrings = event.data.i18nStrings; - taLog = new taLogger('model-worker-openai', do_debug); - } else if (event.data.type === 'chatMessage') { - conversationHistory.push({ role: 'user', content: event.data.message }); - - const response = await openai.fetchResponse(conversationHistory); //4096); - postMessage({ type: 'messageSent' }); - - if (!response.ok) { - let error_message = ''; - let errorDetail = ''; - if(response.is_exception === true){ - error_message = response.error; - }else{ - try{ - const errorJSON = await response.json(); - errorDetail = JSON.stringify(errorJSON); - error_message = errorJSON.error.message; - }catch(e){ - error_message = response.statusText; - } - taLog.log("error_message: " + JSON.stringify(error_message)); - } - postMessage({ type: 'error', payload: i18nStrings["chatgpt_api_request_failed"] + ": " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail }); - throw new Error("[ThunderAI] OpenAI ChatGPT API request failed: " + response.status + " " + response.statusText + ", Detail: " + error_message + " " + errorDetail); - } - - const reader = response.body.getReader(); - const decoder = new TextDecoder("utf-8"); - let buffer = ''; - - while (true) { - if (stopStreaming) { - stopStreaming = false; - reader.cancel(); - conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); - assistantResponseAccumulator = ''; - postMessage({ type: 'tokensDone' }); - break; - } - const { done, value } = await reader.read(); - if (done) { - conversationHistory.push({ role: 'assistant', content: assistantResponseAccumulator }); - assistantResponseAccumulator = ''; - postMessage({ type: 'tokensDone' }); - break; - } - // lots of low-level OpenAI response parsing stuff - const chunk = decoder.decode(value); - buffer += chunk; - taLog.log("buffer " + buffer); - const lines = buffer.split("\n"); - buffer = lines.pop(); - let parsedLines = []; - try{ - parsedLines = lines - .map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix - .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" - // .map((line) => JSON.parse(line)); // Parse the JSON string - .map((line) => { - try { - taLog.log("line: " + JSON.stringify(line)); - return JSON.parse(line); - } catch (e) { - taLog.warn("JSON parse warning, skipped line: " + line + " - " + e.message); - return null; - } - }) - .filter((parsed) => parsed !== null); - }catch(e){ - taLog.error("Error parsing lines: " + e); - } - - for (const parsedLine of parsedLines) { - const { choices } = parsedLine; - const { delta } = choices[0]; - const { content } = delta; - // Update the UI with the new content - if (content) { - assistantResponseAccumulator += content; - postMessage({ type: 'newToken', payload: { token: content } }); - } - } - } - } else if (event.data.type === 'stop') { - stopStreaming = true; - } -}; From 85a473dd3dc4208c5b62bf20db9a6b5ad235fa65 Mon Sep 17 00:00:00 2001 From: Mic Date: Mon, 22 Dec 2025 23:55:00 +0100 Subject: [PATCH 009/146] include fix. see #407 --- pages/_lib/connection-ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index ef285b3a..9bbcf41a 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -17,7 +17,7 @@ */ import { prefs_default } from '../../options/mzta-options-default.js'; -import { OpenAI } from '../../js/api/openai.js'; +import { OpenAI } from '../../js/api/openai_responses.js'; import { Ollama } from '../../js/api/ollama.js'; import { OpenAIComp } from '../../js/api/openai_comp.js' import { GoogleGemini } from '../../js/api/google_gemini.js'; From 3c5b0aa02a8418fb1e7dfafb996d51ab939ea7a5 Mon Sep 17 00:00:00 2001 From: Mic Date: Mon, 22 Dec 2025 23:55:00 +0100 Subject: [PATCH 010/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f370cd5..3deb0b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@

      Version 3.8.0 - ??/??/2025

      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • +
      • [OpenAI API] Now using the new Responses API [#407].
      • ...

      Version 3.7.8 - 18/12/2025

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

      Version 3.8.0 - ??/??/2025

      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • +
      • [OpenAI API] Now using the new Responses API [#407].
      • ...

      Version 3.7.8 - 18/12/2025

      From 3e7f67b698460d5954064ac17ebe6f296a5b5155 Mon Sep 17 00:00:00 2001 From: Mic Date: Mon, 22 Dec 2025 23:55:00 +0100 Subject: [PATCH 011/146] removing commented line --- js/workers/model-worker-openai_responses.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js index cb1562d5..25037e53 100644 --- a/js/workers/model-worker-openai_responses.js +++ b/js/workers/model-worker-openai_responses.js @@ -110,7 +110,6 @@ self.onmessage = async function(event) { .filter((line) => line.startsWith("data:")) .map((line) => line.replace(/^data: /, "").trim()) // Remove the "data: " prefix .filter((line) => line !== "" && line !== "[DONE]") // Remove empty lines and "[DONE]" - // .map((line) => JSON.parse(line)); // Parse the JSON string .map((line) => { try { taLog.log("line: " + JSON.stringify(line)); From 936f225adfa7bf25808a0ec3a8301728d84506b4 Mon Sep 17 00:00:00 2001 From: mic Date: Wed, 24 Dec 2025 00:08:18 +0100 Subject: [PATCH 012/146] OpenAI class for responses constructor fixed. see #407 --- js/api/openai_responses.js | 4 ++-- js/workers/model-worker-openai_responses.js | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js index f4f4977a..30202a79 100644 --- a/js/api/openai_responses.js +++ b/js/api/openai_responses.js @@ -27,13 +27,13 @@ export class OpenAI { stream = false; store = false; - constructor( + constructor({ apiKey = '', model = '', developer_messages = '', stream = false, store = false - ) { + } = {}) { this.apiKey = apiKey; this.model = model; this.developer_messages = developer_messages; diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js index 25037e53..2427fb9d 100644 --- a/js/workers/model-worker-openai_responses.js +++ b/js/workers/model-worker-openai_responses.js @@ -39,7 +39,13 @@ self.onmessage = async function(event) { if (event.data.type === 'init') { chatgpt_api_key = event.data.chatgpt_api_key; chatgpt_model = event.data.chatgpt_model; - openai = new OpenAI(chatgpt_api_key, chatgpt_model, event.data.chatgpt_developer_messages, true, event.data.chatgpt_api_store); + openai = new OpenAI({ + apiKey: chatgpt_api_key, + model: chatgpt_model, + developer_messages: event.data.chatgpt_developer_messages, + stream: true, + store: event.data.chatgpt_api_store + }); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-openai_responses', do_debug); From 1311f568256e686aaa5279ecad43849cbd9b818b Mon Sep 17 00:00:00 2001 From: mic Date: Wed, 24 Dec 2025 00:09:34 +0100 Subject: [PATCH 013/146] version set to 3.8.0pre1 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 92a30fb3..15411cb6 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.0pre1", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { From 7a6927ceeca763292e41d349ef33a2bcdb00f4ae Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:37:25 +0100 Subject: [PATCH 014/146] dynamic placeholder methods added. see #527 --- _locales/en/messages.json | 4 +++ js/mzta-placeholders.js | 63 +++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 904229c1..a2d5a902 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -619,6 +619,10 @@ "message": "Folder path", "description": "" }, + "placeholder_mail_headers": { + "message": "Mail headers", + "description": "" + }, "placeholder_selected_text": { "message": "Selected text", "description": "" diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 0eb6f926..c211ac11 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -17,6 +17,7 @@ */ import { prefs_default } from '../options/mzta-options-default.js'; +import { getMailHeader } from './mzta-utils.js'; /* ================= PLACEHOLDERS PROPERTIES ======================================== @@ -35,6 +36,10 @@ import { prefs_default } from '../options/mzta-options-default.js'; 0: Custom placeholder 1: Default placeholder (not editable, cannot be deleted) + is_dynamic attribute: + 0: it's a fixed placeholder + 1: it's a dynamic placehoder (it means that it will have a : and then a value, like {%my_placeholder:test_value%}) + ================ USER PROPERTIES enabled attribute: 0: Disabled @@ -53,6 +58,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -61,6 +67,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -69,6 +76,7 @@ const defaultPlaceholders = [ default_value: "", type: 2, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -77,6 +85,7 @@ const defaultPlaceholders = [ default_value: "", type: 2, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -85,6 +94,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -93,6 +103,7 @@ const defaultPlaceholders = [ default_value: "", type: 1, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -101,6 +112,16 @@ const defaultPlaceholders = [ default_value: "", type: 1, is_default: "1", + is_dynamic: "0", + enabled: 1, + }, + { + id: 'mail_headers', + name: "__MSG_placeholder_mail_headers__", + default_value: "", + type: 1, + is_default: "1", + is_dynamic: "1", enabled: 1, }, { @@ -109,6 +130,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -117,6 +139,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -125,6 +148,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -133,6 +157,7 @@ const defaultPlaceholders = [ default_value: "0", type: 1, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -141,6 +166,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -149,6 +175,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -157,6 +184,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -165,6 +193,7 @@ const defaultPlaceholders = [ default_value: "", type: 1, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -173,6 +202,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -181,6 +211,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -189,6 +220,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -197,6 +229,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -205,6 +238,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -213,6 +247,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -221,6 +256,7 @@ const defaultPlaceholders = [ default_value: "", type: 0, is_default: "1", + is_dynamic: "0", enabled: 1, }, { @@ -229,6 +265,7 @@ const defaultPlaceholders = [ default_value: "", type: 1, is_default: "1", + is_dynamic: "0", enabled: 1, } ]; @@ -269,6 +306,7 @@ export async function setCustomPlaceholders(placeholders) { placeholders.forEach(ph => { ph.id = placeholdersUtils.validateCustomDataPH_ID(ph.id); ph.is_default = "0"; + ph.is_dynamic = "0"; }); await browser.storage.local.set({_custom_placeholder: placeholders}); } @@ -330,10 +368,21 @@ export const placeholdersUtils = { // Use exec to find all matches while ((match = regex.exec(text)) !== null) { - const foundPH = activePHs.find(ph => ph.id === match[1].trim()); - if (foundPH) { - matches.push(foundPH); - } + console.log(">>>>>>>>>> extractPlaceholders match: " + JSON.stringify(match)); + const foundPH = activePHs.find(ph => ph.id === match[1].trim() || (ph.is_dynamic == 1 && match[1].startsWith(ph.id + ':'))); + if (foundPH) { + if (foundPH.is_dynamic == 1 && match[1].includes(':')) { + const [id, custom_value] = match[1].split(':', 2); + const dynamicPH = { ...foundPH }; // Create a copy to avoid modifying the original + dynamicPH.id = id.trim(); + dynamicPH.custom_value = custom_value.trim(); + matches.push(dynamicPH); + console.log(">>>>>>>>>> extractPlaceholders dynamicPH: " + JSON.stringify(dynamicPH)); + } else { + matches.push(foundPH); + console.log(">>>>>>>>>> extractPlaceholders foundPH: " + JSON.stringify(foundPH)); + } + } } return matches; @@ -424,6 +473,7 @@ export const placeholdersUtils = { // console.log(">>>>>>>>>> curr_message: " + JSON.stringify(curr_message)); let finalSubs = {}; for(let currPH of currPHs){ + console.log(">>>>>>>>>> currPH: " + JSON.stringify(currPH)); switch(currPH.id){ case 'mail_text_body': finalSubs['mail_text_body'] = placeholdersUtils.failSafePlaceholders(body_text); @@ -446,8 +496,11 @@ export const placeholdersUtils = { case 'mail_folder_path': finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path); break; + case 'mail_headers': + finalSubs['mail_headers'] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.original_value)); + break; case 'selected_text': - finalSubs['selected_text'] = placeholdersUtils.failSafePlaceholders(selection_text); + finalSubs['selected_text:'+currPH.original_value] = placeholdersUtils.failSafePlaceholders(selection_text); break; case 'selected_html': finalSubs['selected_html'] = placeholdersUtils.failSafePlaceholders(selection_html); From 61c7edc54413dd5edcef60981c902a6dc96be057 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:45:05 +0100 Subject: [PATCH 015/146] var name fixed. see #527 --- js/mzta-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index c211ac11..f4ec7bb5 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -497,7 +497,7 @@ export const placeholdersUtils = { finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path); break; case 'mail_headers': - finalSubs['mail_headers'] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.original_value)); + finalSubs['mail_headers'] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.custom_value)); break; case 'selected_text': finalSubs['selected_text:'+currPH.original_value] = placeholdersUtils.failSafePlaceholders(selection_text); From 633f0dc3e29aa5fc2bc170fdff3fb0726a988f6e Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:45:20 +0100 Subject: [PATCH 016/146] getMailHeader method added. see #527 --- js/mzta-utils.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 24cb954c..e087308e 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -189,6 +189,17 @@ export async function replaceBody(tabId, replyHtml) { await messenger.compose.setComposeDetails(tabId, {body: fullBody}); } +export async function getMailHeader(curr_message, mail_header_id) { + let mail_header_value = ""; + let full_message = await browser.messages.getFull(curr_message.id); + console.log(">>>>>>>>>>>> getMailHeader full_message: " + JSON.stringify(full_message)); + if(full_message.hasOwnProperty("headers") && Object.keys(full_message.headers).some(header => header.toLowerCase() === mail_header_id.toLowerCase())){ + mail_header_value = full_message.headers[Object.keys(full_message.headers).find(header => header.toLowerCase() === mail_header_id.toLowerCase())]; + } + console.log(">>>>>>>>>>>> getMailHeader mail_header_value: " + mail_header_value) + return mail_header_value; +} + export function sanitizeHtml(input) { // Keep only
      tags and remove all other HTML tags return input.replace(/<(?!br\s*\/?)[^>]+>/gi, ''); From 06c13a4f810cc981a976ce42b265f8c2484becdd Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:47:05 +0100 Subject: [PATCH 017/146] using the correct dynamic id for the substitution. see #527 --- js/mzta-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index f4ec7bb5..e2506f90 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -497,7 +497,7 @@ export const placeholdersUtils = { finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path); break; case 'mail_headers': - finalSubs['mail_headers'] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.custom_value)); + finalSubs['mail_headers:' + currPH.custom_value] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.custom_value)); break; case 'selected_text': finalSubs['selected_text:'+currPH.original_value] = placeholdersUtils.failSafePlaceholders(selection_text); From 5521945d70de46e8068c702637772a9b7453c9ba Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:47:24 +0100 Subject: [PATCH 018/146] fixed wrong line modified --- js/mzta-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index e2506f90..b57ac76a 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -500,7 +500,7 @@ export const placeholdersUtils = { finalSubs['mail_headers:' + currPH.custom_value] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.custom_value)); break; case 'selected_text': - finalSubs['selected_text:'+currPH.original_value] = placeholdersUtils.failSafePlaceholders(selection_text); + finalSubs['selected_text'] = placeholdersUtils.failSafePlaceholders(selection_text); break; case 'selected_html': finalSubs['selected_html'] = placeholdersUtils.failSafePlaceholders(selection_html); From f22482d083bc1c2fe594b0f17af020a693f971bb Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:49:36 +0100 Subject: [PATCH 019/146] console.log debug line added --- js/mzta-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index b57ac76a..00f8bdf7 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -559,7 +559,7 @@ export const placeholdersUtils = { break; } } - + console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs)); return finalSubs; }, From 049b88302a04a79e9b7a4ac258c32fe40a1dcbcc Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 11:51:34 +0100 Subject: [PATCH 020/146] if it's async, you have to wait..... --- js/mzta-placeholders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 00f8bdf7..e8a222ae 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -497,7 +497,7 @@ export const placeholdersUtils = { finalSubs['mail_folder_path'] = placeholdersUtils.failSafePlaceholders(curr_message.folder?.path); break; case 'mail_headers': - finalSubs['mail_headers:' + currPH.custom_value] = placeholdersUtils.failSafePlaceholders(getMailHeader(curr_message, currPH.custom_value)); + finalSubs['mail_headers:' + currPH.custom_value] = placeholdersUtils.failSafePlaceholders(await getMailHeader(curr_message, currPH.custom_value)); break; case 'selected_text': finalSubs['selected_text'] = placeholdersUtils.failSafePlaceholders(selection_text); From 5e8015161b030008da2225aa93f28ffd8f1ef31a Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 12:09:26 +0100 Subject: [PATCH 021/146] correctly substituting text for a dynamic placeholder see #527 --- js/mzta-placeholders.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index e8a222ae..7308a4a2 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -395,13 +395,17 @@ export const placeholdersUtils = { use_default_value = false, skip_additional_text = false } = args || {}; + console.log(">>>>>>>>>> replacePlaceholders replacements: " + JSON.stringify(replacements)); // Regular expression to match patterns like {%...%} return text.replace(/{%\s*(.*?)\s*%}/g, function(match, p1) { + console.log(">>>>>>>>>> replacePlaceholders match: " + JSON.stringify(match)); + console.log(">>>>>>>>>> replacePlaceholders p1: " + JSON.stringify(p1)); // p1 contains the key inside {% %} if (skip_additional_text && (p1 === 'additional_text')) { return match; } - const currPlaceholder = defaultPlaceholders.find(ph => ph.id === p1); + const currPlaceholder = defaultPlaceholders.find(ph => (ph.id === p1) || (ph.is_dynamic == 1 && p1.startsWith(ph.id + ':'))); + console.log(">>>>>>>>>> replacePlaceholders currPlaceholder: " + JSON.stringify(currPlaceholder)); if (!currPlaceholder) { return match; } From 542deb25a11f1509db1f20d209114ecad8cdb241 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 12:12:53 +0100 Subject: [PATCH 022/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3deb0b4c..8a89eab1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • [OpenAI API] Now using the new Responses API [#407].
      • +
      • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
      • ...

      Version 3.7.8 - 18/12/2025

      diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 7f5c8c31..5b49f47c 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -11,6 +11,7 @@
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • [OpenAI API] Now using the new Responses API [#407].
      • +
      • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
      • ...

      Version 3.7.8 - 18/12/2025

      From dc6f4f2d5b091a590c78e06c5ad1571bee918efb Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 12:13:07 +0100 Subject: [PATCH 023/146] version set to 3.8.0pre2 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 15411cb6..d9660a70 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.0pre1", + "version": "3.8.0pre2", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { From 54689286737bea8094d0b9d260cc45b0f1275775 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 22:32:18 +0100 Subject: [PATCH 024/146] console.log debug lines commented out --- js/mzta-placeholders.js | 18 +++++++++--------- js/mzta-utils.js | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 7308a4a2..3dfd0491 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -368,7 +368,7 @@ export const placeholdersUtils = { // Use exec to find all matches while ((match = regex.exec(text)) !== null) { - console.log(">>>>>>>>>> extractPlaceholders match: " + JSON.stringify(match)); + // console.log(">>>>>>>>>> extractPlaceholders match: " + JSON.stringify(match)); const foundPH = activePHs.find(ph => ph.id === match[1].trim() || (ph.is_dynamic == 1 && match[1].startsWith(ph.id + ':'))); if (foundPH) { if (foundPH.is_dynamic == 1 && match[1].includes(':')) { @@ -377,10 +377,10 @@ export const placeholdersUtils = { dynamicPH.id = id.trim(); dynamicPH.custom_value = custom_value.trim(); matches.push(dynamicPH); - console.log(">>>>>>>>>> extractPlaceholders dynamicPH: " + JSON.stringify(dynamicPH)); + // console.log(">>>>>>>>>> extractPlaceholders dynamicPH: " + JSON.stringify(dynamicPH)); } else { matches.push(foundPH); - console.log(">>>>>>>>>> extractPlaceholders foundPH: " + JSON.stringify(foundPH)); + // console.log(">>>>>>>>>> extractPlaceholders foundPH: " + JSON.stringify(foundPH)); } } } @@ -395,17 +395,17 @@ export const placeholdersUtils = { use_default_value = false, skip_additional_text = false } = args || {}; - console.log(">>>>>>>>>> replacePlaceholders replacements: " + JSON.stringify(replacements)); + // console.log(">>>>>>>>>> replacePlaceholders replacements: " + JSON.stringify(replacements)); // Regular expression to match patterns like {%...%} return text.replace(/{%\s*(.*?)\s*%}/g, function(match, p1) { - console.log(">>>>>>>>>> replacePlaceholders match: " + JSON.stringify(match)); - console.log(">>>>>>>>>> replacePlaceholders p1: " + JSON.stringify(p1)); + // console.log(">>>>>>>>>> replacePlaceholders match: " + JSON.stringify(match)); + // console.log(">>>>>>>>>> replacePlaceholders p1: " + JSON.stringify(p1)); // p1 contains the key inside {% %} if (skip_additional_text && (p1 === 'additional_text')) { return match; } const currPlaceholder = defaultPlaceholders.find(ph => (ph.id === p1) || (ph.is_dynamic == 1 && p1.startsWith(ph.id + ':'))); - console.log(">>>>>>>>>> replacePlaceholders currPlaceholder: " + JSON.stringify(currPlaceholder)); + // console.log(">>>>>>>>>> replacePlaceholders currPlaceholder: " + JSON.stringify(currPlaceholder)); if (!currPlaceholder) { return match; } @@ -477,7 +477,7 @@ export const placeholdersUtils = { // console.log(">>>>>>>>>> curr_message: " + JSON.stringify(curr_message)); let finalSubs = {}; for(let currPH of currPHs){ - console.log(">>>>>>>>>> currPH: " + JSON.stringify(currPH)); + // console.log(">>>>>>>>>> currPH: " + JSON.stringify(currPH)); switch(currPH.id){ case 'mail_text_body': finalSubs['mail_text_body'] = placeholdersUtils.failSafePlaceholders(body_text); @@ -563,7 +563,7 @@ export const placeholdersUtils = { break; } } - console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs)); + // console.log(">>>>>>>>>> finalSubs: " + JSON.stringify(finalSubs)); return finalSubs; }, diff --git a/js/mzta-utils.js b/js/mzta-utils.js index e087308e..90a61123 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -192,11 +192,11 @@ export async function replaceBody(tabId, replyHtml) { export async function getMailHeader(curr_message, mail_header_id) { let mail_header_value = ""; let full_message = await browser.messages.getFull(curr_message.id); - console.log(">>>>>>>>>>>> getMailHeader full_message: " + JSON.stringify(full_message)); + // console.log(">>>>>>>>>>>> getMailHeader full_message: " + JSON.stringify(full_message)); if(full_message.hasOwnProperty("headers") && Object.keys(full_message.headers).some(header => header.toLowerCase() === mail_header_id.toLowerCase())){ mail_header_value = full_message.headers[Object.keys(full_message.headers).find(header => header.toLowerCase() === mail_header_id.toLowerCase())]; } - console.log(">>>>>>>>>>>> getMailHeader mail_header_value: " + mail_header_value) + // console.log(">>>>>>>>>>>> getMailHeader mail_header_value: " + mail_header_value) return mail_header_value; } From 385241efb3fdd4970a49bdcaccf280e7d92d4623 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 22:48:09 +0100 Subject: [PATCH 025/146] mapPlaceholderToSuggestion method added. see #553 --- js/mzta-placeholders.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 3dfd0491..b0ea8647 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -573,6 +573,13 @@ export const placeholdersUtils = { return ''; } return element; - } + }, + + mapPlaceholderToSuggestion(p) { + return { + command: '{%' + p.id + '%}', + type: p.type + }; + }, } From cc2d3b8e5afffc468cbe42b7232618b53e7a9579 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 22:49:26 +0100 Subject: [PATCH 026/146] mapPlaceholderToSuggestion exported directly. see #553 --- js/mzta-placeholders.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index b0ea8647..6c276fad 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -339,6 +339,12 @@ export async function prepareCustomDataPHsForImport(placeholders){ return output; } +export function mapPlaceholderToSuggestion(p) { + return { + command: '{%' + p.id + '%}', + type: p.type + }; +} export const placeholdersUtils = { @@ -575,11 +581,4 @@ export const placeholdersUtils = { return element; }, - mapPlaceholderToSuggestion(p) { - return { - command: '{%' + p.id + '%}', - type: p.type - }; - }, - -} +} \ No newline at end of file From 01df96d0c7dbd8d86d3abfa9410dee08943c41cc Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 22:52:34 +0100 Subject: [PATCH 027/146] using mapPlaceholderToSuggestion. see #553 --- pages/addtags/mzta-add-tags.js | 7 +++++-- pages/customprompts/mzta-custom-prompts.js | 8 ++++++-- pages/get-calendar-event/mzta-get-calendar-event.js | 7 +++++-- pages/get-task/mzta-get-task.js | 7 +++++-- pages/spamfilter/mzta-spamfilter.js | 7 +++++-- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 570dd5ec..73c0fcb3 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -25,7 +25,10 @@ import { savePrompt, clearPromptAPI } from "../../js/mzta-prompts.js"; -import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { + getPlaceholders, + mapPlaceholderToSuggestion + } from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; import { addTags_getExclusionList, @@ -177,7 +180,7 @@ document.addEventListener('DOMContentLoaded', async () => { updateAdditionalPromptStatements(); - autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(mapPlaceholderToSuggestion); textareaAutocomplete(addtags_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email let excl_list_textarea = document.getElementById('addtags_excl_list'); diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index b1e2f86a..0187b59a 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -20,7 +20,11 @@ import { prefs_default } from "../../options/mzta-options-default.js"; import { getPrompts, setDefaultPromptsProperties, setCustomPrompts, preparePromptsForExport, preparePromptsForImport } from "../../js/mzta-prompts.js"; import { ChatGPTWeb_models, isThunderbird128OrGreater, getLocalStorageUsedSpace, sanitizeHtml, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, openTab } from "../../js/mzta-utils.js"; import { taLogger } from "../../js/mzta-logger.js"; -import { getPlaceholders, placeholdersUtils } from "../../js/mzta-placeholders.js"; +import { + getPlaceholders, + placeholdersUtils, + mapPlaceholderToSuggestion +} from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; let prefs = null; @@ -86,7 +90,7 @@ document.addEventListener('DOMContentLoaded', async () => { } const textareas = document.querySelectorAll('.editor'); - autocompleteSuggestions = (await getPlaceholders(true)).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + autocompleteSuggestions = (await getPlaceholders(true)).map(mapPlaceholderToSuggestion); // console.log('>>>>>>>>>>> autocompleteSuggestions: ' + JSON.stringify(autocompleteSuggestions)); diff --git a/pages/get-calendar-event/mzta-get-calendar-event.js b/pages/get-calendar-event/mzta-get-calendar-event.js index 455e12d4..303ac444 100644 --- a/pages/get-calendar-event/mzta-get-calendar-event.js +++ b/pages/get-calendar-event/mzta-get-calendar-event.js @@ -19,7 +19,10 @@ 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 { + getPlaceholders, + mapPlaceholderToSuggestion +} from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; import { isAPIKeyValue } from "../../js/mzta-utils.js"; @@ -73,7 +76,7 @@ document.addEventListener('DOMContentLoaded', async () => { get_calendar_event_textarea.value = get_calendar_event_prompt.text; get_calendar_event_reset_btn.disabled = (get_calendar_event_textarea.value === browser.i18n.getMessage('prompt_get_calendar_event_full_text')); - autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(mapPlaceholderToSuggestion); textareaAutocomplete(get_calendar_event_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email }); diff --git a/pages/get-task/mzta-get-task.js b/pages/get-task/mzta-get-task.js index da7c0fee..84df2e8e 100644 --- a/pages/get-task/mzta-get-task.js +++ b/pages/get-task/mzta-get-task.js @@ -19,7 +19,10 @@ 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 { + getPlaceholders, + mapPlaceholderToSuggestion +} from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; import { isAPIKeyValue } from "../../js/mzta-utils.js"; @@ -73,7 +76,7 @@ document.addEventListener('DOMContentLoaded', async () => { get_calendar_event_textarea.value = get_calendar_event_prompt.text; get_calendar_event_reset_btn.disabled = (get_calendar_event_textarea.value === browser.i18n.getMessage('prompt_get_task_full_text')); - autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(mapPlaceholderToSuggestion); textareaAutocomplete(get_calendar_event_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email }); diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index a783d3ca..02289fd2 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -19,7 +19,10 @@ import { prefs_default } from '../../options/mzta-options-default.js'; import { taLogger } from '../../js/mzta-logger.js'; import { getSpecialPrompts, setSpecialPrompts, loadPrompt, savePrompt, clearPromptAPI } from "../../js/mzta-prompts.js"; -import { getPlaceholders } from "../../js/mzta-placeholders.js"; +import { + getPlaceholders, + mapPlaceholderToSuggestion +} from "../../js/mzta-placeholders.js"; import { textareaAutocomplete } from "../../js/mzta-placeholders-autocomplete.js"; import { taSpamReport } from '../../js/mzta-spamreport.js'; import { getAccountsList, isAPIKeyValue } from "../../js/mzta-utils.js"; @@ -141,7 +144,7 @@ document.addEventListener('DOMContentLoaded', async () => { spamfilter_textarea.value = spamfilter_prompt.text; spamfilter_reset_btn.disabled = (spamfilter_textarea.value === browser.i18n.getMessage('prompt_spamfilter_full_text')); - autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(p => ({command: '{%'+p.id+'%}', type: p.type})); + autocompleteSuggestions = (await getPlaceholders(true)).filter(p => !(p.id === 'additional_text')).map(mapPlaceholderToSuggestion); textareaAutocomplete(spamfilter_textarea, autocompleteSuggestions, 1); // type_value = 1, only when reading an email //Accounts manager From c9b0e394339d6f1237edbcc130b080a4c891e5cf Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 22:56:36 +0100 Subject: [PATCH 028/146] property name fixed. see #553 --- js/mzta-placeholders.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 6c276fad..27eeb858 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -340,9 +340,11 @@ export async function prepareCustomDataPHsForImport(placeholders){ } export function mapPlaceholderToSuggestion(p) { + // console.log(">>>>>>>>>> mapPlaceholderToSuggestion p" + JSON.stringify(p)); return { - command: '{%' + p.id + '%}', - type: p.type + command: '{%' + p.id + (p.is_dynamic == 1 ? ':' : '') + '%}', + type: p.type, + is_dynamic: p.is_dynamic, }; } From de7a2ca83181ef853ffd807a76a1407e8d28e017 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 23:03:23 +0100 Subject: [PATCH 029/146] correctly handling dynamic palceholders when autocompleting. see #553 --- js/mzta-placeholders-autocomplete.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/mzta-placeholders-autocomplete.js b/js/mzta-placeholders-autocomplete.js index 3bf1463b..d4f03f3d 100644 --- a/js/mzta-placeholders-autocomplete.js +++ b/js/mzta-placeholders-autocomplete.js @@ -34,7 +34,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) { type = tr.querySelector('.type_output').value } // console.log(">>>>>>>>> type: " + type); - // console.log(">>>>>>>>> suggestions: " + JSON.stringify(suggestions)); + // console.log(">>>>>>>>> suggestions: " + JSON.stringify(suggestions)); // console.log(">>>>>>>>> lastWord: " + lastWord); const matches = suggestions.filter(s => s.command.startsWith(lastWord) && (String(s.type) == String(type) || String(s.type) == '0' )).map(s => s.command); // console.log(">>>>>>>>> matches: " + JSON.stringify(matches)); @@ -106,6 +106,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) { } function insertAutocomplete(suggestion, textarea) { + // console.log(">>>>>>>>> insertAutocomplete suggestion: " + JSON.stringify(suggestion)); const cursorPosition = textarea.selectionStart; const textBefore = textarea.value.substring(0, cursorPosition); const textAfter = textarea.value.substring(cursorPosition); @@ -115,7 +116,7 @@ export function textareaAutocomplete(textarea, suggestions, type_value = -1) { const completion = suggestion.substring(lastWord.length); const newText = textBefore + completion + textAfter; textarea.value = newText; - const newCursorPosition = cursorPosition + completion.length; + const newCursorPosition = cursorPosition + completion.length - (suggestion.endsWith(':%}') ? 2 : 0); textarea.setSelectionRange(newCursorPosition, newCursorPosition); } } From 3c089fc04e7617562271541babc762def52f5d95 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 23:16:56 +0100 Subject: [PATCH 030/146] temperature added to the google gemini class. see #572 --- js/api/google_gemini.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/js/api/google_gemini.js b/js/api/google_gemini.js index f2e2eb67..aae8ab09 100644 --- a/js/api/google_gemini.js +++ b/js/api/google_gemini.js @@ -25,6 +25,7 @@ export class GoogleGemini { system_instruction = ''; stream = false; thinking_budget = ''; // Model default + temperature = ''; // no temperature defined constructor({ apiKey = '', @@ -32,12 +33,14 @@ export class GoogleGemini { system_instruction = '', stream = false, thinking_budget = '', + temperature = '', } = {}) { this.apiKey = apiKey; this.model = model; this.system_instruction = system_instruction; this.stream = stream; this.thinking_budget = String(thinking_budget ?? '').trim(); + this.temperature = String(temperature ?? '').trim(); /* Info from: https://ai.google.dev/gemini-api/docs/thinking?#set-budget # Turn on thinking with a specific token limit: "thinking_budget": 1024 # Thinking off: "thinking_budget": 0 @@ -87,7 +90,8 @@ export class GoogleGemini { try { let google_gemini_body = { - contents:messages + contents: messages, + generationConfig: {}, }; // console.log("[ThunderAI] Google Gemini API system_instruction: " + JSON.stringify(this.system_instruction)); @@ -101,13 +105,15 @@ export class GoogleGemini { } if(this.thinking_budget !== '') { - google_gemini_body.generationConfig = { - thinkingConfig: { + google_gemini_body.generationConfig.thinkingConfig = { thinking_budget: this.thinking_budget, - } }; } + if(this.temperature !== ''){ + google_gemini_body.generationConfig.temperature = this.temperature; + } + // 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, { From f95fbeb00eaf7484058a09a810044474ea3690bd Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 26 Dec 2025 23:35:42 +0100 Subject: [PATCH 031/146] temperature added to Google Gemini. see #572 --- _locales/en/messages.json | 8 ++++++++ api_webchat/controller.js | 8 +++++++- options/mzta-options-default.js | 1 + pages/_lib/connection-ui.js | 13 +++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index a2d5a902..40553e1a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1685,6 +1685,14 @@ "message": "Define the number of tokens to be used for thinking. Leave this field blank if the selected model does not support thinking or if you want to use the default method. Enter 0 to disable thinking, or -1 to enable dynamic thinking.", "description": "" }, + "prefs_google_gemini_temperature": { + "message": "Temperature", + "description": "" + }, + "prefs_google_gemini_temperature_Info": { + "message": "This parameter must be a number between 0.0 and 2.0. It controls the randomness of the output. The default value varies depending on the model. Leave it empty to avoid setting the parameter in the API call.", + "description": "" + }, "SelectAll": { "message": "Select All", "description": "" diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 5f29526a..04ef964c 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -119,6 +119,7 @@ switch (llm) { google_gemini_api_key: prefs_default.google_gemini_api_key, google_gemini_model: prefs_default.google_gemini_model, google_gemini_system_instruction: prefs_default.google_gemini_system_instruction, + google_gemini_temperature: prefs_default.google_gemini_temperature, google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget, do_debug: prefs_default.do_debug, }); @@ -131,7 +132,12 @@ switch (llm) { if(prefs_api.google_gemini_system_instruction && prefs_api.google_gemini_system_instruction.length > 0) { additional_text_elements.push({label: browser.i18n.getMessage("GoogleGemini_SystemInstruction"), value: prefs_api.google_gemini_system_instruction}); } - additional_text_elements.push({label: 'Thinking Budget', value: prefs_api.google_gemini_thinking_budget}); + if(prefs_api.google_gemini_temperature.length > 0){ + additional_text_elements.push({label: browser.i18n.getMessage("prefs_google_gemini_temperature"), value: prefs_api.google_gemini_temperature}); + } + if(prefs_api.google_gemini_thinking_budget.length > 0){ + additional_text_elements.push({label: browser.i18n.getMessage("prefs_google_gemini_thinking_budget"), value: prefs_api.google_gemini_thinking_budget}); + } additional_text_elements.push({label: "Prompt", value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); worker.postMessage({ type: 'init', diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 6405c1a0..a10a5fea 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -46,6 +46,7 @@ export const prefs_default = { google_gemini_model: '', google_gemini_system_instruction: '', google_gemini_thinking_budget: '', + google_gemini_temperature: '', anthropic_api_key: '', anthropic_model: '', anthropic_version: '2023-06-01', diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 9bbcf41a..38e41ed3 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -208,6 +208,19 @@ export async function injectConnectionUI({ + + + + + + + + + + + + + + + +

    Version 3.7.8 - 18/12/2025

    diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 5b49f47c..2ecb122b 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -12,6 +12,7 @@
  • [OpenAI API] Model filtering improved when choosing a model in the options page.
  • [OpenAI API] Now using the new Responses API [#407].
  • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
  • +
  • [All APIs] The configuration information reported in the webchat API has been improved for all integrations.
  • ...

Version 3.7.8 - 18/12/2025

From dfa4da5b2ef23552b4e8d6aab8fdda006d8ab908 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 27 Dec 2025 22:40:51 +0100 Subject: [PATCH 035/146] temperature added to Open AI API. see #571 --- _locales/en/messages.json | 8 ++++++++ api_webchat/controller.js | 6 ++++++ js/api/openai_responses.js | 4 ++++ options/mzta-options-default.js | 1 + pages/_lib/connection-ui.js | 13 +++++++++++++ 5 files changed, 32 insertions(+) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 4146fce8..eb6ab97a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1577,6 +1577,14 @@ "message": "If checked, your chats will be stored by OpenAI.", "description": "" }, + "prefs_chatgpt_api_temperature": { + "message": "Temperature", + "description": "" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic.", + "description": "" + }, "prefs_ollama_think": { "message": "Enable thinking", "description": "" diff --git a/api_webchat/controller.js b/api_webchat/controller.js index e1ec8cb8..af6230bc 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -81,6 +81,7 @@ switch (llm) { chatgpt_model: prefs_default.chatgpt_model, chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, chatgpt_api_store: prefs_default.chatgpt_api_store, + chatgpt_api_temperature: prefs_default.chatgpt_api_temperature, do_debug: prefs_default.do_debug, }); let i18nStrings = {}; @@ -94,6 +95,7 @@ switch (llm) { chatgpt_model: prefs_api.chatgpt_model, chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, chatgpt_api_store: prefs_api.chatgpt_api_store, + chatgpt_api_temperature: prefs_api.chatgpt_api_temperature, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings, }); @@ -103,6 +105,9 @@ switch (llm) { if(prefs_api.chatgpt_developer_messages && prefs_api.chatgpt_developer_messages.length > 0) { additional_text_elements.push({label: browser.i18n.getMessage("ChatGPT_Developer_Messages"), value: prefs_api.chatgpt_developer_messages}); } + if(prefs_api.chatgpt_api_temperature && prefs_api.chatgpt_api_temperature.length > 0){ + additional_text_elements.push({label: browser.i18n.getMessage("prefs_chatgpt_api_temperature"), value: prefs_api.chatgpt_api_temperature}); + } messagesArea.appendUserMessage(getAPIsInitMessageString({ api_string: "ChatGPT API", model_string: prefs_api.chatgpt_model, @@ -145,6 +150,7 @@ switch (llm) { google_gemini_model: prefs_api.google_gemini_model, google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, google_gemini_thinking_budget: prefs_api.google_gemini_thinking_budget, + google_gemini_temperature: prefs_api.google_gemini_temperature, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings, }); diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js index 30202a79..1889980c 100644 --- a/js/api/openai_responses.js +++ b/js/api/openai_responses.js @@ -24,6 +24,7 @@ export class OpenAI { apiKey = ''; model = ''; developer_messages = ''; + temperature = ''; stream = false; store = false; @@ -31,12 +32,14 @@ export class OpenAI { apiKey = '', model = '', developer_messages = '', + temperature = '', stream = false, store = false } = {}) { this.apiKey = apiKey; this.model = model; this.developer_messages = developer_messages; + this.temperature = temperature; this.stream = stream; this.store = store; } @@ -90,6 +93,7 @@ export class OpenAI { input: input, stream: this.stream, store: this.store, + ...(this.temperature != '' ? { 'temperature': this.temperature } : {}), ...(maxTokens > 0 ? { 'max_output_tokens': parseInt(maxTokens) } : {}), ...(previous_response_id && this.store ? { 'previous_response_id': previous_response_id } : {}) } diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index a2dddb95..c0b771f2 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -33,6 +33,7 @@ export const prefs_default = { chatgpt_api_store: false, chatgpt_model: '', chatgpt_developer_messages: '', + chatgpt_api_temperature: '', ollama_host: '', ollama_model: '', ollama_num_ctx: 0, diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index de13219d..25367f5b 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -156,6 +156,19 @@ export async function injectConnectionUI({ + + + + + + + + + + + + + + + + + + + + + + + + @@ -313,7 +313,7 @@ export async function injectConnectionUI({ @@ -324,7 +324,7 @@ export async function injectConnectionUI({ @@ -347,7 +347,7 @@ export async function injectConnectionUI({ @@ -366,7 +366,7 @@ export async function injectConnectionUI({ @@ -379,7 +379,7 @@ export async function injectConnectionUI({
@@ -406,7 +406,7 @@ export async function injectConnectionUI({ @@ -431,7 +431,7 @@ export async function injectConnectionUI({
@@ -471,7 +471,7 @@ export async function injectConnectionUI({ @@ -484,7 +484,7 @@ export async function injectConnectionUI({ @@ -493,7 +493,7 @@ export async function injectConnectionUI({ __MSG_prefs_OptionText_anthropic_max_tokens__ @@ -514,6 +514,8 @@ export async function injectConnectionUI({ } }); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + // Bindings // const bindClick = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('click', cb); }; // const bindChange = (id, cb) => { const el = document.getElementById(id); if (el && typeof cb === 'function') el.addEventListener('change', cb); }; @@ -536,15 +538,15 @@ export async function injectConnectionUI({ conntype_select.addEventListener("change", (ev) => warn_Anthropic_VersionEmpty(modelId_prefix)); document.getElementById("chatgpt_web_project").addEventListener("input", validateCustomData_ChatGPTWeb); document.getElementById("chatgpt_web_custom_gpt").addEventListener("input", validateCustomData_ChatGPTWeb); - document.getElementById("chatgpt_api_key").addEventListener("change", (ev) => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); - document.getElementById("ollama_host").addEventListener("change", (ev) => warn_Ollama_HostEmpty(modelId_prefix)); - document.getElementById("openai_comp_host").addEventListener("change", (ev) => warn_OpenAIComp_HostEmpty(modelId_prefix)); - document.getElementById("google_gemini_api_key").addEventListener("change", (ev) => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); - document.getElementById("anthropic_api_key").addEventListener("change", (ev) => warn_Anthropic_APIKeyEmpty(modelId_prefix)); - document.getElementById("anthropic_version").addEventListener("change", (ev) => warn_Anthropic_VersionEmpty(modelId_prefix)); - document.getElementById("openai_comp_host").addEventListener("input", resetOpenAICompConfigs); - document.getElementById("openai_comp_chat_name").addEventListener("input", resetOpenAICompConfigs); - document.getElementById("openai_comp_use_v1").addEventListener("input", resetOpenAICompConfigs); + document.getElementById(getPrefixedId("chatgpt_api_key")).addEventListener("change", (ev) => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("ollama_host")).addEventListener("change", (ev) => warn_Ollama_HostEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("openai_comp_host")).addEventListener("change", (ev) => warn_OpenAIComp_HostEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("google_gemini_api_key")).addEventListener("change", (ev) => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("anthropic_api_key")).addEventListener("change", (ev) => warn_Anthropic_APIKeyEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("anthropic_version")).addEventListener("change", (ev) => warn_Anthropic_VersionEmpty(modelId_prefix)); + document.getElementById(getPrefixedId("openai_comp_host")).addEventListener("input", () => resetOpenAICompConfigs(modelId_prefix)); + document.getElementById(getPrefixedId("openai_comp_chat_name")).addEventListener("input", () => resetOpenAICompConfigs(modelId_prefix)); + document.getElementById(getPrefixedId("openai_comp_use_v1")).addEventListener("input", () => resetOpenAICompConfigs(modelId_prefix)); showConnectionOptions(conntype_select); loadOpenAICompConfigs(); @@ -555,7 +557,7 @@ export async function injectConnectionUI({ warn_Anthropic_APIKeyEmpty(modelId_prefix); warn_Anthropic_VersionEmpty(modelId_prefix); - const passwordField_chatgpt_api_key = document.getElementById('chatgpt_api_key'); + const passwordField_chatgpt_api_key = document.getElementById(getPrefixedId('chatgpt_api_key')); const toggleIcon_chatgpt_api_key = document.getElementById('toggle_chatgpt_api_key'); const icon_img_chatgpt_api_key = document.getElementById('pwd-icon_chatgpt_api_key'); @@ -566,7 +568,7 @@ export async function injectConnectionUI({ icon_img_chatgpt_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; }); - const passwordField_google_gemini_api_key = document.getElementById('google_gemini_api_key'); + const passwordField_google_gemini_api_key = document.getElementById(getPrefixedId('google_gemini_api_key')); const toggleIcon_google_gemini_api_key = document.getElementById('toggle_google_gemini_api_key'); const icon_img_google_gemini_api_key = document.getElementById('pwd-icon_google_gemini_api_key'); @@ -577,7 +579,7 @@ export async function injectConnectionUI({ icon_img_google_gemini_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; }); - const passwordField_openai_comp_api_key = document.getElementById('openai_comp_api_key'); + const passwordField_openai_comp_api_key = document.getElementById(getPrefixedId('openai_comp_api_key')); const toggleIcon_openai_comp_api_key = document.getElementById('toggle_openai_comp_api_key'); const icon_img_openai_comp_api_key = document.getElementById('pwd-icon_openai_comp_api_key'); @@ -588,7 +590,7 @@ export async function injectConnectionUI({ icon_img_openai_comp_api_key.src = type === 'password' ? "/images/pwd-show.png" : "/images/pwd-hide.png"; }); - const passwordField_anthropic_api_key = document.getElementById('anthropic_api_key'); + const passwordField_anthropic_api_key = document.getElementById(getPrefixedId('anthropic_api_key')); const toggleIcon_anthropic_api_key = document.getElementById('toggle_anthropic_api_key'); const icon_img_anthropic_api_key = document.getElementById('pwd-icon_anthropic_api_key'); @@ -632,20 +634,20 @@ export async function injectConnectionUI({ if (!confirm(browser.i18n.getMessage('OpenAIComp_Configs_ConfirmApply', config.name))) { return; } - document.getElementById('openai_comp_host').value = config.host || ''; + document.getElementById(getPrefixedId('openai_comp_host')).value = config.host || ''; // Clear all options from the select except the first (placeholder) one const openaiCompModelSelect = getModelEl('openai_comp_model', modelId_prefix); openaiCompModelSelect.value = ''; while (openaiCompModelSelect.options.length > 0) { openaiCompModelSelect.remove(0); } - document.getElementById('openai_comp_use_v1').checked = !!config.use_v1; - document.getElementById('openai_comp_chat_name').value = config.chat_name || ''; + document.getElementById(getPrefixedId('openai_comp_use_v1')).checked = !!config.use_v1; + document.getElementById(getPrefixedId('openai_comp_chat_name')).value = config.chat_name || ''; // Trigger change events if needed - document.getElementById('openai_comp_host').dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById(getPrefixedId('openai_comp_host')).dispatchEvent(new Event('change', { bubbles: true })); getModelEl('openai_comp_model', modelId_prefix).dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_use_v1').dispatchEvent(new Event('change', { bubbles: true })); - document.getElementById('openai_comp_chat_name').dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById(getPrefixedId('openai_comp_use_v1')).dispatchEvent(new Event('change', { bubbles: true })); + document.getElementById(getPrefixedId('openai_comp_chat_name')).dispatchEvent(new Event('change', { bubbles: true })); } }); @@ -662,7 +664,7 @@ export async function injectConnectionUI({ document.getElementById('btnUpdateChatGPTModels').addEventListener('click', async () => { document.getElementById('chatgpt_model_fetch_loading').style.display = 'inline'; let openai = new OpenAI({ - apiKey: document.getElementById("chatgpt_api_key").value, + apiKey: document.getElementById(getPrefixedId("chatgpt_api_key")).value, }); let granted = await messenger.permissions.request({ origins: ["https://*.openai.com/*"] }); if(!granted){ @@ -711,7 +713,7 @@ export async function injectConnectionUI({ document.getElementById('btnUpdateGoogleGeminiModels').addEventListener('click', async () => { document.getElementById('google_gemini_model_fetch_loading').style.display = 'inline'; let google_gemini = new GoogleGemini({ - apiKey: document.getElementById("google_gemini_api_key").value, + apiKey: document.getElementById(getPrefixedId("google_gemini_api_key")).value, }); google_gemini.fetchModels().then((data) => { if(!data.ok){ @@ -753,7 +755,7 @@ export async function injectConnectionUI({ document.getElementById('btnUpdateOllamaModels').addEventListener('click', async () => { document.getElementById('ollama_model_fetch_loading').style.display = 'inline'; let ollama = new Ollama({ - host: document.getElementById("ollama_host").value, + host: document.getElementById(getPrefixedId("ollama_host")).value, }); try { let data = await ollama.fetchModels(); @@ -812,9 +814,9 @@ export async function injectConnectionUI({ document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => { document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline'; let openai_comp = new OpenAIComp({ - host: document.getElementById("openai_comp_host").value, - apiKey: document.getElementById("openai_comp_api_key").value, - use_v1: document.getElementById("openai_comp_use_v1").checked, + host: document.getElementById(getPrefixedId("openai_comp_host")).value, + apiKey: document.getElementById(getPrefixedId("openai_comp_api_key")).value, + use_v1: document.getElementById(getPrefixedId("openai_comp_use_v1")).checked, }); openai_comp.fetchModels().then((data) => { if(!data.ok){ @@ -857,8 +859,8 @@ export async function injectConnectionUI({ document.getElementById('btnUpdateAnthropicModels').addEventListener('click', async () => { document.getElementById('anthropic_model_fetch_loading').style.display = 'inline'; let anthropic = new Anthropic({ - apiKey: document.getElementById("anthropic_api_key").value, - version: document.getElementById("anthropic_version").value, + apiKey: document.getElementById(getPrefixedId("anthropic_api_key")).value, + version: document.getElementById(getPrefixedId("anthropic_version")).value, }); let granted = await messenger.permissions.request({ origins: ["https://*.anthropic.com/*"] }); if(!granted){ @@ -1164,7 +1166,8 @@ function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { } function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { - let apiKeyInput = document.getElementById('chatgpt_api_key'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let apiKeyInput = document.getElementById(getPrefixedId('chatgpt_api_key')); let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); let modelChatGPT = getModelEl('chatgpt_model', modelId_prefix); if(apiKeyInput.value === ''){ @@ -1186,7 +1189,8 @@ function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { } function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) { - let apiKeyInput = document.getElementById('google_gemini_api_key'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let apiKeyInput = document.getElementById(getPrefixedId('google_gemini_api_key')); let btnFetchGoogleGeminiModels = document.getElementById('btnUpdateGoogleGeminiModels'); let modelGoogleGemini = getModelEl('google_gemini_model', modelId_prefix); if(apiKeyInput.value === ''){ @@ -1208,7 +1212,8 @@ function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) { } function warn_Ollama_HostEmpty(modelId_prefix) { - let hostInput = document.getElementById('ollama_host'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let hostInput = document.getElementById(getPrefixedId('ollama_host')); let btnFetchOllamaModels = document.getElementById('btnUpdateOllamaModels'); let modelOllama = getModelEl('ollama_model', modelId_prefix); if(hostInput.value === ''){ @@ -1230,7 +1235,8 @@ function warn_Ollama_HostEmpty(modelId_prefix) { } function warn_OpenAIComp_HostEmpty(modelId_prefix) { - let hostInput = document.getElementById('openai_comp_host'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let hostInput = document.getElementById(getPrefixedId('openai_comp_host')); let btnUpdateOpenAICompModels = document.getElementById('btnUpdateOpenAICompModels'); let modelOpenAIComp = getModelEl('openai_comp_model', modelId_prefix); if(hostInput.value === ''){ @@ -1252,7 +1258,8 @@ function warn_OpenAIComp_HostEmpty(modelId_prefix) { } function warn_Anthropic_APIKeyEmpty(modelId_prefix) { - let apiKeyInput = document.getElementById('anthropic_api_key'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let apiKeyInput = document.getElementById(getPrefixedId('anthropic_api_key')); let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(apiKeyInput.value === ''){ @@ -1274,7 +1281,8 @@ function warn_Anthropic_APIKeyEmpty(modelId_prefix) { } function warn_Anthropic_VersionEmpty(modelId_prefix) { - let versionInput = document.getElementById('anthropic_version'); + const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; + let versionInput = document.getElementById(getPrefixedId('anthropic_version')); let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(versionInput.value === ''){ From a7d42530fc67cae4886f1d8989ba8bc90cfe8b49 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 21:31:31 +0100 Subject: [PATCH 055/146] improved isAPIKeyValue method --- js/mzta-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 16a639f3..49abe49f 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -623,7 +623,7 @@ export function extractJsonObject(inputString) { } export function isAPIKeyValue(id){ - return id=="chatgpt_api_key" || id=="openai_comp_api_key" || id=="google_gemini_api_key" || id=="anthropic_api_key"; + return id.endsWith('_api_key'); } export function getConnectionType(prefsOrType, prompt, prefixOrSpecific = null) { From 2dcb661368049d8f2017cd8fd618863af9e7a62b Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 21:39:40 +0100 Subject: [PATCH 056/146] add_tags updating settings values from the special prompt --- pages/addtags/mzta-add-tags.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index e472370b..17c3dffa 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { prefs_default } from '../../options/mzta-options-default.js'; +import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; import { taLogger } from '../../js/mzta-logger.js'; import { getSpecialPrompts, @@ -44,6 +44,25 @@ let autocompleteSuggestions = []; let taLog = new taLogger("mzta-addtags-page",true); document.addEventListener('DOMContentLoaded', async () => { + + let specialPrompts = await getSpecialPrompts(); + let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); + + if (addtags_prompt && addtags_prompt.api && addtags_prompt.api !== '') { + let update_prefs = {}; + update_prefs['add_tags_connection_type'] = addtags_prompt.api; + + let integration = addtags_prompt.api.replace('_api', ''); + if (integration_options_config && integration_options_config[integration]) { + for (const key of Object.keys(integration_options_config[integration])) { + if (addtags_prompt[key] !== undefined) { + update_prefs[`add_tags_${integration}_${key}`] = addtags_prompt[key]; + } + } + } + await browser.storage.sync.set(update_prefs); + } + await initializeSpecificIntegrationUI({ prefix: 'add_tags', promptId: 'prompt_add_tags', @@ -62,9 +81,6 @@ document.addEventListener('DOMContentLoaded', async () => { let addtags_save_btn = document.getElementById('btn_save_prompt'); let addtags_reset_btn = document.getElementById('btn_reset_prompt'); - let specialPrompts = await getSpecialPrompts(); - let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); - addtags_textarea.addEventListener('input', (event) => { addtags_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_add_tags_full_text')); addtags_save_btn.disabled = (event.target.value === addtags_prompt.text); From 3816d89bd0d6f0b65b7318d55db2415d1974bf81 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 21:41:31 +0100 Subject: [PATCH 057/146] dynamically saving special prompts api settings --- pages/_lib/connection-ui.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index fb4735d7..af598c8c 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { prefs_default } from '../../options/mzta-options-default.js'; +import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; import { OpenAI } from '../../js/api/openai_responses.js'; import { Ollama } from '../../js/api/ollama.js'; import { OpenAIComp } from '../../js/api/openai_comp.js' @@ -985,15 +985,22 @@ export async function initializeSpecificIntegrationUI({ // Helper to update prompt const _updatePrompt = async () => { let conntype = conntype_el.value; - let model_value = conntype.substring(0, conntype.length - 4) + '_model'; - let temperature_value = conntype.substring(0, conntype.length - 4) + '_temperature'; + let integration = conntype.replace('_api', ''); let prompt = await loadPrompt(promptId); if(!prompt) return; prompt.api = conntype; - prompt.model = document.getElementById(model_prefix + model_value)?.value || ''; - prompt.temperature = document.getElementById(model_prefix + temperature_value)?.value || ''; + + if (integration_options_config[integration]) { + for (const key of Object.keys(integration_options_config[integration])) { + let elementId = `${model_prefix}${integration}_${key}`; + let element = document.getElementById(elementId); + if (element) { + prompt[key] = (element.type === 'checkbox') ? element.checked : element.value; + } + } + } await savePrompt(prompt); }; @@ -1031,7 +1038,7 @@ export async function initializeSpecificIntegrationUI({ if (use_specific_integration_el.checked) await _updatePrompt(); }); - document.querySelectorAll(".option-input-specific").forEach(element => { + document.querySelectorAll(".specific_integration_sub .option-input").forEach(element => { element.addEventListener("change", async () => { if (use_specific_integration_el.checked) await _updatePrompt(); }); From a436bd16b211c605714a1c5dad481b240a81b928 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 21:58:09 +0100 Subject: [PATCH 058/146] chatgpt_api var names fixed --- options/mzta-options-default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index 968214b5..b297f225 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -23,8 +23,8 @@ export const integration_options_config = { api_key: '', model: '', developer_messages: '', - api_temperature: '', - api_store: false + temperature: '', + store: false }, ollama: { host: '', From 5893ee668c1e52ec8c5e6a44f2102f08befeb7e2 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:02:33 +0100 Subject: [PATCH 059/146] fixed chatgpt_store and chatgpt_temperature var names --- api_webchat/controller.js | 14 +++++++------- pages/_lib/connection-ui.js | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 01737a91..5728f051 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -80,8 +80,8 @@ switch (llm) { chatgpt_api_key: prefs_default.chatgpt_api_key, chatgpt_model: prefs_default.chatgpt_model, chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, - chatgpt_api_store: prefs_default.chatgpt_api_store, // Keep as boolean - chatgpt_api_temperature: prefs_default.chatgpt_api_temperature, + chatgpt_store: prefs_default.chatgpt_store, // Keep as boolean + chatgpt_temperature: prefs_default.chatgpt_temperature, do_debug: prefs_default.do_debug, }); let i18nStrings = {}; @@ -94,19 +94,19 @@ switch (llm) { chatgpt_api_key: prefs_api.chatgpt_api_key, chatgpt_model: prefs_api.chatgpt_model, chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, - chatgpt_api_store: prefs_api.chatgpt_api_store, - chatgpt_api_temperature: prefs_api.chatgpt_api_temperature, + chatgpt_store: prefs_api.chatgpt_store, + chatgpt_temperature: prefs_api.chatgpt_temperature, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings, }); let additional_text_elements = []; additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - additional_text_elements.push({label: 'OpenAI Store', value: (prefs_api.chatgpt_api_store ? 'Yes' : 'No')}); + additional_text_elements.push({label: 'OpenAI Store', value: (prefs_api.chatgpt_store ? 'Yes' : 'No')}); if(prefs_api.chatgpt_developer_messages && prefs_api.chatgpt_developer_messages.length > 0) { additional_text_elements.push({label: browser.i18n.getMessage("ChatGPT_Developer_Messages"), value: prefs_api.chatgpt_developer_messages}); } - if(prefs_api.chatgpt_api_temperature && prefs_api.chatgpt_api_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.chatgpt_api_temperature}); + if(prefs_api.chatgpt_temperature && prefs_api.chatgpt_temperature.length > 0){ + additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.chatgpt_temperature}); } messagesArea.appendUserMessage(getAPIsInitMessageString({ api_string: "ChatGPT API", diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index af598c8c..7a68d921 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -165,7 +165,7 @@ export async function injectConnectionUI({ @@ -178,7 +178,7 @@ export async function injectConnectionUI({ From f47b12946a676cd91aef932207dba1752b32ee65 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:03:45 +0100 Subject: [PATCH 060/146] workers updated to use the new dynamic settings --- js/workers/model-worker-anthropic.js | 18 +++++++++--------- js/workers/model-worker-google_gemini.js | 17 +++++++++-------- js/workers/model-worker-ollama.js | 16 ++++++++-------- js/workers/model-worker-openai_comp.js | 17 +++++++++-------- js/workers/model-worker-openai_responses.js | 18 ++++++++++-------- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/js/workers/model-worker-anthropic.js b/js/workers/model-worker-anthropic.js index ead40aff..9af3dc17 100644 --- a/js/workers/model-worker-anthropic.js +++ b/js/workers/model-worker-anthropic.js @@ -35,15 +35,15 @@ let assistantResponseAccumulator = ''; self.onmessage = async function(event) { if (event.data.type === 'init') { // console.log(">>>>>>>>>>>>>> event.data: " + JSON.stringify(event.data)); - anthropic = new Anthropic({ - apiKey: event.data.anthropic_api_key, - version: event.data.anthropic_version, - model: event.data.anthropic_model, - system_prompt: event.data.anthropic_system_prompt, - temperature: event.data.anthropic_temperature, - max_tokens: event.data.anthropic_max_tokens, - stream: true - }); + let config = { stream: true }; + for (const key in event.data) { + if (key.startsWith('anthropic_')) { + let newKey = key.replace('anthropic_', ''); + if (newKey === 'api_key') newKey = 'apiKey'; + config[newKey] = event.data[key]; + } + } + anthropic = new Anthropic(config); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-anthropic', do_debug); diff --git a/js/workers/model-worker-google_gemini.js b/js/workers/model-worker-google_gemini.js index 359e0b20..4b6fc138 100644 --- a/js/workers/model-worker-google_gemini.js +++ b/js/workers/model-worker-google_gemini.js @@ -34,14 +34,15 @@ let assistantResponseAccumulator = ''; self.onmessage = async function(event) { if (event.data.type === 'init') { - google_gemini = new GoogleGemini({ - apiKey: event.data.google_gemini_api_key, - model: event.data.google_gemini_model, - system_instruction: event.data.google_gemini_system_instruction, - temperature: event.data.google_gemini_temperature, - thinking_budget: event.data.google_gemini_thinking_budget, - stream: true - }); + let config = { stream: true }; + for (const key in event.data) { + if (key.startsWith('google_gemini_')) { + let newKey = key.replace('google_gemini_', ''); + if (newKey === 'api_key') newKey = 'apiKey'; + config[newKey] = event.data[key]; + } + } + google_gemini = new GoogleGemini(config); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-google_gemini', do_debug); diff --git a/js/workers/model-worker-ollama.js b/js/workers/model-worker-ollama.js index a3374eba..3987df33 100644 --- a/js/workers/model-worker-ollama.js +++ b/js/workers/model-worker-ollama.js @@ -35,14 +35,14 @@ let assistantResponseAccumulator = ''; self.onmessage = async function(event) { switch (event.data.type) { case 'init': - ollama = new Ollama({ - host: event.data.ollama_host, - model: event.data.ollama_model, - stream: true, - num_ctx: event.data.ollama_num_ctx, - temperature: event.data.ollama_temperature, - think: event.data.ollama_think - }); + let config = { stream: true }; + for (const key in event.data) { + if (key.startsWith('ollama_')) { + let newKey = key.replace('ollama_', ''); + config[newKey] = event.data[key]; + } + } + ollama = new Ollama(config); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-ollama', do_debug); diff --git a/js/workers/model-worker-openai_comp.js b/js/workers/model-worker-openai_comp.js index 1e7b8aea..a541ffa8 100644 --- a/js/workers/model-worker-openai_comp.js +++ b/js/workers/model-worker-openai_comp.js @@ -34,14 +34,15 @@ let assistantResponseAccumulator = ''; self.onmessage = async function(event) { if (event.data.type === 'init') { - openai_comp = new OpenAIComp({ - host: event.data.openai_comp_host, - model: event.data.openai_comp_model, - apiKey: event.data.openai_comp_api_key, - stream: true, - use_v1: event.data.openai_comp_use_v1, - openai_comp_temperature: event.data.openai_comp_temperature - }); + let config = { stream: true }; + for (const key in event.data) { + if (key.startsWith('openai_comp_')) { + let newKey = key.replace('openai_comp_', ''); + if (newKey === 'api_key') newKey = 'apiKey'; + config[newKey] = event.data[key]; + } + } + openai_comp = new OpenAIComp(config); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-openai_comp', do_debug); diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js index 3189944d..89803673 100644 --- a/js/workers/model-worker-openai_responses.js +++ b/js/workers/model-worker-openai_responses.js @@ -35,14 +35,16 @@ let previous_response_id = null; self.onmessage = async function(event) { if (event.data.type === 'init') { - openai = new OpenAI({ - apiKey: event.data.chatgpt_api_key, - model: event.data.chatgpt_model, - developer_messages: event.data.chatgpt_developer_messages, - temperature: event.data.chatgpt_api_temperature, - stream: true, - store: event.data.chatgpt_api_store - }); + let config = { stream: true }; + for (const key in event.data) { + if (key.startsWith('chatgpt_')) { + if (key.startsWith('chatgpt_web_')) continue; // Exclude chatgpt_web_ prefixed keys + let newKey = key.replace('chatgpt_', ''); + if (newKey === 'api_key') newKey = 'apiKey'; + config[newKey] = event.data[key]; + } + } + openai = new OpenAI(config); do_debug = event.data.do_debug; i18nStrings = event.data.i18nStrings; taLog = new taLogger('model-worker-openai_responses', do_debug); From 285ee3a79edfcad7be99af2eb8c488bcbe4aa965 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:22:45 +0100 Subject: [PATCH 061/146] the controller.js is now dynamic --- api_webchat/controller.js | 375 ++++++++++++++------------------------ 1 file changed, 138 insertions(+), 237 deletions(-) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 5728f051..050471d2 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -20,7 +20,7 @@ * The original code has been released under the Apache License, Version 2.0. */ -import { prefs_default } from '../options/mzta-options-default.js'; +import { prefs_default, integration_options_config } from '../options/mzta-options-default.js'; import { placeholdersUtils } from '../js/mzta-placeholders.js'; import { getAPIsInitMessageString, convertNewlinesToBr } from '../js/mzta-utils.js'; @@ -46,260 +46,161 @@ const messagesArea = document.querySelector('messages-area'); // The controller wires up all the components and workers together, // managing the dependencies. A kind of "DI" class. let worker = null; +const integration = llm.replace('_api', ''); +const worker_path_map = { + chatgpt: '../js/workers/model-worker-openai_responses.js', + google_gemini: '../js/workers/model-worker-google_gemini.js', + ollama: '../js/workers/model-worker-ollama.js', + openai_comp: '../js/workers/model-worker-openai_comp.js', + anthropic: '../js/workers/model-worker-anthropic.js', +}; -switch (llm) { - case "chatgpt_api": - worker = new Worker('../js/workers/model-worker-openai_responses.js', { type: 'module' }); - break; - case "google_gemini_api": - worker = new Worker('../js/workers/model-worker-google_gemini.js', { type: 'module' }); - break; - case "ollama_api": - worker = new Worker('../js/workers/model-worker-ollama.js', { type: 'module' }); - break; - case "openai_comp_api": - worker = new Worker('../js/workers/model-worker-openai_comp.js', { type: 'module' }); - break; - case "anthropic_api": - worker = new Worker('../js/workers/model-worker-anthropic.js', { type: 'module' }); - break; - default: - console.error('[ThunderAI] API WebChat Unknown LLM type:', llm); - break; +const worker_path = worker_path_map[integration]; + +if (worker_path) { + worker = new Worker(worker_path, { type: 'module' }); +} else { + console.error('[ThunderAI] API WebChat Unknown LLM type:', llm); } -messagesArea.init(worker); +if (worker) { + messagesArea.init(worker); + messageInput.init(worker); + messageInput.setMessagesArea(messagesArea); -// Initialize the messageInput component and pass the worker to it -messageInput.init(worker); -messageInput.setMessagesArea(messagesArea); + if (integration_options_config[integration]) { + const integration_prefix = integration; + const options_config = integration_options_config[integration]; + + let prefsToGet = { do_debug: prefs_default.do_debug }; + for (const key in options_config) { + prefsToGet[`${integration_prefix}_${key}`] = prefs_default[`${integration_prefix}_${key}`]; + } + if (integration === 'openai_comp') { + prefsToGet.openai_comp_chat_name = prefs_default.openai_comp_chat_name; + } + + let prefs_api = await browser.storage.sync.get(prefsToGet); -switch (llm) { - case "chatgpt_api": { - let prefs_api = await browser.storage.sync.get({ - chatgpt_api_key: prefs_default.chatgpt_api_key, - chatgpt_model: prefs_default.chatgpt_model, - chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, - chatgpt_store: prefs_default.chatgpt_store, // Keep as boolean - chatgpt_temperature: prefs_default.chatgpt_temperature, - do_debug: prefs_default.do_debug, - }); let i18nStrings = {}; - i18nStrings["chatgpt_api_request_failed"] = browser.i18n.getMessage('chatgpt_api_request_failed'); + const i18n_msg_key = integration === 'openai_comp' ? 'OpenAIComp_api_request_failed' : `${integration}_api_request_failed`; + i18nStrings[i18n_msg_key] = browser.i18n.getMessage(i18n_msg_key); i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); - messageInput.setModel(prefs_api.chatgpt_model); - messagesArea.setLLMName("ChatGPT"); - worker.postMessage({ + + messageInput.setModel(prefs_api[`${integration_prefix}_model`]); + + let llmName = "API"; + switch(integration) { + case 'chatgpt': llmName = "ChatGPT"; break; + case 'google_gemini': llmName = "Google Gemini"; break; + case 'ollama': llmName = "Ollama Local"; break; + case 'openai_comp': llmName = prefs_api.openai_comp_chat_name || "OpenAI Comp"; break; + case 'anthropic': llmName = "Claude"; break; + } + messagesArea.setLLMName(llmName); + + let workerInitMessage = { type: 'init', - chatgpt_api_key: prefs_api.chatgpt_api_key, - chatgpt_model: prefs_api.chatgpt_model, - chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, - chatgpt_store: prefs_api.chatgpt_store, - chatgpt_temperature: prefs_api.chatgpt_temperature, do_debug: prefs_api.do_debug, i18nStrings: i18nStrings, - }); + }; + + for (const key in options_config) { + const prefKey = `${integration_prefix}_${key}`; + workerInitMessage[prefKey] = prefs_api[prefKey]; + } + + worker.postMessage(workerInitMessage); + + const additional_messages_config = { + chatgpt: [ + { key: 'store', labelKey: 'ChatGPT_chatgpt_api_store', type: 'boolean' }, + { key: 'developer_messages', labelKey: 'ChatGPT_Developer_Messages', type: 'string' }, + { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' } + ], + google_gemini: [ + { key: 'system_instruction', labelKey: 'GoogleGemini_SystemInstruction', type: 'string' }, + { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' }, + { key: 'thinking_budget', labelKey: 'prefs_google_gemini_thinking_budget', type: 'string' } + ], + ollama: [ + { key: 'think', labelKey: 'prefs_ollama_think', type: 'boolean' }, + { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' }, + { key: 'num_ctx', labelKey: 'prefs_ollama_num_ctx', type: 'number_gt_zero' } + ], + openai_comp: [ + { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' } + ], + anthropic: [ + { key: 'system_prompt', labelKey: 'Anthropic_System_Prompt', type: 'string' }, + { key: 'max_tokens', labelKey: 'prefs_OptionText_anthropic_max_tokens', type: 'number_gt_zero' }, + { key: 'temperature', labelKey: 'prefs_api_temperature', type: 'string' } + ] + }; + + const getAdditionalMessages = (integration, prefs) => { + const messages = []; + const config = additional_messages_config[integration]; + if (!config) return messages; + + for (const item of config) { + const prefKey = `${integration}_${item.key}`; + const value = prefs[prefKey]; + + if (value !== undefined && value !== null && value !== '') { + let displayValue; + let shouldAdd = false; + + switch (item.type) { + case 'boolean': + displayValue = value ? 'Yes' : 'No'; + shouldAdd = true; + break; + case 'string': + if (value.length > 0) { + displayValue = value; + shouldAdd = true; + } + break; + case 'number_gt_zero': + if (value > 0) { + displayValue = value; + shouldAdd = true; + } + break; + } + if (shouldAdd) { + messages.push({ label: browser.i18n.getMessage(item.labelKey), value: displayValue }); + } + } + } + return messages; + }; + let additional_text_elements = []; additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - additional_text_elements.push({label: 'OpenAI Store', value: (prefs_api.chatgpt_store ? 'Yes' : 'No')}); - if(prefs_api.chatgpt_developer_messages && prefs_api.chatgpt_developer_messages.length > 0) { - additional_text_elements.push({label: browser.i18n.getMessage("ChatGPT_Developer_Messages"), value: prefs_api.chatgpt_developer_messages}); - } - if(prefs_api.chatgpt_temperature && prefs_api.chatgpt_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.chatgpt_temperature}); - } + additional_text_elements.push(...getAdditionalMessages(integration, prefs_api)); + + const api_strings = { + chatgpt: "ChatGPT API", + google_gemini: "Google Gemini API", + ollama: "Ollama API", + openai_comp: "OpenAI Compatible API", + anthropic: "Claude API" + }; + messagesArea.appendUserMessage(getAPIsInitMessageString({ - api_string: "ChatGPT API", - model_string: prefs_api.chatgpt_model, + api_string: api_strings[integration], + model_string: prefs_api[`${integration_prefix}_model`], + host_string: prefs_api[`${integration_prefix}_host`], + version_string: prefs_api[`${integration_prefix}_version`], additional_messages: additional_text_elements }), "info"); + browser.runtime.sendMessage({ - command: "openai_api_ready_" + call_id, + command: `${llm}_ready_${call_id}`, window_id: (await browser.windows.getCurrent()).id }); - break; - } - case "google_gemini_api": { - let prefs_api = await browser.storage.sync.get({ - google_gemini_api_key: prefs_default.google_gemini_api_key, - google_gemini_model: prefs_default.google_gemini_model, - google_gemini_system_instruction: prefs_default.google_gemini_system_instruction, - google_gemini_temperature: prefs_default.google_gemini_temperature, - google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget, - do_debug: prefs_default.do_debug, - }); - let i18nStrings = {}; - i18nStrings["google_gemini_api_request_failed"] = browser.i18n.getMessage('google_gemini_api_request_failed'); - i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); - messageInput.setModel(prefs_api.google_gemini_model); - messagesArea.setLLMName("Google Gemini"); - let additional_text_elements = []; - additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - if(prefs_api.google_gemini_system_instruction && prefs_api.google_gemini_system_instruction.length > 0) { - additional_text_elements.push({label: browser.i18n.getMessage("GoogleGemini_SystemInstruction"), value: prefs_api.google_gemini_system_instruction}); - } - if(prefs_api.google_gemini_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.google_gemini_temperature}); - } - if(prefs_api.google_gemini_thinking_budget.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_google_gemini_thinking_budget"), value: prefs_api.google_gemini_thinking_budget}); - } - worker.postMessage({ - type: 'init', - google_gemini_api_key: prefs_api.google_gemini_api_key, - google_gemini_model: prefs_api.google_gemini_model, - google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, - google_gemini_thinking_budget: prefs_api.google_gemini_thinking_budget, - google_gemini_temperature: prefs_api.google_gemini_temperature, - do_debug: prefs_api.do_debug, - i18nStrings: i18nStrings, - }); - messagesArea.appendUserMessage(getAPIsInitMessageString({ - api_string: "Google Gemini API", - model_string: prefs_api.google_gemini_model, - additional_messages: additional_text_elements - }), "info"); - browser.runtime.sendMessage({ - command: "google_gemini_api_ready_" + call_id, - window_id: (await browser.windows.getCurrent()).id - }); - break; - } - case "ollama_api": { - let prefs_api = await browser.storage.sync.get({ - ollama_host: prefs_default.ollama_host, - ollama_model: prefs_default.ollama_model, - ollama_num_ctx: prefs_default.ollama_num_ctx, - ollama_temperature: prefs_default.ollama_temperature, - ollama_think: prefs_default.ollama_think, - do_debug: prefs_default.do_debug, - }); - let i18nStrings = {}; - i18nStrings["ollama_api_request_failed"] = browser.i18n.getMessage('ollama_api_request_failed'); - i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); - messageInput.setModel(prefs_api.ollama_model); - messagesArea.setLLMName("Ollama Local"); - worker.postMessage({ - type: 'init', - ollama_host: prefs_api.ollama_host, - ollama_model: prefs_api.ollama_model, - ollama_num_ctx: prefs_api.ollama_num_ctx, - ollama_temperature: prefs_api.ollama_temperature, - ollama_think: prefs_api.ollama_think, - do_debug: prefs_api.do_debug, - i18nStrings: i18nStrings - }); - browser.runtime.sendMessage({ - command: "ollama_api_ready_" + call_id, - window_id: (await browser.windows.getCurrent()).id - }); - let additional_text_elements = []; - additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - additional_text_elements.push({label: browser.i18n.getMessage("prefs_ollama_think"), value: (prefs_api.ollama_think ? 'Yes' : 'No')}); - if(prefs_api.ollama_temperature && prefs_api.ollama_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.ollama_temperature}); - } - if(prefs_api.ollama_num_ctx > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_ollama_num_ctx"), value: prefs_api.ollama_num_ctx}); - } - messagesArea.appendUserMessage(getAPIsInitMessageString({ - api_string: "Ollama API", - model_string: prefs_api.ollama_model, - host_string: prefs_api.ollama_host, - additional_messages: additional_text_elements - }), "info"); - break; - } - case "openai_comp_api": { - let prefs_api = await browser.storage.sync.get({ - openai_comp_host: prefs_default.openai_comp_host, - openai_comp_model: prefs_default.openai_comp_model, - openai_comp_api_key: prefs_default.openai_comp_api_key, - openai_comp_use_v1: prefs_default.openai_comp_use_v1, - openai_comp_chat_name: prefs_default.openai_comp_chat_name, - openai_comp_temperature: prefs_default.openai_comp_temperature, - do_debug: prefs_default.do_debug, - }); - let i18nStrings = {}; - i18nStrings["OpenAIComp_api_request_failed"] = browser.i18n.getMessage('OpenAIComp_api_request_failed'); - i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); - messageInput.setModel(prefs_api.openai_comp_model); - messagesArea.setLLMName(prefs_api.openai_comp_chat_name); - worker.postMessage({ - type: 'init', - openai_comp_host: prefs_api.openai_comp_host, - openai_comp_model: prefs_api.openai_comp_model, - openai_comp_api_key: prefs_api.openai_comp_api_key, - openai_comp_use_v1: prefs_api.openai_comp_use_v1, - openai_comp_temperature: prefs_api.openai_comp_temperature, - do_debug: prefs_api.do_debug, - i18nStrings: i18nStrings, - }); - let additional_text_elements = []; - additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - if(prefs_api.openai_comp_temperature && prefs_api.openai_comp_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.openai_comp_temperature}); - } - messagesArea.appendUserMessage(getAPIsInitMessageString({ - api_string: "OpenAI Compatible API", - model_string: prefs_api.openai_comp_model, - host_string: prefs_api.openai_comp_host, - additional_messages: additional_text_elements - }), "info"); - browser.runtime.sendMessage({ - command: "openai_comp_api_ready_" + call_id, - window_id: (await browser.windows.getCurrent()).id - }); - break; - } - case "anthropic_api": { - let prefs_api = await browser.storage.sync.get({ - anthropic_api_key: prefs_default.anthropic_api_key, - anthropic_model: prefs_default.anthropic_model, - anthropic_system_prompt: prefs_default.anthropic_system_prompt, - anthropic_temperature: prefs_default.anthropic_temperature, - anthropic_version: prefs_default.anthropic_version, - anthropic_max_tokens: prefs_default.anthropic_max_tokens, - do_debug: prefs_default.do_debug, - }); - let i18nStrings = {}; - i18nStrings["anthropic_api_request_failed"] = browser.i18n.getMessage('anthropic_api_request_failed'); - i18nStrings["error_connection_interrupted"] = browser.i18n.getMessage('error_connection_interrupted'); - messageInput.setModel(prefs_api.anthropic_model); - messagesArea.setLLMName("Claude"); - worker.postMessage({ - type: 'init', - anthropic_api_key: prefs_api.anthropic_api_key, - anthropic_model: prefs_api.anthropic_model, - anthropic_system_prompt: prefs_api.anthropic_system_prompt, - anthropic_version: prefs_api.anthropic_version, - anthropic_temperature: prefs_api.anthropic_temperature, - anthropic_max_tokens: prefs_api.anthropic_max_tokens, - do_debug: prefs_api.do_debug, - i18nStrings: i18nStrings, - }); - let additional_text_elements = []; - additional_text_elements.push({label: browser.i18n.getMessage("prompt_string"), value: '[' + prompt_id + '] ' + decodeURIComponent(prompt_name)}); - if(prefs_api.anthropic_system_prompt && prefs_api.anthropic_system_prompt.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("Anthropic_System_Prompt"), value: prefs_api.anthropic_system_prompt}); - } - if(prefs_api.anthropic_max_tokens > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_OptionText_anthropic_max_tokens"), value: prefs_api.anthropic_max_tokens}); - } - if(prefs_api.anthropic_temperature && prefs_api.anthropic_temperature.length > 0){ - additional_text_elements.push({label: browser.i18n.getMessage("prefs_api_temperature"), value: prefs_api.anthropic_temperature}); - } - messagesArea.appendUserMessage(getAPIsInitMessageString({ - api_string: "Claude API", - model_string: prefs_api.anthropic_model, - version_string: prefs_api.anthropic_version, - additional_messages: additional_text_elements - }), "info"); - browser.runtime.sendMessage({ - command: "anthropic_api_ready_" + call_id, - window_id: (await browser.windows.getCurrent()).id - }); - break; } } From 154a0a981bac92e1b7cfe4bb5a913fa38ba37e5a Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:25:15 +0100 Subject: [PATCH 062/146] option-input-specific removed --- pages/_lib/connection-ui.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 7a68d921..37c22001 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -153,7 +153,7 @@ export async function injectConnectionUI({ __MSG_Loading__
@@ -165,7 +165,7 @@ export async function injectConnectionUI({ @@ -218,7 +218,7 @@ export async function injectConnectionUI({ __MSG_Loading__
@@ -230,7 +230,7 @@ export async function injectConnectionUI({ @@ -290,7 +290,7 @@ export async function injectConnectionUI({ __MSG_Loading__
@@ -302,7 +302,7 @@ export async function injectConnectionUI({ @@ -396,7 +396,7 @@ export async function injectConnectionUI({ __MSG_Loading__
@@ -419,7 +419,7 @@ export async function injectConnectionUI({ @@ -446,7 +446,7 @@ export async function injectConnectionUI({ __MSG_Loading__
@@ -458,7 +458,7 @@ export async function injectConnectionUI({ From 168dd339a05235ced192675d457c2744238e3209 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:28:30 +0100 Subject: [PATCH 063/146] spamfilter updated to use the new dynamic settings --- pages/spamfilter/mzta-spamfilter.js | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index 0e22f435..5f3c2fe5 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { prefs_default } from '../../options/mzta-options-default.js'; +import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; import { taLogger } from '../../js/mzta-logger.js'; import { getSpecialPrompts, @@ -38,6 +38,25 @@ let taLog = new taLogger("mzta-spamfilter-page",true); taSpamReport.logger = taLog; document.addEventListener('DOMContentLoaded', async () => { + + let specialPrompts = await getSpecialPrompts(); + let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); + + if (spamfilter_prompt && spamfilter_prompt.api && spamfilter_prompt.api !== '') { + let update_prefs = {}; + update_prefs['spamfilter_connection_type'] = spamfilter_prompt.api; + + let integration = spamfilter_prompt.api.replace('_api', ''); + if (integration_options_config && integration_options_config[integration]) { + for (const key of Object.keys(integration_options_config[integration])) { + if (spamfilter_prompt[key] !== undefined) { + update_prefs[`spamfilter_${integration}_${key}`] = spamfilter_prompt[key]; + } + } + } + await browser.storage.sync.set(update_prefs); + } + await initializeSpecificIntegrationUI({ prefix: 'spamfilter', promptId: 'prompt_spamfilter', @@ -59,9 +78,6 @@ document.addEventListener('DOMContentLoaded', async () => { let spamfilter_save_btn = document.getElementById('btn_save_prompt'); let spamfilter_reset_btn = document.getElementById('btn_reset_prompt'); - let specialPrompts = await getSpecialPrompts(); - let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); - spamfilter_textarea.addEventListener('input', (event) => { spamfilter_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_spamfilter_full_text')); spamfilter_save_btn.disabled = (event.target.value === spamfilter_prompt.text); From 5bd00fd64b9bf1f11740037a39b8a84f20184922 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 22:45:30 +0100 Subject: [PATCH 064/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33795e09..a9e2cfae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@

Version 3.8.0 - ??/??/2025

    +
  • [All APIs] When using special prompts 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].
  • [OpenAI API] Model filtering improved when choosing a model in the options page.
  • [OpenAI API] Now using the new Responses API [#407].
  • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
  • diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 45ef8585..4ef9fb44 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -9,6 +9,7 @@

    ThunderAI Release Notes

    Version 3.8.0 - ??/??/2025

      +
    • [All APIs] When using special prompts 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].
    • [OpenAI API] Model filtering improved when choosing a model in the options page.
    • [OpenAI API] Now using the new Responses API [#407].
    • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
    • From 96657611b877ac538e6088617205336f0569066b Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 29 Dec 2025 23:09:47 +0100 Subject: [PATCH 065/146] text udpated --- 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 a9e2cfae..8b55e195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@

      Version 3.8.0 - ??/??/2025

        -
      • [All APIs] When using special prompts 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].
      • +
      • [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].
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • [OpenAI API] Now using the new Responses API [#407].
      • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
      • diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 4ef9fb44..de7fa017 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -9,7 +9,7 @@

        ThunderAI Release Notes

        Version 3.8.0 - ??/??/2025

          -
        • [All APIs] When using special prompts 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].
        • +
        • [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].
        • [OpenAI API] Model filtering improved when choosing a model in the options page.
        • [OpenAI API] Now using the new Responses API [#407].
        • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
        • From ffb7b8d3c199884f1c8cb5e2263dc91dd9fbdd01 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 30 Dec 2025 22:05:37 +0100 Subject: [PATCH 066/146] red border if the temperature value is not a number. see #582 --- pages/_lib/connection-ui.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 37c22001..f3e823cd 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -165,7 +165,7 @@ export async function injectConnectionUI({ @@ -230,7 +230,7 @@ export async function injectConnectionUI({ @@ -302,7 +302,7 @@ export async function injectConnectionUI({ @@ -419,7 +419,7 @@ export async function injectConnectionUI({ @@ -458,7 +458,7 @@ export async function injectConnectionUI({ @@ -933,6 +933,10 @@ export async function injectConnectionUI({ document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: [""] }); }); + + document.querySelectorAll('.check-number').forEach(input => { + input.addEventListener('input', warn_InvalidNumber); + }); warn_ChatGPT_APIKeyEmpty(modelId_prefix); warn_Ollama_HostEmpty(modelId_prefix); @@ -1172,6 +1176,17 @@ function populateConnectionTypeOptions(selectId, no_chatgpt_web = false) { } } +function warn_InvalidNumber(event){ + const elementValue = event.target.value; + // console.log(">>>>>>>>>>> warn_InvalidNumber: " + event.target.id + ": " + elementValue) + if (elementValue != '' && isNaN(parseFloat(elementValue))) { + // Handle invalid number case, e.g., set border to red + event.target.style.border = '2px solid red'; + } else { + event.target.style.border = ''; + } +} + function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let apiKeyInput = document.getElementById(getPrefixedId('chatgpt_api_key')); From 36e7c26e96217cf7cad44264c4cb3456f0c1d695 Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 30 Dec 2025 22:09:45 +0100 Subject: [PATCH 067/146] version set to 3.8.0pre3 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index d9660a70..e18ffa08 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.0pre2", + "version": "3.8.0pre3", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { From 6c79e220ac7fd2e175467b32acb7410b95ab744b Mon Sep 17 00:00:00 2001 From: mic Date: Tue, 30 Dec 2025 22:13:05 +0100 Subject: [PATCH 068/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b55e195..a7f39c44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@

          Version 3.8.0 - ??/??/2025

          • [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].
          • +
          • [All APIs] Added the temperature parameter [#561].
          • [OpenAI API] Model filtering improved when choosing a model in the options page.
          • [OpenAI API] Now using the new Responses API [#407].
          • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
          • diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index de7fa017..6107811c 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -10,6 +10,7 @@

            Version 3.8.0 - ??/??/2025

            • [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].
            • +
            • [All APIs] Added the temperature parameter [#561].
            • [OpenAI API] Model filtering improved when choosing a model in the options page.
            • [OpenAI API] Now using the new Responses API [#407].
            • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
            • From b07de999c20deab4db1ca13b9fe479f7251ae22b Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Mon, 29 Dec 2025 22:52:34 +0100 Subject: [PATCH 069/146] Added translation using Weblate (Swedish) --- _locales/sv/messages.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 _locales/sv/messages.json diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/_locales/sv/messages.json @@ -0,0 +1 @@ +{} From 0512a83bd923775f157e8c1f0580ace47d8ff9ab Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Tue, 30 Dec 2025 20:59:57 +0100 Subject: [PATCH 070/146] Translated using Weblate (Swedish) Currently translated at 5.3% (23 of 431 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 72 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 0967ef42..501458e0 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -1 +1,71 @@ -{} +{ + "extensionDescription": { + "message": "Använd ChatGPT, Google Gemini, Claude eller Ollama för att förbättra dina e-postmeddelanden!" + }, + "menu_title": { + "message": "AI" + }, + "customPrompts_btnEdit": { + "message": "Redigera" + }, + "customPrompts_btnCancel": { + "message": "Avbryt" + }, + "customPrompts_btnOK": { + "message": "Ok" + }, + "customPrompts_btnDelete": { + "message": "Ta bort" + }, + "customPrompts_btnDelete_confirmText": { + "message": "Är du säker på att du vill ta bort det här objektet?" + }, + "customPrompts_unsaved_changes": { + "message": "Det finns osparade ändringar!" + }, + "btnSaveAll_string": { + "message": "Spara alla" + }, + "chatgpt_win_close": { + "message": "Stäng" + }, + "customPrompts_add_to_menu_always": { + "message": "Alltid" + }, + "Date": { + "message": "Datum" + }, + "prompt_selection_needed": { + "message": "För att fortsätta måste du markera lite text!" + }, + "customPrompts_form_label_Name": { + "message": "Namn" + }, + "customPrompts_form_label_Action": { + "message": "Åtgärd" + }, + "customPrompts_form_label_enabled": { + "message": "Aktiverad" + }, + "btnNew_string": { + "message": "Lägg till ny" + }, + "chatgpt_btn_retry": { + "message": "Försöka igen" + }, + "placeholder_selected_html": { + "message": "Vald HTML" + }, + "placeholder_additional_text": { + "message": "Ytterligare text" + }, + "chatgpt_win_send": { + "message": "Skicka" + }, + "prefs_OptionText_chatgpt_win_height": { + "message": "Höjd" + }, + "prefs_OptionText_chatgpt_win_width": { + "message": "Bredd" + } +} From daaf5dfbe0806ac048dd8c4b4a170c609fe02171 Mon Sep 17 00:00:00 2001 From: Gerardo Sobarzo Date: Tue, 30 Dec 2025 12:44:15 +0100 Subject: [PATCH 071/146] Translated using Weblate (Spanish) Currently translated at 73.5% (317 of 431 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/es/ --- _locales/es/messages.json | 115 +++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 997a3bf7..47343e87 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -153,7 +153,7 @@ "message": "Botón de cerrar" }, "customPrompts_do_reply": { - "message": "Hacer respuesta" + "message": "Responder" }, "customPrompts_substitute_text": { "message": "Sustituir texto" @@ -162,7 +162,7 @@ "message": "Trabajo en progreso..." }, "chatgpt_win_job_completed": { - "message": "¡Completo!" + "message": "¡Completado!" }, "chatgpt_win_job_completed_select": { "message": "Selecciona el texto que deseas utilizar y haz clic en el botón." @@ -838,5 +838,116 @@ }, "prefs_OptionText_add_tags_auto_Info": { "message": "Si está marcado, la IA añadirá automáticamente etiquetas a los correos electrónicos recién recibidos." + }, + "prompt_string": { + "message": "Prompt" + }, + "prefs_OptionText_add_tags_auto_Info2": { + "message": "Elige qué cuenta activar esta función en la parte inferior de esta página." + }, + "prefs_OptionText_add_tags_auto_force_existing": { + "message": "Forzar etiquetas existentes" + }, + "prefs_OptionText_add_tags_auto_force_existing_Info": { + "message": "Si está marcado, la IA solo añadirá etiquetas existentes y no creará nuevas etiquetas." + }, + "prefs_OptionText_add_tags_auto_uselist": { + "message": "Usa solo estas etiquetas" + }, + "prefs_OptionText_add_tags_auto_uselist_Info": { + "message": "Si está marcado, la IA solo añadirá etiquetas de la lista a continuación." + }, + "prefs_OptionText_add_tags_auto_uselist_list_Info": { + "message": "La lista debe contener al menos una etiqueta. Añade una etiqueta por línea, o separada por una coma." + }, + "prompt_add_tags_use_list": { + "message": "Usa solo las etiquetas de esta lista separada por comas" + }, + "prefs_OptionText_add_tags_auto_only_inbox": { + "message": "Solo añadir etiquetas a los correos en la bandeja de entrada" + }, + "prefs_OptionText_add_tags_auto_only_inbox_Info": { + "message": "Si está marcado, la IA solo añadirá etiquetas a los correos recibidos en la carpeta de la bandeja de entrada." + }, + "prefs_OptionText_add_tags_use_specific_integration_Info": { + "message": "If checked, the AI will only add tags to emails received in the inbox folder." + }, + "placeholder_thunderai_def_sign": { + "message": "Firma predeterminada según lo definido en las opciones de ThunderAI." + }, + "thunderai_def_lang": { + "message": "Idioma predeterminado según lo definido en las opciones de ThunderAI." + }, + "placeholder_mail_attachments_info": { + "message": "Información sobre los archivos adjuntos en el correo electrónico" + }, + "empty": { + "message": "Este marcador de posición no añade texto, pero evita que el cuerpo del correo se añada automáticamente al final del prompt." + }, + "prefs_OptionText_spamfilter": { + "message": "Filtro de spam automático" + }, + "prefs_OptionText_spamfilter_Info": { + "message": "Si está marcado, ThunderAI moverá automáticamente los correos spam a la carpeta de spam." + }, + "prefs_OptionText_btnManageSpamFilterInfo": { + "message": "Gestionar la configuración del filtro de spam" + }, + "SpamFilter_PageTitle": { + "message": "Gestionar la configuración del filtro de spam" + }, + "SpamFilter_info_default": { + "message": "En esta página puedes modificar el prompt predeterminado utilizado para detectar correos spam." + }, + "SpamFilter_prompt_text_title": { + "message": "Texto actual del prompt" + }, + "prompt_spamfilter": { + "message": "Detectar correos spam" + }, + "prompt_spamfilter_full_text": { + "message": "Analiza el siguiente correo electrónico y determina si es spam o no. Considera factores como palabras clave sospechosas, lenguaje promocional excesivo, líneas de asunto engañosas, solicitudes de información personal y direcciones de remitente inusuales. \n\nProporciona un valor de 0 (no es spam) a 100 (spam) y una explicación de no más de 10 palabras. \nEn caso de que falten datos del mensaje, establece el valor en 0 (no es spam) y da la razón. \nGenera una respuesta únicamente en formato JSON. No incluyas texto adicional ni explicación; proporciona solo el JSON. El formato a usar es: \n{\n\"spamValue\": ,\n\"explanation\": \"Breve explicación de tu razonamiento\"\n} \nAquí está la información del correo: \nRemitente: \"{%author%}\" \nAsunto: \"{%mail_subject%}\" \nCuerpo HTML: \"{%mail_html_body%}\"" + }, + "SpamFilter_prompt_prefs_title": { + "message": "Opciones del filtro de spam" + }, + "prefs_OptionText_use_specific_integration": { + "message": "Usar modelo y API específicos" + }, + "prefs_OptionText_spamfilter_use_specific_integration_Info": { + "message": "Si está marcado, el Modelo y la API especificados a continuación se usarán para el filtro de spam, sin importar el que se haya elegido en la página de opciones de ThunderAI." + }, + "prefs_OptionText_spamfilter_threshold": { + "message": "Umbral de spam" + }, + "prefs_OptionText_spamfilter_threshold_Info": { + "message": "Si el valor devuelto por la IA supera este umbral, el correo se moverá a la carpeta de spam." + }, + "spamfilter_threshold_too_low": { + "message": "¡El umbral de spam es demasiado bajo! ¡Probablemente marcarás demasiados correos como spam!" + }, + "spamfilter_threshold_zero": { + "message": "¡El umbral de spam es cero! ¡Marcarás todos los correos como spam!" + }, + "spamfilter_no_reports": { + "message": "No hay mensajes filtrados como spam todavía. Aquí encontrarás una lista de los últimos 100 informes de spam solo para la sesión actual." + }, + "SpamReport_Title": { + "message": "Informes del filtro de spam" + }, + "Date": { + "message": "Fecha" + }, + "From": { + "message": "De" + }, + "Subject": { + "message": "Asunto" + }, + "Spam_Value": { + "message": "Valor de spam" + }, + "Moved_to_Spam": { + "message": "Movido a Spam" } } From 675b4b296c1c1f2d25d9ab1b9ee5fc69678ea57d Mon Sep 17 00:00:00 2001 From: Mic Date: Tue, 30 Dec 2025 22:21:38 +0100 Subject: [PATCH 072/146] Translated using Weblate (French) Currently translated at 99.7% (430 of 431 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/fr/ --- _locales/fr/messages.json | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 2b3f8a52..89cc8a12 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -1107,7 +1107,7 @@ "message": "Version de l’API Claude" }, "prefs_OptionText_anthropic_max_tokens": { - "message": "Nombre maximum de jetons Claude" + "message": "Nombre maximum de jetons" }, "anthropic_api_request_failed": { "message": "Échec de la requête à l'API Claude" @@ -1311,5 +1311,29 @@ }, "Optional_Permission_Denied_Model_Fetching": { "message": "Vous avez refusé l’autorisation facultative nécessaire pour récupérer les modèles pour cette intégration." + }, + "prompt_string": { + "message": "Prompt" + }, + "placeholder_mail_headers": { + "message": "En-têtes d'e-mail" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "Quelle température d'échantillonnage utiliser, entre 0 et 2. Des valeurs plus élevées comme 0,8 rendront le résultat plus aléatoire, tandis que des valeurs plus basses comme 0,2 le rendront plus ciblé et déterministe." + }, + "prefs_ollama_temperature_Info": { + "message": "La température du modèle. Augmenter la température rendra les réponses du modèle plus créatives. La valeur par défaut est 0,8. Il est recommandé d'utiliser des valeurs comprises entre 0 et 1." + }, + "prefs_api_temperature": { + "message": "Température" + }, + "prefs_openai_comp_temperature_Info": { + "message": "Quelle température d'échantillonnage utiliser, entre 0 et 2. Des valeurs plus élevées, comme 0,8, rendront le résultat plus aléatoire, tandis que des valeurs plus basses, comme 0,2, le rendront plus ciblé et déterministe." + }, + "prefs_google_gemini_temperature_Info": { + "message": "Ce paramètre doit être un nombre compris entre 0,0 et 2,0. Il contrôle le caractère aléatoire du résultat. La valeur par défaut varie selon le modèle. Laissez ce champ vide pour ne pas définir le paramètre dans l'appel d'API." + }, + "prefs_anthropic_temperature_Info": { + "message": "Degré d'aléa injecté dans la réponse. La valeur par défaut est 1,0. La plage de valeurs s'étend di 0,0 à 1,0. Utilisez une température proche de 0,0 pour des tâches analytiques ou des choix multiples, et proche de 1,0 pour des tâches créatives et génératives. Notez que même avec une température de 0,0, les résultats ne seront pas totalement déterministes." } } From d39771f02c5ccb0146ee406b2848a45291dff649 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 15:14:30 +0100 Subject: [PATCH 073/146] some comments translated to english --- js/mzta-utils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index 49abe49f..c833bb31 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -631,7 +631,7 @@ export function getConnectionType(prefsOrType, prompt, prefixOrSpecific = null) let specificType = ''; if (typeof prefsOrType === 'object' && prefsOrType !== null) { - // Nuova firma: (prefs, prompt, prefix) + // New signature: (prefs, prompt, prefix) defaultType = prefsOrType.connection_type; if (typeof prefixOrSpecific === 'string' && prefixOrSpecific) { const prefix = prefixOrSpecific; @@ -641,8 +641,7 @@ export function getConnectionType(prefsOrType, prompt, prefixOrSpecific = null) } } } else { - // Vecchia firma / Uso diretto: (connection_type_string, prompt, [specific_type_string]) - defaultType = prefsOrType; + // Old signature / Direct usage: (connection_type_string, prompt, [specific_type_string]) if (typeof prefixOrSpecific === 'string') { specificType = prefixOrSpecific; } From 2357886693fba1145f5d9a7d39c2a6b806f9ccef Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 15:17:55 +0100 Subject: [PATCH 074/146] processEmails updated to use the new dyamic settings --- mzta-background.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mzta-background.js b/mzta-background.js index a29286e7..ddfe6dff 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1035,7 +1035,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { add_tags_auto_uselist: prefs_default.add_tags_auto_uselist, add_tags_auto_uselist_list: prefs_default.add_tags_auto_uselist_list, spamfilter_enabled_accounts: prefs_default.spamfilter_enabled_accounts, - ...getDynamicSettingsDefaults(['use_specific_integration']), + ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']), do_debug: prefs_default.do_debug, }); @@ -1082,8 +1082,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { // console.log(">>>>>>>>>> curr_prompt_add_tags.model: " + curr_prompt_add_tags.model); let cmd_addTags = new mzta_specialCommand({ prompt: specialFullPrompt_add_tags, - llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags, prefs_aats.add_tags_use_specific_integration), - llm: getConnectionType(prefs_aats.connection_type, curr_prompt_add_tags, getDynamicSettingValue(prefs_aats, 'add_tags', 'use_specific_integration')), + llm: getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags'), custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '', do_debug: prefs_aats.do_debug }); @@ -1122,8 +1121,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { // console.log(">>>>>>>> Special prompt for spamfilter: " + specialFullPrompt_spamfilter); let cmd_spamfilter = new mzta_specialCommand({ prompt: specialFullPrompt_spamfilter, - llm: getConnectionType(prefs_aats.connection_type, curr_prompt_spamfilter, prefs_aats.spamfilter_use_specific_integration), - llm: getConnectionType(prefs_aats.connection_type, curr_prompt_spamfilter, getDynamicSettingValue(prefs_aats, 'spamfilter', 'use_specific_integration')), + llm: getConnectionType(prefs_aats, curr_prompt_spamfilter, 'spamfilter'), custom_model: curr_prompt_spamfilter.model ? curr_prompt_spamfilter.model : '', do_debug: prefs_aats.do_debug }); From 3e05f0b551dd06703395d09351874e01bf081323 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 16:00:31 +0100 Subject: [PATCH 075/146] Working on a first version... See #102 --- pages/customprompts/mzta-custom-prompts.js | 232 ++++++++++++++++++++- 1 file changed, 226 insertions(+), 6 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 0187b59a..1922642d 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -16,9 +16,30 @@ * along with this program. If not, see . */ -import { prefs_default } from "../../options/mzta-options-default.js"; -import { getPrompts, setDefaultPromptsProperties, setCustomPrompts, preparePromptsForExport, preparePromptsForImport } from "../../js/mzta-prompts.js"; -import { ChatGPTWeb_models, isThunderbird128OrGreater, getLocalStorageUsedSpace, sanitizeHtml, validateCustomData_ChatGPTWeb, getChatGPTWebModelsList_HTML, openTab } from "../../js/mzta-utils.js"; +import { + prefs_default, + integration_options_config +} from "../../options/mzta-options-default.js"; +import { + getPrompts, + setDefaultPromptsProperties, + setCustomPrompts, + preparePromptsForExport, + preparePromptsForImport +} from "../../js/mzta-prompts.js"; +import { + injectConnectionUI, + showConnectionOptions +} from "../../pages/_lib/connection-ui.js"; +import { + ChatGPTWeb_models, + isThunderbird128OrGreater, + getLocalStorageUsedSpace, + sanitizeHtml, + validateCustomData_ChatGPTWeb, + getChatGPTWebModelsList_HTML, + openTab +} from "../../js/mzta-utils.js"; import { taLogger } from "../../js/mzta-logger.js"; import { getPlaceholders, @@ -106,6 +127,59 @@ document.addEventListener('DOMContentLoaded', async () => { i18n.updateDocument(); + // Inject API Configuration UI for New Prompt + const webToggle = document.getElementById('chatgpt_web_additional_info_toggle'); + + const apiSettingsToggle = document.createElement('tr'); + apiSettingsToggle.id = 'api_additional_info_toggle'; + apiSettingsToggle.className = 'small_info'; + apiSettingsToggle.style.cursor = 'pointer'; + apiSettingsToggle.innerHTML = '' + browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; + + const apiSettingsRow = document.createElement('tr'); + apiSettingsRow.id = 'api_additional_info'; + apiSettingsRow.style.display = 'none'; + apiSettingsRow.innerHTML = ''; + + webToggle.parentNode.insertBefore(apiSettingsToggle, webToggle.nextSibling); + webToggle.parentNode.insertBefore(apiSettingsRow, apiSettingsToggle.nextSibling); + + apiSettingsToggle.addEventListener('click', (e) => { + e.preventDefault(); + if (apiSettingsRow.style.display === 'none') { + apiSettingsRow.style.display = 'table-row'; + apiSettingsToggle.querySelector('span').innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [API]'; + } else { + apiSettingsRow.style.display = 'none'; + apiSettingsToggle.querySelector('span').innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; + } + }); + + const apiTable = document.createElement('table'); + apiTable.style.width = "100%"; + apiTable.innerHTML = '' + browser.i18n.getMessage('prefs_Connection_type') + ':'; + document.getElementById('api_ui_container').appendChild(apiTable); + + await injectConnectionUI({ + afterTrId: 'api_ui_anchor', + selectId: 'new_prompt_api_type', + no_chatgpt_web: true, + taLog: taLog + }); + + const apiSelect = document.getElementById('new_prompt_api_type'); + // Remove chatgpt_web + // for (let i = 0; i < apiSelect.options.length; i++) { + // if (apiSelect.options[i].value === 'chatgpt_web') { + // apiSelect.remove(i); + // break; + // } + // } + apiSelect.addEventListener('change', () => { + showConnectionOptions(apiSelect); + }); + showConnectionOptions(apiSelect); + switch(prefs.connection_type) { case 'chatgpt_web': { // for the new item form @@ -120,7 +194,7 @@ document.addEventListener('DOMContentLoaded', async () => { e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info'); } else { additionalInfoRow.style.display = 'none'; - e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info'); + e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [ChatGPT Web]'; } }); }); @@ -132,6 +206,24 @@ document.addEventListener('DOMContentLoaded', async () => { }); break; } + } + + // for the edit list items form [API] + document.querySelectorAll('.api_additional_info_toggle').forEach(element => { + element.addEventListener('click', (e) => { + e.preventDefault(); + let additionalInfoRow = e.target.closest('td').querySelector('.api_additional_info'); + if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') { + additionalInfoRow.style.display = 'block'; + e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [API]'; + } else { + additionalInfoRow.style.display = 'none'; + e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; + } + }); + }); + + switch(prefs.connection_type) { // case 'chatgpt_api': // document.getElementById('chatgpt_api').style.display = 'block'; // break; @@ -214,6 +306,7 @@ document.addEventListener('DOMContentLoaded', async () => { position_display: positionMax_display + 1, is_default: 0, idnum: idnumMax + 1, + api_type: document.getElementById('new_prompt_api_type').value }; switch(prefs.connection_type) { @@ -236,6 +329,16 @@ document.addEventListener('DOMContentLoaded', async () => { // break; } + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + const inputEl = document.getElementById(propName); + if (inputEl) { + newItemData[propName] = (inputEl.type === 'checkbox') ? inputEl.checked : inputEl.value; + } + } + } + let newItem = promptsList.add(newItemData); idnumMax++; let curr_idnum = newItem[0].values().idnum; @@ -348,6 +451,10 @@ document.addEventListener('DOMContentLoaded', async () => { document.querySelectorAll('.chatgpt_web_additional_info_show').forEach(element => { toggleAdditionalPropertiesShow(element.closest('tr')); }); + + document.querySelectorAll('.api_additional_info_show').forEach(element => { + toggleApiPropertiesShow(element.closest('tr')); + }); getChatGPTWebModelsList_HTML(ChatGPTWeb_models, 'chatgpt_web_models_list'); let formNewWebModelList = document.getElementById('chatgpt_web_models_list'); @@ -381,6 +488,28 @@ document.getElementById('btnManageCustomDataPH').addEventListener('click', () => function handleEditClick(e) { e.preventDefault(); const tr = e.target.parentNode.parentNode; + const id = tr.querySelector('.id_output').value; + + // Inject Connection UI if needed + const anchorId = `api_ui_anchor_${id}`; + const selectId = `api_type_${id}`; + const prefix = `prompt_${id}_`; + + if (!document.getElementById(selectId)) { + injectConnectionUI({ + afterTrId: anchorId, + selectId: selectId, + modelId_prefix: prefix, + no_chatgpt_web: true, + taLog: taLog + }).then(() => { + populateConnectionUI(tr, id, prefix, selectId); + }); + } else { + populateConnectionUI(tr, id, prefix, selectId); + } + + // Show/Hide buttons //console.log('>>>>>>>> tr: ' + tr.getAttribute('data-idnum')); e.target.style.display = 'none'; // Edit btn tr.querySelector('.btnConfirmItem').style.display = 'inline'; // Save btn @@ -391,6 +520,29 @@ function handleEditClick(e) { toggleDiffviewer(e); } +function populateConnectionUI(tr, id, prefix, selectId) { + const item = promptsList.get('id', id)[0]; + const itemValues = item.values(); + + const selectEl = document.getElementById(selectId); + if (selectEl) { + selectEl.value = itemValues.api_type || ''; + showConnectionOptions(selectEl); + } + + 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) { + inputEl.type === 'checkbox' ? inputEl.checked = (itemValues[propName] === true || itemValues[propName] === 'true') : inputEl.value = itemValues[propName] || ''; + } + } + } + i18n.updateDocument(); +} + function showItemRowEditor(tr) { tr.querySelector('.id_output').style.display = 'inline'; tr.querySelector('.id_show').style.display = 'none'; @@ -402,6 +554,7 @@ function showItemRowEditor(tr) { tr.querySelector('.text_show').style.display = 'none'; toggleAdditionalPropertiesEditor(tr); tr.querySelector('.chatgpt_web_additional_info_show').style.display = 'none'; + tr.querySelector('.api_additional_info_show').style.display = 'none'; tr.querySelector('.type_output').style.display = 'inline'; tr.querySelector('.type_show').style.display = 'none'; const action_output = tr.querySelector('.action_output') @@ -424,6 +577,8 @@ function hideItemRowEditor(tr) { tr.querySelector('.text_show').style.display = 'inline'; tr.querySelector('.chatgpt_web_additional_info_toggle').style.display = 'none'; tr.querySelector('.chatgpt_web_additional_info').style.display = 'none'; + tr.querySelector('.api_additional_info_toggle').style.display = 'none'; + tr.querySelector('.api_additional_info').style.display = 'none'; toggleAdditionalPropertiesShow(tr); tr.querySelector('.type_output').style.display = 'none'; tr.querySelector('.type_show').style.display = 'inline'; @@ -486,6 +641,23 @@ function toggleAdditionalPropertiesShow(tr) { } } +function toggleApiPropertiesShow(tr) { + let element = tr.querySelector('.api_additional_info_show'); + let api_type_show = tr.querySelector('.api_type_show'); + + if (api_type_show.innerText !== '' && api_type_show.innerText !== 'undefined') { + element.style.display = 'flex'; + } else { + element.style.display = 'none'; + } + + if(api_type_show.innerText === '' || api_type_show.innerText === 'undefined') { + api_type_show.parentNode.style.display = 'none'; + } else { + api_type_show.parentNode.style.display = 'inline'; + } +} + function toggleAdditionalPropertiesEditor(tr) { switch(prefs.connection_type) { case 'chatgpt_web': { @@ -515,6 +687,14 @@ function toggleAdditionalPropertiesEditor(tr) { // document.getElementById('google_gemini_api').style.display = 'block'; // break; } + + let api_info_toggle = tr.querySelector('.api_additional_info_toggle'); + api_info_toggle.style.display = 'block'; + let api_type_show = tr.querySelector('.api_type_show').innerText; + + if (api_type_show !== '' && api_type_show !== 'undefined') { + api_info_toggle.click(); + } } function toggleDiffviewer(e) { @@ -574,6 +754,27 @@ function handleConfirmClick(e) { e.preventDefault(); const tr = e.target.parentNode.parentNode; e.target.style.display = 'none'; // Ok btn + + const id = tr.querySelector('.id_output').value; + const prefix = `prompt_${id}_`; + const selectId = `api_type_${id}`; + + let newValues = {}; + const selectEl = document.getElementById(selectId); + if(selectEl) newValues.api_type = selectEl.value; + + 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) { + newValues[propName] = (inputEl.type === 'checkbox') ? inputEl.checked : inputEl.value; + } + } + } + promptsList.get('id', id)[0].values(newValues); + // tr.querySelector('.btnConfirmItem').style.display = 'none'; // Ok btn tr.querySelector('.btnCancelItem').style.display = 'none'; // Cancel btn tr.querySelector('.btnEditItem').style.display = 'inline'; // Edit btn @@ -585,6 +786,7 @@ function handleConfirmClick(e) { tr.querySelector('.chatgpt_web_model_show').innerText = tr.querySelector('.chatgpt_web_model_output').value; tr.querySelector('.chatgpt_web_project_show').innerText = tr.querySelector('.chatgpt_web_project_output').value; tr.querySelector('.chatgpt_web_custom_gpt_show').innerText = tr.querySelector('.chatgpt_web_custom_gpt_output').value; + tr.querySelector('.api_type_show').innerText = newValues.api_type || ''; tr.querySelector('.type').innerText = tr.querySelector('.type_output').value; tr.querySelector('.type_show').innerText = tr.querySelector('.type_output').selectedOptions[0].text; tr.querySelector('.action').innerText = tr.querySelector('.action_output').value; @@ -617,8 +819,15 @@ function handleInputChange(e) { function loadPromptsList(values){ // console.log('>>>>>>>> loadPromptsList values: ' + JSON.stringify(values)); + let api_fields = []; + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + api_fields.push(`${integration}_${key}`); + } + } + let options = { - valueNames: [ { data: ['idnum'] }, 'is_default', 'id', 'name', 'text', 'type', 'action', 'position_compose', 'position_display', { name: 'need_selected', attr: 'checked_val'}, { name: 'need_signature', attr: 'checked_val'}, { name: 'need_custom_text', attr: 'checked_val'}, { name: 'define_response_lang', attr: 'checked_val'}, { name: 'use_diff_viewer', attr: 'checked_val'}, { name: 'enabled', attr: 'checked_val'} ], + valueNames: [ { data: ['idnum'] }, 'is_default', 'id', 'name', 'text', 'type', 'action', 'position_compose', 'position_display', { name: 'need_selected', attr: 'checked_val'}, { name: 'need_signature', attr: 'checked_val'}, { name: 'need_custom_text', attr: 'checked_val'}, { name: 'define_response_lang', attr: 'checked_val'}, { name: 'use_diff_viewer', attr: 'checked_val'}, { name: 'enabled', attr: 'checked_val'}, 'api_type', ...api_fields ], item: function(values) { let type_output = ''; switch(String(values.type)){ @@ -676,6 +885,14 @@ function loadPromptsList(values){
              __MSG_prefs_OptionText_chatgpt_web_custom_data_info2__
              __MSG_prefs_OptionText_CustomGPT_Warn__
        +
        __MSG_customPrompts_show_additional_info__ [API]
        +
        + + + + +
        +
        __MSG_customPrompts_add_to_menu__:
        @@ -711,11 +928,14 @@ function loadPromptsList(values){ -
        __MSG_customPrompts_show_additional_info_show__ +
        __MSG_customPrompts_show_additional_info_show__ [ChatGPT Web]
        __MSG_prefs_OptionText_chatgpt_web_model__:` + values.chatgpt_web_model + `
        __MSG_prefs_OptionText_chatgpt_web_project__:` + values.chatgpt_web_project + `
        __MSG_prefs_OptionText_chatgpt_web_custom_gpt__:` + values.chatgpt_web_custom_gpt + `
        +
        __MSG_customPrompts_show_additional_info_show__ [API] +
        __MSG_prefs_Connection_type__:` + values.api_type + `
        +
        From 0eaeec9e9f6a3b07e287bb02a3cec7f8486c2934 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 16:17:10 +0100 Subject: [PATCH 076/146] fixes to work with the custom prompts page. see #102 --- pages/_lib/connection-ui.js | 151 ++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 68 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index f3e823cd..3b19b2ab 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -50,6 +50,19 @@ export async function injectConnectionUI({ return null; } + // Inject CSS if not present + if (!document.getElementById('mzta-connection-ui-style')) { + const style = document.createElement('style'); + style.id = 'mzta-connection-ui-style'; + style.textContent = ` + .api_key-container { position: relative; display: flex; align-items: center; } + .toggle-icon { cursor: pointer; margin-left: 5px; } + .toggle-icon img { width: 16px; height: 16px; vertical-align: middle; } + .option-input { flex-grow: 1; } + `; + document.head.appendChild(style); + } + let tpl = ` @@ -140,7 +153,7 @@ export async function injectConnectionUI({ - +
        @@ -151,7 +164,7 @@ export async function injectConnectionUI({ - __MSG_Loading__
        +
        @@ -205,7 +218,7 @@ export async function injectConnectionUI({ - +
    @@ -216,7 +229,7 @@ export async function injectConnectionUI({ - __MSG_Loading__
    +
    @@ -273,12 +286,12 @@ export async function injectConnectionUI({ - + __MSG_remember_CORS__ [__MSG_more_info_string__]

    __MSG_CORS_alternative_1__
    __MSG_CORS_alternative_2__ -

    +

    @@ -288,7 +301,7 @@ export async function injectConnectionUI({ - __MSG_Loading__
    +
    @@ -335,7 +348,7 @@ export async function injectConnectionUI({ @@ -352,12 +365,12 @@ export async function injectConnectionUI({ - + __MSG_maybe_CORS_openai_comp__ [__MSG_more_info_string__]

    __MSG_CORS_alternative_1__
    __MSG_CORS_alternative_2__ -

    +

    @@ -381,7 +394,7 @@ export async function injectConnectionUI({ - + @@ -389,12 +402,12 @@ export async function injectConnectionUI({ - __MSG_Loading__
    +
    @@ -433,7 +446,7 @@ export async function injectConnectionUI({ - + @@ -444,7 +457,7 @@ export async function injectConnectionUI({ - __MSG_Loading__
    +
    @@ -549,7 +562,7 @@ export async function injectConnectionUI({ document.getElementById(getPrefixedId("openai_comp_use_v1")).addEventListener("input", () => resetOpenAICompConfigs(modelId_prefix)); showConnectionOptions(conntype_select); - loadOpenAICompConfigs(); + loadOpenAICompConfigs(modelId_prefix); warn_ChatGPT_APIKeyEmpty(modelId_prefix); warn_Ollama_HostEmpty(modelId_prefix); warn_OpenAIComp_HostEmpty(modelId_prefix); @@ -558,8 +571,8 @@ export async function injectConnectionUI({ warn_Anthropic_VersionEmpty(modelId_prefix); const passwordField_chatgpt_api_key = document.getElementById(getPrefixedId('chatgpt_api_key')); - const toggleIcon_chatgpt_api_key = document.getElementById('toggle_chatgpt_api_key'); - const icon_img_chatgpt_api_key = document.getElementById('pwd-icon_chatgpt_api_key'); + const toggleIcon_chatgpt_api_key = document.getElementById(getPrefixedId('toggle_chatgpt_api_key')); + const icon_img_chatgpt_api_key = document.getElementById(getPrefixedId('pwd-icon_chatgpt_api_key')); toggleIcon_chatgpt_api_key.addEventListener('click', () => { const type = passwordField_chatgpt_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; @@ -569,8 +582,8 @@ export async function injectConnectionUI({ }); const passwordField_google_gemini_api_key = document.getElementById(getPrefixedId('google_gemini_api_key')); - const toggleIcon_google_gemini_api_key = document.getElementById('toggle_google_gemini_api_key'); - const icon_img_google_gemini_api_key = document.getElementById('pwd-icon_google_gemini_api_key'); + const toggleIcon_google_gemini_api_key = document.getElementById(getPrefixedId('toggle_google_gemini_api_key')); + const icon_img_google_gemini_api_key = document.getElementById(getPrefixedId('pwd-icon_google_gemini_api_key')); toggleIcon_google_gemini_api_key.addEventListener('click', () => { const type = passwordField_google_gemini_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; @@ -580,8 +593,8 @@ export async function injectConnectionUI({ }); const passwordField_openai_comp_api_key = document.getElementById(getPrefixedId('openai_comp_api_key')); - const toggleIcon_openai_comp_api_key = document.getElementById('toggle_openai_comp_api_key'); - const icon_img_openai_comp_api_key = document.getElementById('pwd-icon_openai_comp_api_key'); + const toggleIcon_openai_comp_api_key = document.getElementById(getPrefixedId('toggle_openai_comp_api_key')); + const icon_img_openai_comp_api_key = document.getElementById(getPrefixedId('pwd-icon_openai_comp_api_key')); toggleIcon_openai_comp_api_key.addEventListener('click', () => { const type = passwordField_openai_comp_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; @@ -591,8 +604,8 @@ export async function injectConnectionUI({ }); const passwordField_anthropic_api_key = document.getElementById(getPrefixedId('anthropic_api_key')); - const toggleIcon_anthropic_api_key = document.getElementById('toggle_anthropic_api_key'); - const icon_img_anthropic_api_key = document.getElementById('pwd-icon_anthropic_api_key'); + const toggleIcon_anthropic_api_key = document.getElementById(getPrefixedId('toggle_anthropic_api_key')); + const icon_img_anthropic_api_key = document.getElementById(getPrefixedId('pwd-icon_anthropic_api_key')); toggleIcon_anthropic_api_key.addEventListener('click', () => { const type = passwordField_anthropic_api_key.getAttribute('type') === 'password' ? 'text' : 'password'; @@ -626,7 +639,7 @@ export async function injectConnectionUI({ browser.tabs.create({ url: base_url + model_opt }); }); - let select_openai_comp_services_shortcut = document.getElementById('openai_comp_services_shortcut'); + let select_openai_comp_services_shortcut = document.getElementById(getPrefixedId('openai_comp_services_shortcut')); select_openai_comp_services_shortcut.addEventListener("change", () => { let selectedOption = select_openai_comp_services_shortcut.options[select_openai_comp_services_shortcut.selectedIndex]; const config = openAICompConfigs.find(cfg => cfg.id === selectedOption.value); @@ -661,14 +674,14 @@ export async function injectConnectionUI({ select_chatgpt_model.appendChild(chatgpt_option); select_chatgpt_model.addEventListener("change", () => warn_ChatGPT_APIKeyEmpty(modelId_prefix)); - document.getElementById('btnUpdateChatGPTModels').addEventListener('click', async () => { - document.getElementById('chatgpt_model_fetch_loading').style.display = 'inline'; + document.getElementById(getPrefixedId('btnUpdateChatGPTModels')).addEventListener('click', async () => { + document.getElementById(getPrefixedId('chatgpt_model_fetch_loading')).style.display = 'inline'; let openai = new OpenAI({ apiKey: document.getElementById(getPrefixedId("chatgpt_api_key")).value, }); let granted = await messenger.permissions.request({ origins: ["https://*.openai.com/*"] }); if(!granted){ - document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('chatgpt_model_fetch_loading')).style.display = 'none'; taLog.log("OpenAI API permission denied"); alert(browser.i18n.getMessage("Optional_Permission_Denied_Model_Fetching")); return; @@ -682,7 +695,7 @@ export async function injectConnectionUI({ } catch (e) { errorDetail = data.error; } - document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('chatgpt_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("ChatGPT_Models_Error_fetching")); alert(browser.i18n.getMessage("ChatGPT_Models_Error_fetching")+": " + errorDetail); return; @@ -696,7 +709,7 @@ export async function injectConnectionUI({ select_chatgpt_model.appendChild(option); } }); - document.getElementById('chatgpt_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('chatgpt_model_fetch_loading')).style.display = 'none'; }); warn_ChatGPT_APIKeyEmpty(modelId_prefix); @@ -710,8 +723,8 @@ export async function injectConnectionUI({ select_google_gemini_model.appendChild(google_gemini_option); select_google_gemini_model.addEventListener("change", () => warn_GoogleGemini_APIKeyEmpty(modelId_prefix)); - document.getElementById('btnUpdateGoogleGeminiModels').addEventListener('click', async () => { - document.getElementById('google_gemini_model_fetch_loading').style.display = 'inline'; + document.getElementById(getPrefixedId('btnUpdateGoogleGeminiModels')).addEventListener('click', async () => { + document.getElementById(getPrefixedId('google_gemini_model_fetch_loading')).style.display = 'inline'; let google_gemini = new GoogleGemini({ apiKey: document.getElementById(getPrefixedId("google_gemini_api_key")).value, }); @@ -724,7 +737,7 @@ export async function injectConnectionUI({ } catch (e) { errorDetail = data.error; } - document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('google_gemini_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")); alert(browser.i18n.getMessage("GoogleGemini_Models_Error_fetching")+": " + errorDetail); return; @@ -738,7 +751,7 @@ export async function injectConnectionUI({ select_google_gemini_model.appendChild(option); } }); - document.getElementById('google_gemini_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('google_gemini_model_fetch_loading')).style.display = 'none'; }); warn_GoogleGemini_APIKeyEmpty(modelId_prefix); @@ -752,15 +765,15 @@ export async function injectConnectionUI({ select_ollama_model.appendChild(ollama_option); select_ollama_model.addEventListener("change", () => warn_Ollama_HostEmpty(modelId_prefix)); - document.getElementById('btnUpdateOllamaModels').addEventListener('click', async () => { - document.getElementById('ollama_model_fetch_loading').style.display = 'inline'; + document.getElementById(getPrefixedId('btnUpdateOllamaModels')).addEventListener('click', async () => { + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'inline'; let ollama = new Ollama({ host: document.getElementById(getPrefixedId("ollama_host")).value, }); try { let data = await ollama.fetchModels(); if(!data){ - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")); return; @@ -773,13 +786,13 @@ export async function injectConnectionUI({ } catch (e) { errorDetail = data.error; } - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + errorDetail); return; } if(data.response.models.length == 0){ - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("Ollama_Models_Error_fetching")); alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + browser.i18n.getMessage("API_Models_Error_NoModels")); return; @@ -793,9 +806,9 @@ export async function injectConnectionUI({ select_ollama_model.appendChild(option); } }); - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none'; } catch (error) { - document.getElementById('ollama_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('ollama_model_fetch_loading')).style.display = 'none'; taLog.error(browser.i18n.getMessage("Ollama_Models_Error_fetching")); alert(browser.i18n.getMessage("Ollama_Models_Error_fetching")+": " + error.message); } @@ -811,8 +824,8 @@ export async function injectConnectionUI({ select_openai_comp_model.appendChild(openai_comp_option); select_openai_comp_model.addEventListener("change", () => warn_OpenAIComp_HostEmpty(modelId_prefix)); - document.getElementById('btnUpdateOpenAICompModels').addEventListener('click', async () => { - document.getElementById('openai_comp_model_fetch_loading').style.display = 'inline'; + document.getElementById(getPrefixedId('btnUpdateOpenAICompModels')).addEventListener('click', async () => { + document.getElementById(getPrefixedId('openai_comp_model_fetch_loading')).style.display = 'inline'; let openai_comp = new OpenAIComp({ host: document.getElementById(getPrefixedId("openai_comp_host")).value, apiKey: document.getElementById(getPrefixedId("openai_comp_api_key")).value, @@ -827,7 +840,7 @@ export async function injectConnectionUI({ } catch (e) { errorDetail = data.error; } - document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('openai_comp_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")); alert(browser.i18n.getMessage("OpenAIComp_Models_Error_fetching")+": " + errorDetail); return; @@ -841,7 +854,7 @@ export async function injectConnectionUI({ select_openai_comp_model.appendChild(option); } }); - document.getElementById('openai_comp_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('openai_comp_model_fetch_loading')).style.display = 'none'; }); warn_OpenAIComp_HostEmpty(modelId_prefix); @@ -856,15 +869,15 @@ export async function injectConnectionUI({ select_anthropic_model.addEventListener("change", () => warn_Anthropic_APIKeyEmpty(modelId_prefix)); select_anthropic_model.addEventListener("change", () => warn_Anthropic_VersionEmpty(modelId_prefix)); - document.getElementById('btnUpdateAnthropicModels').addEventListener('click', async () => { - document.getElementById('anthropic_model_fetch_loading').style.display = 'inline'; + document.getElementById(getPrefixedId('btnUpdateAnthropicModels')).addEventListener('click', async () => { + document.getElementById(getPrefixedId('anthropic_model_fetch_loading')).style.display = 'inline'; let anthropic = new Anthropic({ apiKey: document.getElementById(getPrefixedId("anthropic_api_key")).value, version: document.getElementById(getPrefixedId("anthropic_version")).value, }); let granted = await messenger.permissions.request({ origins: ["https://*.anthropic.com/*"] }); if(!granted){ - document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('anthropic_model_fetch_loading')).style.display = 'none'; taLog.warn("Claude API web permission denied"); alert(browser.i18n.getMessage("Optional_Permission_Denied_Model_Fetching")); return; @@ -878,7 +891,7 @@ export async function injectConnectionUI({ } catch (e) { errorDetail = data.error; } - document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('anthropic_model_fetch_loading')).style.display = 'none'; console.error("[ThunderAI] " + browser.i18n.getMessage("Anthropic_Models_Error_fetching")); alert(browser.i18n.getMessage("Anthropic_Models_Error_fetching")+": " + errorDetail); return; @@ -895,13 +908,13 @@ export async function injectConnectionUI({ select_anthropic_model.appendChild(option); } }); - document.getElementById('anthropic_model_fetch_loading').style.display = 'none'; + document.getElementById(getPrefixedId('anthropic_model_fetch_loading')).style.display = 'none'; }); warn_Anthropic_APIKeyEmpty(modelId_prefix); }); - document.getElementById('btnOpenAICompForceModel').addEventListener('click', () => { + document.getElementById(getPrefixedId('btnOpenAICompForceModel')).addEventListener('click', () => { let modelName = prompt(browser.i18n.getMessage('OpenAIComp_force_model_ask')).trim(); if ((modelName !== null) && (modelName !== undefined) && (modelName !== '')) { let select_openai_comp_model = getModelEl('openai_comp_model', modelId_prefix); @@ -914,7 +927,7 @@ export async function injectConnectionUI({ } }); - document.getElementById('btnOpenAICompClearModelsList').addEventListener('click', () => { + document.getElementById(getPrefixedId('btnOpenAICompClearModelsList')).addEventListener('click', () => { if (!confirm(browser.i18n.getMessage('OpenAIComp_ClearModelsList_Confirm'))) { return; } @@ -926,11 +939,11 @@ export async function injectConnectionUI({ select_openai_comp_model.dispatchEvent(new Event('change', { bubbles: true })); }); - document.getElementById('btnGiveAllUrlsPermission_ollama_api').addEventListener('click', async () => { + document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_ollama_api')).addEventListener('click', async () => { varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: [""] }); }); - document.getElementById('btnGiveAllUrlsPermission_openai_comp_api').addEventListener('click', async () => { + document.getElementById(getPrefixedId('btnGiveAllUrlsPermission_openai_comp_api')).addEventListener('click', async () => { varConnectionUI.permission_all_urls = await messenger.permissions.request({ origins: [""] }); }); @@ -1077,7 +1090,7 @@ export function changeConnTypeRowColor(conntype_row, conntype_select) { conntype_row.classList.toggle("conntype_anthropic_api", (conntype_select.value === "anthropic_api")); } -export function showConnectionOptions(conntype_select) { +export function showConnectionOptions(conntype_select, modelId_prefix = '') { let chatgpt_web_display = 'table-row'; let chatgpt_api_display = 'none'; let ollama_api_display = 'none'; @@ -1135,8 +1148,10 @@ export function showConnectionOptions(conntype_select) { element.style.display = anthropic_api_display; }); if (varConnectionUI.permission_all_urls) { - document.getElementById('openai_comp_api_cors_warning').style.display = 'none'; - document.getElementById('ollama_api_cors_warning').style.display = 'none'; + const openaiCompWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning'); + if (openaiCompWarning) openaiCompWarning.style.display = 'none'; + const ollamaWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning'); + if (ollamaWarning) ollamaWarning.style.display = 'none'; } } @@ -1190,7 +1205,7 @@ function warn_InvalidNumber(event){ function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let apiKeyInput = document.getElementById(getPrefixedId('chatgpt_api_key')); - let btnFetchChatGPTModels = document.getElementById('btnUpdateChatGPTModels'); + let btnFetchChatGPTModels = document.getElementById(getPrefixedId('btnUpdateChatGPTModels')); let modelChatGPT = getModelEl('chatgpt_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; @@ -1213,7 +1228,7 @@ function warn_ChatGPT_APIKeyEmpty(modelId_prefix) { function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let apiKeyInput = document.getElementById(getPrefixedId('google_gemini_api_key')); - let btnFetchGoogleGeminiModels = document.getElementById('btnUpdateGoogleGeminiModels'); + let btnFetchGoogleGeminiModels = document.getElementById(getPrefixedId('btnUpdateGoogleGeminiModels')); let modelGoogleGemini = getModelEl('google_gemini_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; @@ -1236,7 +1251,7 @@ function warn_GoogleGemini_APIKeyEmpty(modelId_prefix) { function warn_Ollama_HostEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let hostInput = document.getElementById(getPrefixedId('ollama_host')); - let btnFetchOllamaModels = document.getElementById('btnUpdateOllamaModels'); + let btnFetchOllamaModels = document.getElementById(getPrefixedId('btnUpdateOllamaModels')); let modelOllama = getModelEl('ollama_model', modelId_prefix); if(hostInput.value === ''){ hostInput.style.border = '2px solid red'; @@ -1259,7 +1274,7 @@ function warn_Ollama_HostEmpty(modelId_prefix) { function warn_OpenAIComp_HostEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let hostInput = document.getElementById(getPrefixedId('openai_comp_host')); - let btnUpdateOpenAICompModels = document.getElementById('btnUpdateOpenAICompModels'); + let btnUpdateOpenAICompModels = document.getElementById(getPrefixedId('btnUpdateOpenAICompModels')); let modelOpenAIComp = getModelEl('openai_comp_model', modelId_prefix); if(hostInput.value === ''){ hostInput.style.border = '2px solid red'; @@ -1282,7 +1297,7 @@ function warn_OpenAIComp_HostEmpty(modelId_prefix) { function warn_Anthropic_APIKeyEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let apiKeyInput = document.getElementById(getPrefixedId('anthropic_api_key')); - let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); + let btnFetchAnthropicModels = document.getElementById(getPrefixedId('btnUpdateAnthropicModels')); let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(apiKeyInput.value === ''){ apiKeyInput.style.border = '2px solid red'; @@ -1305,7 +1320,7 @@ function warn_Anthropic_APIKeyEmpty(modelId_prefix) { function warn_Anthropic_VersionEmpty(modelId_prefix) { const getPrefixedId = (id) => `${modelId_prefix ? `${modelId_prefix}` : ''}${id}`; let versionInput = document.getElementById(getPrefixedId('anthropic_version')); - let btnFetchAnthropicModels = document.getElementById('btnUpdateAnthropicModels'); + let btnFetchAnthropicModels = document.getElementById(getPrefixedId('btnUpdateAnthropicModels')); let modelAnthropic = getModelEl('anthropic_model', modelId_prefix); if(versionInput.value === ''){ versionInput.style.border = '2px solid red'; @@ -1325,13 +1340,13 @@ function warn_Anthropic_VersionEmpty(modelId_prefix) { } } -function resetOpenAICompConfigs(){ - let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); +function resetOpenAICompConfigs(modelId_prefix = ''){ + let select_openai_comp_model = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_services_shortcut'); select_openai_comp_model.value = 'custom'; } -function loadOpenAICompConfigs(){ - let select_openai_comp_model = document.getElementById('openai_comp_services_shortcut'); +function loadOpenAICompConfigs(modelId_prefix = ''){ + let select_openai_comp_model = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_services_shortcut'); openAICompConfigs.forEach(config => { const option = document.createElement('option'); option.value = config.id; From 1b1143e6e37f66b9b0b96f79327332fdf3bacd26 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 16:30:10 +0100 Subject: [PATCH 077/146] saving custom prompts api settings --- pages/customprompts/mzta-custom-prompts.js | 72 ++++++++++++---------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 1922642d..93d3beea 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -329,15 +329,8 @@ document.addEventListener('DOMContentLoaded', async () => { // break; } - for (const [integration, options] of Object.entries(integration_options_config)) { - for (const key of Object.keys(options)) { - const propName = `${integration}_${key}`; - const inputEl = document.getElementById(propName); - if (inputEl) { - newItemData[propName] = (inputEl.type === 'checkbox') ? inputEl.checked : inputEl.value; - } - } - } + const apiValues = getAPIValuesFromUI(); + Object.assign(newItemData, apiValues); let newItem = promptsList.add(newItemData); idnumMax++; @@ -755,38 +748,40 @@ function handleConfirmClick(e) { const tr = e.target.parentNode.parentNode; e.target.style.display = 'none'; // Ok btn - const id = tr.querySelector('.id_output').value; - const prefix = `prompt_${id}_`; - const selectId = `api_type_${id}`; + const oldId = tr.querySelector('.id_show').innerText; + const prefix = `prompt_${oldId}_`; + const selectId = `api_type_${oldId}`; let newValues = {}; + + // Standard fields + newValues.id = tr.querySelector('.id_output').value.trim().toLowerCase(); + newValues.name = tr.querySelector('.name_output').value.trim(); + newValues.text = tr.querySelector('.text_output').value; + newValues.type = tr.querySelector('.type_output').value; + newValues.action = tr.querySelector('.action_output').value; + newValues.need_selected = tr.querySelector('.need_selected').checked ? 1 : 0; + newValues.need_signature = tr.querySelector('.need_signature').checked ? 1 : 0; + newValues.need_custom_text = tr.querySelector('.need_custom_text').checked ? 1 : 0; + newValues.define_response_lang = tr.querySelector('.define_response_lang').checked ? 1 : 0; + newValues.use_diff_viewer = tr.querySelector('.use_diff_viewer').checked ? 1 : 0; + newValues.enabled = tr.querySelector('.enabled').checked ? 1 : 0; + newValues.chatgpt_web_model = tr.querySelector('.chatgpt_web_model_output').value.trim(); + newValues.chatgpt_web_project = tr.querySelector('.chatgpt_web_project_output').value.trim(); + newValues.chatgpt_web_custom_gpt = tr.querySelector('.chatgpt_web_custom_gpt_output').value.trim(); + const selectEl = document.getElementById(selectId); if(selectEl) newValues.api_type = selectEl.value; - 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) { - newValues[propName] = (inputEl.type === 'checkbox') ? inputEl.checked : inputEl.value; - } - } - } - promptsList.get('id', id)[0].values(newValues); + const apiValues = getAPIValuesFromUI(prefix); + Object.assign(newValues, apiValues); + promptsList.get('id', oldId)[0].values(newValues); // tr.querySelector('.btnConfirmItem').style.display = 'none'; // Ok btn tr.querySelector('.btnCancelItem').style.display = 'none'; // Cancel btn tr.querySelector('.btnEditItem').style.display = 'inline'; // Edit btn tr.querySelector('.btnDeleteItem').style.display = 'inline'; // Delete btn // Update item data - tr.querySelector('.id_show').innerText = String(tr.querySelector('.id_output').value).toLocaleLowerCase(); - tr.querySelector('.name_show').innerText = tr.querySelector('.name_output').value; - tr.querySelector('.text_show').innerText = tr.querySelector('.text_output').value; - tr.querySelector('.chatgpt_web_model_show').innerText = tr.querySelector('.chatgpt_web_model_output').value; - tr.querySelector('.chatgpt_web_project_show').innerText = tr.querySelector('.chatgpt_web_project_output').value; - tr.querySelector('.chatgpt_web_custom_gpt_show').innerText = tr.querySelector('.chatgpt_web_custom_gpt_output').value; - tr.querySelector('.api_type_show').innerText = newValues.api_type || ''; tr.querySelector('.type').innerText = tr.querySelector('.type_output').value; tr.querySelector('.type_show').innerText = tr.querySelector('.type_output').selectedOptions[0].text; tr.querySelector('.action').innerText = tr.querySelector('.action_output').value; @@ -1060,6 +1055,21 @@ function clearFields() { document.getElementById('formNew').style.display = 'none'; } +function getAPIValuesFromUI(prefix = '') { + let values = {}; + 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) { + values[propName] = (inputEl.type === 'checkbox') ? inputEl.checked : inputEl.value; + } + } + } + return values; +} + function inputSetError(input) { document.getElementById(input).style.borderColor = 'red'; } @@ -1117,8 +1127,6 @@ async function saveAll() { setMessage(browser.i18n.getMessage('customPrompts_start_saving')); setNothingChanged(); if(promptsList != null) { - setMessage(browser.i18n.getMessage('customPrompts_reindexing_list')); - promptsList.reIndex(); let newPrompts = promptsList.items.map(item => { // For each item in the array, return only the '_values' part // console.log(">>>>>>>>>>>>>>>> item: " + JSON.stringify(item)) From 9429395030b5fc7df1251677a224c819e62d5be5 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 21:38:30 +0100 Subject: [PATCH 078/146] maxtokens is parsed as an int --- js/api/anthropic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/api/anthropic.js b/js/api/anthropic.js index b8c5f844..dcf438c5 100644 --- a/js/api/anthropic.js +++ b/js/api/anthropic.js @@ -93,7 +93,7 @@ export class Anthropic { let claude_body = { model: this.model, - max_tokens: this.max_tokens, + max_tokens: parseInt(this.max_tokens), system: this.system_prompt, messages: messages, stream: this.stream, From e3d927ab29c24d0e205217526dd255ccf1b8ad3a Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 21:41:48 +0100 Subject: [PATCH 079/146] specific integration settings are now saved at prompt level. see #102 --- js/mzta-menus.js | 35 ++++++++++++++++++++--------- js/mzta-special-commands.js | 33 ++++++++++++++++++++++++++- mzta-background.js | 6 +++-- options/mzta-options-default.js | 6 +++-- pages/_lib/connection-ui.js | 15 ++++++++----- pages/addtags/mzta-add-tags.js | 18 +++++++++++++++ pages/spamfilter/mzta-spamfilter.js | 33 ++++++++++++++------------- 7 files changed, 109 insertions(+), 37 deletions(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index 241daebe..c2a54999 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -19,7 +19,10 @@ // Some original methods are derived from https://github.com/ali-raheem/Aify/blob/cfadf52f576b7be3720b5b73af7c8d3129c054da/plugin/html/actions.js import { getPrompts } from './mzta-prompts.js'; -import { prefs_default } from '../options/mzta-options-default.js'; +import { + prefs_default, + getDynamicSettingsDefaults +} from '../options/mzta-options-default.js'; import { getLanguageDisplayName, getMenuContextCompose, @@ -222,7 +225,8 @@ export class mzta_Menus { prompt: fullPrompt, llm: def_conntype, custom_model: curr_prompt.model ? curr_prompt.model : '', - do_debug: prefs_at.do_debug + do_debug: prefs_at.do_debug, + config: curr_prompt }); await cmd_addTags.initWorker(); try{ @@ -258,9 +262,11 @@ export class mzta_Menus { connection_type: prefs_default.connection_type, calendar_enforce_timezone: prefs_default.calendar_enforce_timezone, calendar_timezone: prefs_default.calendar_timezone, + ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']) }); - if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){ - console.error("[ThunderAI | GetCalendarEvent] Invalid connection type: " + prefs_at.connection_type); + let def_conntype = getConnectionType(prefs_at, curr_prompt, 'get_calendar_event'); + if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){ + console.error("[ThunderAI | GetCalendarEvent] Invalid connection type: " + def_conntype); taWorkingStatus.stopWorking(); return {ok:'0'}; } @@ -277,8 +283,9 @@ export class mzta_Menus { this.logger.log("fullPrompt: " + fullPrompt); let cmd_GetCalendarEvent = new mzta_specialCommand({ prompt: fullPrompt, - llm: prefs_at.connection_type, - do_debug: true + llm: def_conntype, + do_debug: true, + config: curr_prompt }); await cmd_GetCalendarEvent.initWorker(); try{ @@ -333,9 +340,14 @@ export class mzta_Menus { } case 'prompt_get_task': { // Get a task info let task_data = ''; - let prefs_at = await browser.storage.sync.get({connection_type: '', calendar_enforce_timezone: false, calendar_timezone: '',}); - if((prefs_at.connection_type === '')||(prefs_at.connection_type === null)||(prefs_at.connection_type === undefined)||(prefs_at.connection_type === 'chatgpt_web')){ - console.error("[ThunderAI | GetTask] Invalid connection type: " + prefs_at.connection_type); + let prefs_at = await browser.storage.sync.get({ + connection_type: '', + calendar_enforce_timezone: false, + calendar_timezone: '', + ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type'])}); + let def_conntype = getConnectionType(prefs_at, curr_prompt, 'get_task'); + if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){ + console.error("[ThunderAI | GetTask] Invalid connection type: " + def_conntype); taWorkingStatus.stopWorking(); return {ok:'0'}; } @@ -349,8 +361,9 @@ export class mzta_Menus { this.logger.log("fullPrompt: " + fullPrompt); let cmd_GetTask = new mzta_specialCommand({ prompt: fullPrompt, - llm: prefs_at.connection_type, - do_debug: true + llm: def_conntype, + do_debug: true, + config: curr_prompt }); await cmd_GetTask.initWorker(); try{ diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index a6ddaad3..da63271c 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -29,17 +29,20 @@ full_message = ""; logger = null; do_debug = false; + config = {}; constructor(args = {}) { let { prompt = '', llm = '', custom_model = '', - do_debug = false + do_debug = false, + config = {} } = args; this.prompt = prompt; this.llm = llm; this.custom_model = custom_model; + this.config = config; this.logger = new taLogger('mzta_specialCommand', do_debug); this.do_debug = do_debug; switch (this.llm) { @@ -73,6 +76,11 @@ chatgpt_model: prefs_default.chatgpt_model, chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, }); + + if (this.config.chatgpt_api_key) prefs_api.chatgpt_api_key = this.config.chatgpt_api_key; + if (this.config.chatgpt_model) prefs_api.chatgpt_model = this.config.chatgpt_model; + if (this.config.chatgpt_developer_messages) prefs_api.chatgpt_developer_messages = this.config.chatgpt_developer_messages; + this.worker.postMessage({ type: 'init', chatgpt_api_key: prefs_api.chatgpt_api_key, @@ -90,6 +98,12 @@ google_gemini_system_instruction: prefs_default.google_gemini_system_instruction, google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget, }); + + if (this.config.google_gemini_api_key) prefs_api.google_gemini_api_key = this.config.google_gemini_api_key; + if (this.config.google_gemini_model) prefs_api.google_gemini_model = this.config.google_gemini_model; + if (this.config.google_gemini_system_instruction) prefs_api.google_gemini_system_instruction = this.config.google_gemini_system_instruction; + if (this.config.google_gemini_thinking_budget) prefs_api.google_gemini_thinking_budget = this.config.google_gemini_thinking_budget; + this.worker.postMessage({ type: 'init', google_gemini_api_key: prefs_api.google_gemini_api_key, @@ -106,6 +120,10 @@ ollama_host: prefs_default.ollama_host, ollama_model: prefs_default.ollama_model, }); + + if (this.config.ollama_host) prefs_api.ollama_host = this.config.ollama_host; + if (this.config.ollama_model) prefs_api.ollama_model = this.config.ollama_model; + this.worker.postMessage({ type: 'init', ollama_host: prefs_api.ollama_host, @@ -124,6 +142,13 @@ openai_comp_chat_name: prefs_default.openai_comp_chat_name, do_debug: prefs_default.do_debug, }); + + if (this.config.openai_comp_host) prefs_api.openai_comp_host = this.config.openai_comp_host; + if (this.config.openai_comp_model) prefs_api.openai_comp_model = this.config.openai_comp_model; + if (this.config.openai_comp_api_key) prefs_api.openai_comp_api_key = this.config.openai_comp_api_key; + if (this.config.openai_comp_use_v1 !== undefined) prefs_api.openai_comp_use_v1 = this.config.openai_comp_use_v1; + if (this.config.openai_comp_chat_name) prefs_api.openai_comp_chat_name = this.config.openai_comp_chat_name; + this.worker.postMessage({ type: 'init', openai_comp_host: prefs_api.openai_comp_host, @@ -142,6 +167,12 @@ anthropic_version: prefs_default.anthropic_version, anthropic_max_tokens: prefs_default.anthropic_max_tokens, }); + + if (this.config.anthropic_api_key) prefs_api.anthropic_api_key = this.config.anthropic_api_key; + if (this.config.anthropic_model) prefs_api.anthropic_model = this.config.anthropic_model; + if (this.config.anthropic_version) prefs_api.anthropic_version = this.config.anthropic_version; + if (this.config.anthropic_max_tokens) prefs_api.anthropic_max_tokens = this.config.anthropic_max_tokens; + this.worker.postMessage({ type: 'init', anthropic_api_key: prefs_api.anthropic_api_key, diff --git a/mzta-background.js b/mzta-background.js index ddfe6dff..e39bc0a1 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1084,7 +1084,8 @@ async function processEmails(messages, addTagsAuto, spamFilter) { prompt: specialFullPrompt_add_tags, llm: getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags'), custom_model: curr_prompt_add_tags.model ? curr_prompt_add_tags.model : '', - do_debug: prefs_aats.do_debug + do_debug: prefs_aats.do_debug, + config: curr_prompt_add_tags }); await cmd_addTags.initWorker(); let tags_current_email = []; @@ -1123,7 +1124,8 @@ async function processEmails(messages, addTagsAuto, spamFilter) { prompt: specialFullPrompt_spamfilter, llm: getConnectionType(prefs_aats, curr_prompt_spamfilter, 'spamfilter'), custom_model: curr_prompt_spamfilter.model ? curr_prompt_spamfilter.model : '', - do_debug: prefs_aats.do_debug + do_debug: prefs_aats.do_debug, + config: curr_prompt_spamfilter }); await cmd_spamfilter.initWorker(); let spamfilter_result = ''; diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index b297f225..fbecbfb6 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -63,9 +63,11 @@ const integration_settings_template = { connection_type: 'chatgpt_api', }; +const global_integration_settings = { ...integration_settings_template }; + for (const [integration, options] of Object.entries(integration_options_config)) { for (const [key, value] of Object.entries(options)) { - integration_settings_template[`${integration}_${key}`] = value; + global_integration_settings[`${integration}_${key}`] = value; } } @@ -93,7 +95,7 @@ export function getDynamicSettingValue(prefs, prefix, settingName) { } export const prefs_default = { - ...integration_settings_template, + ...global_integration_settings, do_debug: false, chatgpt_win_height: 800, chatgpt_win_width: 700, diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 3b19b2ab..485f6f1e 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -16,7 +16,10 @@ * along with this program. If not, see . */ -import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; +import { + prefs_default, + integration_options_config +} from '../../options/mzta-options-default.js'; import { OpenAI } from '../../js/api/openai_responses.js'; import { Ollama } from '../../js/api/ollama.js'; import { OpenAIComp } from '../../js/api/openai_comp.js' @@ -1002,19 +1005,19 @@ export async function initializeSpecificIntegrationUI({ // Helper to update prompt const _updatePrompt = async () => { let conntype = conntype_el.value; - let integration = conntype.replace('_api', ''); let prompt = await loadPrompt(promptId); if(!prompt) return; prompt.api = conntype; - if (integration_options_config[integration]) { - for (const key of Object.keys(integration_options_config[integration])) { - let elementId = `${model_prefix}${integration}_${key}`; + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + let propName = `${integration}_${key}`; + let elementId = `${model_prefix}${propName}`; let element = document.getElementById(elementId); if (element) { - prompt[key] = (element.type === 'checkbox') ? element.checked : element.value; + prompt[propName] = (element.type === 'checkbox') ? element.checked : element.value; } } } diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 17c3dffa..a39bd217 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -339,5 +339,23 @@ 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'); + + if (addtags_prompt) { + if (addtags_prompt.api && addtags_prompt.api !== '') { + getting['add_tags_connection_type'] = addtags_prompt.api; + } + 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) { + getting[`add_tags_${propName}`] = addtags_prompt[propName]; + } + } + } + } + setCurrentChoice(getting); } diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index 5f3c2fe5..a6f7d30e 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -42,21 +42,6 @@ document.addEventListener('DOMContentLoaded', async () => { let specialPrompts = await getSpecialPrompts(); let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); - if (spamfilter_prompt && spamfilter_prompt.api && spamfilter_prompt.api !== '') { - let update_prefs = {}; - update_prefs['spamfilter_connection_type'] = spamfilter_prompt.api; - - let integration = spamfilter_prompt.api.replace('_api', ''); - if (integration_options_config && integration_options_config[integration]) { - for (const key of Object.keys(integration_options_config[integration])) { - if (spamfilter_prompt[key] !== undefined) { - update_prefs[`spamfilter_${integration}_${key}`] = spamfilter_prompt[key]; - } - } - } - await browser.storage.sync.set(update_prefs); - } - await initializeSpecificIntegrationUI({ prefix: 'spamfilter', promptId: 'prompt_spamfilter', @@ -323,5 +308,23 @@ async function restoreOptions() { } let getting = await browser.storage.sync.get(prefs_default); + + let specialPrompts = await getSpecialPrompts(); + let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); + + if (spamfilter_prompt) { + if (spamfilter_prompt.api && spamfilter_prompt.api !== '') { + getting['spamfilter_connection_type'] = spamfilter_prompt.api; + } + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + if (spamfilter_prompt[propName] !== undefined) { + getting[`spamfilter_${propName}`] = spamfilter_prompt[propName]; + } + } + } + } + setCurrentChoice(getting); } From 1d8e955ba7a20e0f94906f41c9c2e83464d6f8ec Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 21:52:01 +0100 Subject: [PATCH 080/146] mzta_specialCommand class improved --- js/mzta-special-commands.js | 189 +++++++++++------------------------- 1 file changed, 57 insertions(+), 132 deletions(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index da63271c..95a0d14f 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -17,7 +17,10 @@ */ // Call the API to use a special prompt - import { prefs_default } from "../options/mzta-options-default.js"; + import { + prefs_default, + integration_options_config + } from "../options/mzta-options-default.js"; import { taLogger } from './mzta-logger.js'; export class mzta_specialCommand { @@ -45,146 +48,68 @@ this.config = config; this.logger = new taLogger('mzta_specialCommand', do_debug); this.do_debug = do_debug; - switch (this.llm) { - case "chatgpt_api": - this.worker = new Worker(new URL('./workers/model-worker-openai_responses.js', import.meta.url), { type: 'module' }); - break; - case "google_gemini_api": - this.worker = new Worker(new URL('./workers/model-worker-google_gemini.js', import.meta.url), { type: 'module' }); - break; - case "ollama_api": - this.worker = new Worker(new URL('./workers/model-worker-ollama.js', import.meta.url), { type: 'module' }); - break; - case "openai_comp_api": - this.worker = new Worker(new URL('./workers/model-worker-openai_comp.js', import.meta.url), { type: 'module' }); - break; - case "anthropic_api": - this.worker = new Worker(new URL('./workers/model-worker-anthropic.js', import.meta.url), { type: 'module' }); - break; - default: - this.logger.log("Invalid LLM type: " + this.llm); - throw new Error("Invalid LLM type: " + this.llm); + + const worker_path_map = { + chatgpt_api: './workers/model-worker-openai_responses.js', + google_gemini_api: './workers/model-worker-google_gemini.js', + ollama_api: './workers/model-worker-ollama.js', + openai_comp_api: './workers/model-worker-openai_comp.js', + anthropic_api: './workers/model-worker-anthropic.js', + }; + + const worker_path = worker_path_map[this.llm]; + if (worker_path) { + this.worker = new Worker(new URL(worker_path, import.meta.url), { type: 'module' }); + } else { + this.logger.log("Invalid LLM type: " + this.llm); + throw new Error("Invalid LLM type: " + this.llm); } } async initWorker() { - // console.log((">>>>>>>>>>>> this.custom_model: " + this.custom_model)); - switch (this.llm) { - case "chatgpt_api": { - let prefs_api = await browser.storage.sync.get({ - chatgpt_api_key: prefs_default.chatgpt_api_key, - chatgpt_model: prefs_default.chatgpt_model, - chatgpt_developer_messages: prefs_default.chatgpt_developer_messages, - }); + const integration = this.llm.replace('_api', ''); + const options_config = integration_options_config[integration]; - if (this.config.chatgpt_api_key) prefs_api.chatgpt_api_key = this.config.chatgpt_api_key; - if (this.config.chatgpt_model) prefs_api.chatgpt_model = this.config.chatgpt_model; - if (this.config.chatgpt_developer_messages) prefs_api.chatgpt_developer_messages = this.config.chatgpt_developer_messages; + if (!options_config) { + this.logger.error("Invalid integration type: " + integration); + throw new Error("Invalid integration type: " + integration); + } - this.worker.postMessage({ - type: 'init', - chatgpt_api_key: prefs_api.chatgpt_api_key, - chatgpt_model: this.custom_model != '' ? this.custom_model : prefs_api.chatgpt_model, - chatgpt_developer_messages: prefs_api.chatgpt_developer_messages, - do_debug: this.do_debug, - i18nStrings: '' - }); - break; + let prefsToGet = {}; + for (const key in options_config) { + const prefKey = `${integration}_${key}`; + prefsToGet[prefKey] = prefs_default[prefKey]; + } + + let prefs_api = await browser.storage.sync.get(prefsToGet); + + let workerInitMessage = { + type: 'init', + do_debug: this.do_debug, + i18nStrings: '' + }; + + for (const key in options_config) { + const prefKey = `${integration}_${key}`; + + const configValue = this.config[prefKey]; + + if (configValue !== undefined) { + if (typeof options_config[key] === 'boolean') { + prefs_api[prefKey] = (configValue === true || configValue === 'true' || configValue === 1); + } else { + prefs_api[prefKey] = configValue; + } } - case "google_gemini_api": { - let prefs_api = await browser.storage.sync.get({ - google_gemini_api_key: prefs_default.google_gemini_api_key, - google_gemini_model: prefs_default.google_gemini_model, - google_gemini_system_instruction: prefs_default.google_gemini_system_instruction, - google_gemini_thinking_budget: prefs_default.google_gemini_thinking_budget, - }); - - if (this.config.google_gemini_api_key) prefs_api.google_gemini_api_key = this.config.google_gemini_api_key; - if (this.config.google_gemini_model) prefs_api.google_gemini_model = this.config.google_gemini_model; - if (this.config.google_gemini_system_instruction) prefs_api.google_gemini_system_instruction = this.config.google_gemini_system_instruction; - if (this.config.google_gemini_thinking_budget) prefs_api.google_gemini_thinking_budget = this.config.google_gemini_thinking_budget; - - this.worker.postMessage({ - type: 'init', - google_gemini_api_key: prefs_api.google_gemini_api_key, - google_gemini_model: this.custom_model != '' ? this.custom_model : prefs_api.google_gemini_model, - google_gemini_system_instruction: prefs_api.google_gemini_system_instruction, - google_gemini_thinking_budget: prefs_api.google_gemini_thinking_budget, - do_debug: this.do_debug, - i18nStrings: '' - }); - break; - } - case "ollama_api": { - let prefs_api = await browser.storage.sync.get({ - ollama_host: prefs_default.ollama_host, - ollama_model: prefs_default.ollama_model, - }); - - if (this.config.ollama_host) prefs_api.ollama_host = this.config.ollama_host; - if (this.config.ollama_model) prefs_api.ollama_model = this.config.ollama_model; - - this.worker.postMessage({ - type: 'init', - ollama_host: prefs_api.ollama_host, - ollama_model: this.custom_model != '' ? this.custom_model : prefs_api.ollama_model, - do_debug: this.do_debug, - i18nStrings: '' - }); - break; - } - case "openai_comp_api": { - let prefs_api = await browser.storage.sync.get({ - openai_comp_host: prefs_default.openai_comp_host, - openai_comp_model: prefs_default.openai_comp_model, - openai_comp_api_key: prefs_default.openai_comp_api_key, - openai_comp_use_v1: prefs_default.openai_comp_use_v1, - openai_comp_chat_name: prefs_default.openai_comp_chat_name, - do_debug: prefs_default.do_debug, - }); - - if (this.config.openai_comp_host) prefs_api.openai_comp_host = this.config.openai_comp_host; - if (this.config.openai_comp_model) prefs_api.openai_comp_model = this.config.openai_comp_model; - if (this.config.openai_comp_api_key) prefs_api.openai_comp_api_key = this.config.openai_comp_api_key; - if (this.config.openai_comp_use_v1 !== undefined) prefs_api.openai_comp_use_v1 = this.config.openai_comp_use_v1; - if (this.config.openai_comp_chat_name) prefs_api.openai_comp_chat_name = this.config.openai_comp_chat_name; - - this.worker.postMessage({ - type: 'init', - openai_comp_host: prefs_api.openai_comp_host, - openai_comp_model: this.custom_model != '' ? this.custom_model : prefs_api.openai_comp_model, - openai_comp_api_key: prefs_api.openai_comp_api_key, - openai_comp_use_v1: prefs_api.openai_comp_use_v1, - do_debug: this.do_debug, - i18nStrings: '' - }); - break; - } - case "anthropic_api": { - let prefs_api = await browser.storage.sync.get({ - anthropic_api_key: prefs_default.anthropic_api_key, - anthropic_model: prefs_default.anthropic_model, - anthropic_version: prefs_default.anthropic_version, - anthropic_max_tokens: prefs_default.anthropic_max_tokens, - }); - - if (this.config.anthropic_api_key) prefs_api.anthropic_api_key = this.config.anthropic_api_key; - if (this.config.anthropic_model) prefs_api.anthropic_model = this.config.anthropic_model; - if (this.config.anthropic_version) prefs_api.anthropic_version = this.config.anthropic_version; - if (this.config.anthropic_max_tokens) prefs_api.anthropic_max_tokens = this.config.anthropic_max_tokens; - - this.worker.postMessage({ - type: 'init', - anthropic_api_key: prefs_api.anthropic_api_key, - anthropic_model: this.custom_model != '' ? this.custom_model : prefs_api.anthropic_model, - anthropic_version: prefs_api.anthropic_version, - anthropic_max_tokens: prefs_api.anthropic_max_tokens, - do_debug: this.do_debug, - i18nStrings: '' - }); - break; + + if (key === 'model') { + workerInitMessage[prefKey] = this.custom_model !== '' ? this.custom_model : prefs_api[prefKey]; + } else { + workerInitMessage[prefKey] = prefs_api[prefKey]; } } + + this.worker.postMessage(workerInitMessage); } sendPrompt(){ From 7f2c3b422f1a933d7b008d8a8f3bbbf248c59025 Mon Sep 17 00:00:00 2001 From: mic Date: Thu, 1 Jan 2026 22:15:01 +0100 Subject: [PATCH 081/146] working on custom prompt ui. see #102 --- pages/customprompts/mzta-custom-prompts.css | 24 +++++++++ pages/customprompts/mzta-custom-prompts.js | 57 ++++++++++++++++----- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.css b/pages/customprompts/mzta-custom-prompts.css index 888459df..0346bab2 100644 --- a/pages/customprompts/mzta-custom-prompts.css +++ b/pages/customprompts/mzta-custom-prompts.css @@ -302,6 +302,20 @@ input.input_additional[type="text"]{ cursor: pointer; } +.api_additional_info{ + cursor: pointer; + text-align: center; + background-color: #409df3; +} + +.api_additional_info_toggle{ + text-align: center; + padding: 5px; + background-color: #409df3; + cursor: pointer; + display: none;; +} + @media (prefers-color-scheme: dark) { body { background-color: #1C1B22; @@ -357,4 +371,14 @@ input.input_additional[type="text"]{ #chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{ background-color: rgb(88, 25, 0); } + + .api_additional_info, .api_additional_info_toggle{ + background-color: #0f2437; + } + + @media (prefers-color-scheme: dark) { + .api_key-container .toggle-icon img { + filter: invert(1); + } + } } \ No newline at end of file diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 93d3beea..d24c26e9 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -128,18 +128,28 @@ document.addEventListener('DOMContentLoaded', async () => { i18n.updateDocument(); // Inject API Configuration UI for New Prompt - const webToggle = document.getElementById('chatgpt_web_additional_info_toggle'); - + const webToggle = document.getElementById('chatgpt_web_additional_info_toggle'); // Assuming this exists + const apiSettingsToggle = document.createElement('tr'); apiSettingsToggle.id = 'api_additional_info_toggle'; - apiSettingsToggle.className = 'small_info'; + apiSettingsToggle.className = 'small_info api_additional_info'; apiSettingsToggle.style.cursor = 'pointer'; - apiSettingsToggle.innerHTML = '' + browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; - + + const tdToggle = document.createElement('td'); + tdToggle.colSpan = '5'; + const spanToggle = document.createElement('span'); + spanToggle.textContent = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; + tdToggle.appendChild(spanToggle); + apiSettingsToggle.appendChild(tdToggle); + const apiSettingsRow = document.createElement('tr'); apiSettingsRow.id = 'api_additional_info'; apiSettingsRow.style.display = 'none'; - apiSettingsRow.innerHTML = ''; + + const tdRow = document.createElement('td'); + tdRow.colSpan = '5'; + tdRow.id = 'api_ui_container'; + apiSettingsRow.appendChild(tdRow); webToggle.parentNode.insertBefore(apiSettingsToggle, webToggle.nextSibling); webToggle.parentNode.insertBefore(apiSettingsRow, apiSettingsToggle.nextSibling); @@ -156,8 +166,31 @@ document.addEventListener('DOMContentLoaded', async () => { }); const apiTable = document.createElement('table'); - apiTable.style.width = "100%"; - apiTable.innerHTML = '' + browser.i18n.getMessage('prefs_Connection_type') + ':'; + apiTable.style.width = '100%'; + apiTable.style.textAlign = 'left'; + + const tr = document.createElement('tr'); + tr.id = 'api_ui_anchor'; + + const td1 = document.createElement('td'); + td1.classList.add('w30'); + td1.textContent = browser.i18n.getMessage('prefs_Connection_type') + ':'; + + const td2 = document.createElement('td'); + + const select = document.createElement('select'); + select.id = 'new_prompt_api_type'; + select.classList.add('input_new'); + + const option = document.createElement('option'); + option.value = ''; + option.textContent = '-- ' + browser.i18n.getMessage('Custom') + ' --'; + select.appendChild(option); + + td2.appendChild(select); + tr.appendChild(td1); + tr.appendChild(td2); + apiTable.appendChild(tr); document.getElementById('api_ui_container').appendChild(apiTable); await injectConnectionUI({ @@ -223,7 +256,7 @@ document.addEventListener('DOMContentLoaded', async () => { }); }); - switch(prefs.connection_type) { + // switch(prefs.connection_type) { // case 'chatgpt_api': // document.getElementById('chatgpt_api').style.display = 'block'; // break; @@ -236,7 +269,7 @@ document.addEventListener('DOMContentLoaded', async () => { // case 'google_gemini_api': // document.getElementById('google_gemini_api').style.display = 'block'; // break; - } + // } const chatgptWebAdditionalPropToggle = document.getElementById('chatgpt_web_additional_info_toggle'); chatgptWebAdditionalPropToggle.addEventListener('click', (e) => { @@ -881,8 +914,8 @@ function loadPromptsList(values){
    __MSG_prefs_OptionText_CustomGPT_Warn__
    __MSG_customPrompts_show_additional_info__ [API]
    -
    - +
    From 0fb95121a44569dde3f160d7bde5b00b210a2a9a Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 09:44:50 +0100 Subject: [PATCH 082/146] css correctly imported. labels width fixed. see #102 --- pages/_lib/connection-ui.css | 4 ++++ pages/customprompts/mzta-custom-prompts.css | 5 ----- pages/customprompts/mzta-custom-prompts.html | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/_lib/connection-ui.css b/pages/_lib/connection-ui.css index 5b63569d..b4501afc 100644 --- a/pages/_lib/connection-ui.css +++ b/pages/_lib/connection-ui.css @@ -37,6 +37,10 @@ textarea.option-textarea{ height: 10em; } +label{ + width: -moz-available; +} + .api_key-container { position: relative; width: 100%; diff --git a/pages/customprompts/mzta-custom-prompts.css b/pages/customprompts/mzta-custom-prompts.css index 0346bab2..78ccf3e3 100644 --- a/pages/customprompts/mzta-custom-prompts.css +++ b/pages/customprompts/mzta-custom-prompts.css @@ -376,9 +376,4 @@ input.input_additional[type="text"]{ background-color: #0f2437; } - @media (prefers-color-scheme: dark) { - .api_key-container .toggle-icon img { - filter: invert(1); - } - } } \ No newline at end of file diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index cedae75c..239375fd 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -4,6 +4,7 @@ ThunderAI - __MSG_customPrompts_managePrompts__ + From 33fdd0cc9b2e2bc8e61e3993fa6ecea0028d6a19 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 09:54:04 +0100 Subject: [PATCH 083/146] correctyl showing and hiding api settings elements. see #102 --- pages/_lib/connection-ui.js | 16 ++++++++-------- pages/customprompts/mzta-custom-prompts.js | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 485f6f1e..f5d39800 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -1132,28 +1132,28 @@ export function showConnectionOptions(conntype_select, modelId_prefix = '') { }else{ anthropic_api_display = 'none'; } - document.querySelectorAll(".conntype_chatgpt_web").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_chatgpt_web").forEach(element => { element.style.display = chatgpt_web_display; }); - document.querySelectorAll(".conntype_chatgpt_api").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_chatgpt_api").forEach(element => { element.style.display = chatgpt_api_display; }); - document.querySelectorAll(".conntype_ollama_api").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_ollama_api").forEach(element => { element.style.display = ollama_api_display; }); - document.querySelectorAll(".conntype_openai_comp_api").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_openai_comp_api").forEach(element => { element.style.display = openai_comp_api_display; }); - document.querySelectorAll(".conntype_google_gemini_api").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_google_gemini_api").forEach(element => { element.style.display = google_gemini_api_display; }); - document.querySelectorAll(".conntype_anthropic_api").forEach(element => { + parent.parentElement.querySelectorAll(".conntype_anthropic_api").forEach(element => { element.style.display = anthropic_api_display; }); if (varConnectionUI.permission_all_urls) { - const openaiCompWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning'); + const openaiCompWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'openai_comp_api_cors_warning'); if (openaiCompWarning) openaiCompWarning.style.display = 'none'; - const ollamaWarning = document.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning'); + const ollamaWarning = parent.parentElement.getElementById((modelId_prefix ? modelId_prefix : '') + 'ollama_api_cors_warning'); if (ollamaWarning) ollamaWarning.style.display = 'none'; } } diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index d24c26e9..33d2159c 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -245,13 +245,13 @@ document.addEventListener('DOMContentLoaded', async () => { document.querySelectorAll('.api_additional_info_toggle').forEach(element => { element.addEventListener('click', (e) => { e.preventDefault(); - let additionalInfoRow = e.target.closest('td').querySelector('.api_additional_info'); + let additionalInfoRow = element.nextElementSibling; if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') { additionalInfoRow.style.display = 'block'; - e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [API]'; + element.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [API]'; } else { additionalInfoRow.style.display = 'none'; - e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; + element.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; } }); }); From a96e87e95a1a52f5ae1a69742e6874140fcf76e5 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 10:02:34 +0100 Subject: [PATCH 084/146] missing string added --- pages/customprompts/mzta-custom-prompts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 33d2159c..927242a1 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -224,7 +224,7 @@ document.addEventListener('DOMContentLoaded', async () => { let additionalInfoRow = e.target.closest('td').querySelector('.chatgpt_web_additional_info'); if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') { additionalInfoRow.style.display = 'block'; - e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info'); + e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [ChatGPT Web]'; } else { additionalInfoRow.style.display = 'none'; e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [ChatGPT Web]'; From 07f5c699a42e04f28c6d167d431c65c50d2112ac Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 10:04:07 +0100 Subject: [PATCH 085/146] useless switch converted to if --- pages/customprompts/mzta-custom-prompts.js | 47 ++++++++++------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 927242a1..2fcdeaea 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -213,32 +213,29 @@ document.addEventListener('DOMContentLoaded', async () => { }); showConnectionOptions(apiSelect); - switch(prefs.connection_type) { - case 'chatgpt_web': { - // for the new item form - document.getElementById('chatgpt_web_additional_info_toggle').style.display = 'table-row'; - // for the edit list items form - document.querySelectorAll('.chatgpt_web_additional_info_toggle').forEach(element => { - element.addEventListener('click', (e) => { - e.preventDefault(); - let additionalInfoRow = e.target.closest('td').querySelector('.chatgpt_web_additional_info'); - if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') { - additionalInfoRow.style.display = 'block'; - e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [ChatGPT Web]'; - } else { - additionalInfoRow.style.display = 'none'; - e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [ChatGPT Web]'; - } - }); + if(prefs.connection_type == 'chatgpt_web') { + // for the new item form + document.getElementById('chatgpt_web_additional_info_toggle').style.display = 'table-row'; + // for the edit list items form + document.querySelectorAll('.chatgpt_web_additional_info_toggle').forEach(element => { + element.addEventListener('click', (e) => { + e.preventDefault(); + let additionalInfoRow = e.target.closest('td').querySelector('.chatgpt_web_additional_info'); + if (additionalInfoRow.style.display === 'none' || additionalInfoRow.style.display === '') { + additionalInfoRow.style.display = 'block'; + e.target.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [ChatGPT Web]'; + } else { + additionalInfoRow.style.display = 'none'; + e.target.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [ChatGPT Web]'; + } }); - document.querySelectorAll('input.chatgpt_web_project_output').forEach(element => { - element.addEventListener("input", validateCustomData_ChatGPTWeb); - }); - document.querySelectorAll('input.chatgpt_web_custom_gpt_output').forEach(element => { - element.addEventListener("input", validateCustomData_ChatGPTWeb); - }); - break; - } + }); + document.querySelectorAll('input.chatgpt_web_project_output').forEach(element => { + element.addEventListener("input", validateCustomData_ChatGPTWeb); + }); + document.querySelectorAll('input.chatgpt_web_custom_gpt_output').forEach(element => { + element.addEventListener("input", validateCustomData_ChatGPTWeb); + }); } // for the edit list items form [API] From b796b3deecf364910dcc2feda327d2427f66e652 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 10:13:55 +0100 Subject: [PATCH 086/146] api settings in new form are now defined in the html page. see #102 --- pages/customprompts/mzta-custom-prompts.html | 9 +++++++ pages/customprompts/mzta-custom-prompts.js | 28 ++------------------ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index 239375fd..e8ee229e 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -102,6 +102,15 @@
    __MSG_prefs_OptionText_chatgpt_web_custom_data_info2__ +
    + + + + +
    + __MSG_customPrompts_show_additional_info__ [API] +
    * __MSG_customPrompts_form_required_fields__

    diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 2fcdeaea..17ce201e 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -127,32 +127,8 @@ document.addEventListener('DOMContentLoaded', async () => { i18n.updateDocument(); - // Inject API Configuration UI for New Prompt - const webToggle = document.getElementById('chatgpt_web_additional_info_toggle'); // Assuming this exists - - const apiSettingsToggle = document.createElement('tr'); - apiSettingsToggle.id = 'api_additional_info_toggle'; - apiSettingsToggle.className = 'small_info api_additional_info'; - apiSettingsToggle.style.cursor = 'pointer'; - - const tdToggle = document.createElement('td'); - tdToggle.colSpan = '5'; - const spanToggle = document.createElement('span'); - spanToggle.textContent = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; - tdToggle.appendChild(spanToggle); - apiSettingsToggle.appendChild(tdToggle); - - const apiSettingsRow = document.createElement('tr'); - apiSettingsRow.id = 'api_additional_info'; - apiSettingsRow.style.display = 'none'; - - const tdRow = document.createElement('td'); - tdRow.colSpan = '5'; - tdRow.id = 'api_ui_container'; - apiSettingsRow.appendChild(tdRow); - - webToggle.parentNode.insertBefore(apiSettingsToggle, webToggle.nextSibling); - webToggle.parentNode.insertBefore(apiSettingsRow, apiSettingsToggle.nextSibling); + const apiSettingsToggle = document.getElementById('api_additional_info_toggle'); + const apiSettingsRow = document.getElementById('api_additional_info'); apiSettingsToggle.addEventListener('click', (e) => { e.preventDefault(); From 92fba4a1b31fbb40af919e3c534054907cc55fb2 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 10:14:53 +0100 Subject: [PATCH 087/146] comments improved --- pages/customprompts/mzta-custom-prompts.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index e8ee229e..23ee4672 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -102,12 +102,12 @@
    __MSG_prefs_OptionText_chatgpt_web_custom_data_info2__ - + __MSG_customPrompts_show_additional_info__ [API] - + From 56362266e267efe003bc8c42b446b1eb7ff90726 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 10:21:47 +0100 Subject: [PATCH 088/146] the api settings table container is now in the html page. see #102 --- pages/customprompts/mzta-custom-prompts.html | 6 +++- pages/customprompts/mzta-custom-prompts.js | 32 ++------------------ 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index 23ee4672..a364fdd4 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -109,7 +109,11 @@ - + + + +
    +
    * __MSG_customPrompts_form_required_fields__
    diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 17ce201e..8e3f4811 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -125,8 +125,6 @@ document.addEventListener('DOMContentLoaded', async () => { }); }); - i18n.updateDocument(); - const apiSettingsToggle = document.getElementById('api_additional_info_toggle'); const apiSettingsRow = document.getElementById('api_additional_info'); @@ -141,34 +139,6 @@ document.addEventListener('DOMContentLoaded', async () => { } }); - const apiTable = document.createElement('table'); - apiTable.style.width = '100%'; - apiTable.style.textAlign = 'left'; - - const tr = document.createElement('tr'); - tr.id = 'api_ui_anchor'; - - const td1 = document.createElement('td'); - td1.classList.add('w30'); - td1.textContent = browser.i18n.getMessage('prefs_Connection_type') + ':'; - - const td2 = document.createElement('td'); - - const select = document.createElement('select'); - select.id = 'new_prompt_api_type'; - select.classList.add('input_new'); - - const option = document.createElement('option'); - option.value = ''; - option.textContent = '-- ' + browser.i18n.getMessage('Custom') + ' --'; - select.appendChild(option); - - td2.appendChild(select); - tr.appendChild(td1); - tr.appendChild(td2); - apiTable.appendChild(tr); - document.getElementById('api_ui_container').appendChild(apiTable); - await injectConnectionUI({ afterTrId: 'api_ui_anchor', selectId: 'new_prompt_api_type', @@ -176,6 +146,8 @@ document.addEventListener('DOMContentLoaded', async () => { taLog: taLog }); + i18n.updateDocument(); + const apiSelect = document.getElementById('new_prompt_api_type'); // Remove chatgpt_web // for (let i = 0; i < apiSelect.options.length; i++) { From 163bbdc0557efe0224477ea68011d91c78a3c15b Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 12:09:00 +0100 Subject: [PATCH 089/146] now loading default API settings if needed. see #593 --- pages/customprompts/mzta-custom-prompts.js | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 8e3f4811..99fa14f5 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -60,7 +60,8 @@ let autocompleteSuggestions = []; document.addEventListener('DOMContentLoaded', async () => { - prefs = await browser.storage.sync.get({ connection_type:prefs_default.connection_type, do_debug: prefs_default.do_debug }); + let storedPrefs = await browser.storage.sync.get(null); + prefs = { ...prefs_default, ...storedPrefs }; taLog = new taLogger("mzta-custom-prompts", prefs.do_debug); setStorageSpace(); @@ -146,6 +147,21 @@ document.addEventListener('DOMContentLoaded', async () => { taLog: taLog }); + // Fill defaults for new prompt form + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + const inputEl = document.getElementById(propName); + if (inputEl && prefs[propName] !== undefined) { + if (inputEl.type === 'checkbox') { + inputEl.checked = (prefs[propName] === true || prefs[propName] === 'true'); + } else { + inputEl.value = prefs[propName]; + } + } + } + } + i18n.updateDocument(); const apiSelect = document.getElementById('new_prompt_api_type'); @@ -507,7 +523,14 @@ function populateConnectionUI(tr, id, prefix, selectId) { const inputId = `${prefix}${propName}`; const inputEl = document.getElementById(inputId); if (inputEl) { - inputEl.type === 'checkbox' ? inputEl.checked = (itemValues[propName] === true || itemValues[propName] === 'true') : inputEl.value = itemValues[propName] || ''; + let val = itemValues[propName]; + // Use default if undefined or empty string (for text inputs) + if (val === undefined || (inputEl.type !== 'checkbox' && val === '')) { + if (prefs[propName] !== undefined) { + val = prefs[propName]; + } + } + inputEl.type === 'checkbox' ? inputEl.checked = (val === true || val === 'true') : inputEl.value = val || ''; } } } From c18a517b82916b4166c599951eb187e313fb2b91 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 12:13:00 +0100 Subject: [PATCH 090/146] css fix. see #102 --- pages/_lib/connection-ui.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/_lib/connection-ui.css b/pages/_lib/connection-ui.css index b4501afc..4953888b 100644 --- a/pages/_lib/connection-ui.css +++ b/pages/_lib/connection-ui.css @@ -15,7 +15,7 @@ tr.conntype_openai_comp_api, tr.conntype_openai_comp_api2{ } tr.conntype_google_gemini_api, tr.conntype_google_gemini_api2{ - background-color: rgb(233, 238, 169); + background-color: rgb(233, 238, 169) !important; } tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ @@ -109,7 +109,7 @@ span.opt_title{ } tr.conntype_google_gemini_api, tr.conntype_google_gemini_api2{ - background-color: rgb(72, 77, 3); + background-color: rgb(72, 77, 3) !important; } tr.conntype_anthropic_api, tr.conntype_anthropic_api2{ From ae83e3284e575e6aa74531710e541f5461856657 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 12:17:10 +0100 Subject: [PATCH 091/146] correctyl updating the UI wornings. see #102 --- pages/customprompts/mzta-custom-prompts.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 99fa14f5..8753c018 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -29,7 +29,8 @@ import { } from "../../js/mzta-prompts.js"; import { injectConnectionUI, - showConnectionOptions + showConnectionOptions, + updateWarnings } from "../../pages/_lib/connection-ui.js"; import { ChatGPTWeb_models, @@ -491,9 +492,11 @@ function handleEditClick(e) { taLog: taLog }).then(() => { populateConnectionUI(tr, id, prefix, selectId); + updateWarnings(prefix); }); } else { populateConnectionUI(tr, id, prefix, selectId); + updateWarnings(prefix); } // Show/Hide buttons From 3ebbaf184ba7d77a3c610cad6dd02ee20684f303 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 12:33:53 +0100 Subject: [PATCH 092/146] reset button added. see #102 --- pages/_lib/connection-ui.js | 17 +++++++++++++++-- pages/customprompts/mzta-custom-prompts.js | 10 +++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index f5d39800..550a1491 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -44,7 +44,9 @@ export async function injectConnectionUI({ no_chatgpt_web = false, defaultType = '', tr_class = '', - taLog = console + taLog = console, + customButtonLabel = '', + customButtonCallback = null } = {}) { const anchorTr = document.getElementById(afterTrId); @@ -74,8 +76,9 @@ export async function injectConnectionUI({ -
    -
    __MSG_customPrompts_show_additional_info_show__ [API] -
    __MSG_prefs_Connection_type__:` + values.api_type + `
    +
    +
    __MSG_prefs_Connection_type__:
    ` + values.api_type + `
    From 94d1647c3515f35935f45302b0224c4ef3045ad3 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 17:51:13 +0100 Subject: [PATCH 098/146] correctly showing the specific api on confirm. see #102 --- pages/customprompts/mzta-custom-prompts.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index c364d929..b9560e62 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -801,6 +801,12 @@ function handleConfirmClick(e) { tr.querySelector('.type_show').innerText = tr.querySelector('.type_output').selectedOptions[0].text; tr.querySelector('.action').innerText = tr.querySelector('.action_output').value; tr.querySelector('.action_show').innerText = tr.querySelector('.action_output').selectedOptions[0].text; + if (newValues.api_type !== '') { + tr.querySelector('.api_type_show').innerText = newValues.api_type; + tr.querySelector('.api_additional_info_show').style.display = 'block'; + tr.querySelector('.api_additional_info_row').style.display = 'block'; + + } // the checkboxes update is handled directly by themselves hideItemRowEditor(tr); setSomethingChanged(); From c1368fdf442ed7aabb6cd1ba6e4e4dea479b33e9 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 18:04:29 +0100 Subject: [PATCH 099/146] various css fixses. see #102 --- pages/customprompts/mzta-custom-prompts.css | 24 +++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.css b/pages/customprompts/mzta-custom-prompts.css index b0a341cd..16e997ff 100644 --- a/pages/customprompts/mzta-custom-prompts.css +++ b/pages/customprompts/mzta-custom-prompts.css @@ -60,7 +60,7 @@ table.prompts_list th { table td { border: 1px solid #ddd; - padding: 8px; + padding: 5px; } table td.w08{ @@ -229,7 +229,6 @@ label, .id_show, .text_show, .name_show, .type_show, .action_show{ } #chatgpt_web_additional_info_toggle td{ - padding:0px 5px; font-style: italic; } @@ -271,7 +270,7 @@ label, .id_show, .text_show, .name_show, .type_show, .action_show{ .chatgpt_web_additional_info_toggle{ width: -moz-available; text-align: center; - margin-top: 10px; + padding:5px; } .chatgpt_web_additional_info_show{ @@ -308,12 +307,17 @@ input.input_additional[type="text"]{ background-color: #409df3; } +#api_additional_info_toggle{ + font-style: italic; +} + .api_additional_info_toggle{ text-align: center; padding: 5px; background-color: #409df3; cursor: pointer; - display: none;; + display: none; + font-style: italic; } .api_additional_info_show{ @@ -323,7 +327,12 @@ input.input_additional[type="text"]{ height: 100%; padding: 3px; margin-top: 5px; - background-color: #409df3; + background-color: rgb(64, 157, 243); +} + +#api_additional_info_toggle:hover, .api_additional_info_toggle:hover{ + background-color: rgb(64, 137, 213); + text-decoration: underline; } @media (prefers-color-scheme: dark) { @@ -375,7 +384,6 @@ input.input_additional[type="text"]{ #chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show, .chatgpt_web_models_list_table{ background-color: rgb(39, 11, 0); - color: rgb(182, 182, 182); } #chatgpt_web_additional_info_toggle:hover, .chatgpt_web_additional_info_toggle:hover{ @@ -385,4 +393,8 @@ input.input_additional[type="text"]{ .api_additional_info, .api_additional_info_toggle, .api_additional_info_show{ background-color: #0f2437; } + + #api_additional_info_toggle:hover, .api_additional_info_toggle:hover{ + background-color: #1b456d + } } \ No newline at end of file From 9840b0f2658e3b6e1012a8f96e15aad352c43113 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 18:07:08 +0100 Subject: [PATCH 100/146] labels fixed. see #102 --- pages/customprompts/mzta-custom-prompts.html | 2 +- pages/customprompts/mzta-custom-prompts.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index a364fdd4..1ec1d4bb 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -80,7 +80,7 @@ - __MSG_customPrompts_show_additional_info__ + __MSG_customPrompts_show_additional_info__ [ChatGPT Web] diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index b9560e62..8cc4ede7 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -881,7 +881,7 @@ function loadPromptsList(values){
    -
    __MSG_customPrompts_show_additional_info__
    +
    __MSG_customPrompts_show_additional_info__ [ChatGPT Web]
    __MSG_prefs_OptionText_chatgpt_web_model__:
    From 00e415b40fc67e49f23920309702e6041159b230 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 18:08:01 +0100 Subject: [PATCH 101/146] italic removed. see #102 --- pages/customprompts/mzta-custom-prompts.css | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.css b/pages/customprompts/mzta-custom-prompts.css index 16e997ff..5ff45b45 100644 --- a/pages/customprompts/mzta-custom-prompts.css +++ b/pages/customprompts/mzta-custom-prompts.css @@ -228,10 +228,6 @@ label, .id_show, .text_show, .name_show, .type_show, .action_show{ padding-right: 2px; } -#chatgpt_web_additional_info_toggle td{ - font-style: italic; -} - #chatgpt_web_additional_info, #chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info, .chatgpt_web_additional_info_toggle, .chatgpt_web_additional_info_show{ background-color: rgb(255, 209, 183); display:none; @@ -307,17 +303,12 @@ input.input_additional[type="text"]{ background-color: #409df3; } -#api_additional_info_toggle{ - font-style: italic; -} - .api_additional_info_toggle{ text-align: center; padding: 5px; background-color: #409df3; cursor: pointer; display: none; - font-style: italic; } .api_additional_info_show{ From 82629fb4954e1c5731f850b4a6d174fcc9705642 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 18:15:44 +0100 Subject: [PATCH 102/146] missing strings fixed. see #102 --- pages/customprompts/mzta-custom-prompts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 8cc4ede7..b82086bb 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -241,13 +241,13 @@ document.addEventListener('DOMContentLoaded', async () => { additionalInfoRow.style.display = 'table-row'; let subspan = chatgptWebAdditionalPropToggle.querySelector('td span'); if (subspan) { - subspan.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info'); + subspan.innerText = browser.i18n.getMessage('customPrompts_hide_additional_info') + ' [ChatGPT Web]'; } } else { additionalInfoRow.style.display = 'none'; let subspan = chatgptWebAdditionalPropToggle.querySelector('td span'); if (subspan) { - subspan.innerText = browser.i18n.getMessage('customPrompts_show_additional_info'); + subspan.innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [ChatGPT Web]'; } } }); From 1362da944e1d3770d4ca4330c605df6e28419b8c Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 22:10:29 +0100 Subject: [PATCH 103/146] correctly using the toggleApiPropertiesShow method. see #102 --- pages/customprompts/mzta-custom-prompts.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index b82086bb..5c4a286f 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -753,8 +753,7 @@ function handleCancelClick(e) { tr.querySelector('.chatgpt_web_project_output').value = tr.querySelector('.chatgpt_web_project_show').innerText; tr.querySelector('.chatgpt_web_custom_gpt_output').value = tr.querySelector('.chatgpt_web_custom_gpt_show').innerText; tr.querySelector('.api_additional_info_toggle').innerText = browser.i18n.getMessage('customPrompts_show_additional_info') + ' [API]'; - tr.querySelector('.api_additional_info_show').style.display = 'block'; - + toggleApiPropertiesShow(tr); hideItemRowEditor(tr); } @@ -803,8 +802,7 @@ function handleConfirmClick(e) { tr.querySelector('.action_show').innerText = tr.querySelector('.action_output').selectedOptions[0].text; if (newValues.api_type !== '') { tr.querySelector('.api_type_show').innerText = newValues.api_type; - tr.querySelector('.api_additional_info_show').style.display = 'block'; - tr.querySelector('.api_additional_info_row').style.display = 'block'; + toggleApiPropertiesShow(tr); } // the checkboxes update is handled directly by themselves From c7c5d0c59478a9b327f6fbd2c85cafc88c8a4452 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 22:30:44 +0100 Subject: [PATCH 104/146] correctly handling chatgpt additional props show. see #102 --- pages/customprompts/mzta-custom-prompts.js | 94 ++++++++-------------- 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 5c4a286f..f2997c45 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -218,21 +218,6 @@ document.addEventListener('DOMContentLoaded', async () => { }); }); - // switch(prefs.connection_type) { - // case 'chatgpt_api': - // document.getElementById('chatgpt_api').style.display = 'block'; - // break; - // case 'ollama_api': - // document.getElementById('ollama_api').style.display = 'block'; - // break; - // case 'openai_comp_api': - // document.getElementById('openai_comp_api').style.display = 'block'; - // break; - // case 'google_gemini_api': - // document.getElementById('google_gemini_api').style.display = 'block'; - // break; - // } - const chatgptWebAdditionalPropToggle = document.getElementById('chatgpt_web_additional_info_toggle'); chatgptWebAdditionalPropToggle.addEventListener('click', (e) => { e.preventDefault(); @@ -476,7 +461,7 @@ document.getElementById('btnManageCustomDataPH').addEventListener('click', () => function handleEditClick(e) { e.preventDefault(); const tr = e.target.parentNode.parentNode; - const id = tr.querySelector('.id_output').value; + const id = tr.querySelector('.id_output').value.toLowerCase(); // Inject Connection UI if needed const anchorId = `api_ui_anchor_${id}`; @@ -516,6 +501,7 @@ function handleEditClick(e) { tr.querySelector('.btnDeleteItem').style.display = 'none'; // Delete btn showItemRowEditor(tr); toggleDiffviewer(e); + toggleAdditionalPropertiesShow(tr); } function populateConnectionUI(tr, id, prefix, selectId) { @@ -599,50 +585,40 @@ function hideItemRowEditor(tr) { } function toggleAdditionalPropertiesShow(tr) { - switch(prefs.connection_type) { - case 'chatgpt_web': { - let element = tr.querySelector('.chatgpt_web_additional_info_show'); - let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show'); - let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show'); - let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show'); - - if ((chatGPTWebModel_show.innerText !== '' && chatGPTWebModel_show.innerText !== 'undefined') || - (chatGPTWebProject_show.innerText !== '' && chatGPTWebProject_show.innerText !== 'undefined') || - (chatGPTWebCustomGPT_show.innerText !== '' && chatGPTWebCustomGPT_show.innerText !== 'undefined')) { - element.style.display = 'flex'; - } else { - element.style.display = 'none'; - } - - if(chatGPTWebModel_show.innerText === '' || chatGPTWebModel_show.innerText === 'undefined') { - chatGPTWebModel_show.parentNode.style.display = 'none'; - } else { - chatGPTWebModel_show.parentNode.style.display = 'inline'; - } - if(chatGPTWebProject_show.innerText === '' || chatGPTWebProject_show.innerText === 'undefined') { - chatGPTWebProject_show.parentNode.style.display = 'none'; - } else { - chatGPTWebProject_show.parentNode.style.display = 'inline'; - } - if(chatGPTWebCustomGPT_show.innerText === '' || chatGPTWebCustomGPT_show.innerText === 'undefined') { - chatGPTWebCustomGPT_show.parentNode.style.display = 'none'; - } else { - chatGPTWebCustomGPT_show.parentNode.style.display = 'inline'; - } - break; + // console.log(">>>>>>>>>>>>>>>>> toggleAdditionalPropertiesShow tr.querySelector('.api_type_show').innerText: " + tr.querySelector('.api_type_show').innerText); + let element = tr.querySelector('.chatgpt_web_additional_info_show'); + let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show'); + let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show'); + let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show'); + if(prefs.connection_type == 'chatgpt_web' && tr.querySelector('.api_type_show').innerText == '') { + if ((chatGPTWebModel_show.innerText !== '' && chatGPTWebModel_show.innerText !== 'undefined') || + (chatGPTWebProject_show.innerText !== '' && chatGPTWebProject_show.innerText !== 'undefined') || + (chatGPTWebCustomGPT_show.innerText !== '' && chatGPTWebCustomGPT_show.innerText !== 'undefined')) { + element.style.display = 'flex'; + } else { + element.style.display = 'none'; } - // case 'chatgpt_api': - // document.getElementById('chatgpt_api').style.display = 'block'; - // break; - // case 'ollama_api': - // document.getElementById('ollama_api').style.display = 'block'; - // break; - // case 'openai_comp_api': - // document.getElementById('openai_comp_api').style.display = 'block'; - // break; - // case 'google_gemini_api': - // document.getElementById('google_gemini_api').style.display = 'block'; - // break; + + if(chatGPTWebModel_show.innerText === '' || chatGPTWebModel_show.innerText === 'undefined') { + chatGPTWebModel_show.parentNode.style.display = 'none'; + } else { + chatGPTWebModel_show.parentNode.style.display = 'inline'; + } + if(chatGPTWebProject_show.innerText === '' || chatGPTWebProject_show.innerText === 'undefined') { + chatGPTWebProject_show.parentNode.style.display = 'none'; + } else { + chatGPTWebProject_show.parentNode.style.display = 'inline'; + } + if(chatGPTWebCustomGPT_show.innerText === '' || chatGPTWebCustomGPT_show.innerText === 'undefined') { + chatGPTWebCustomGPT_show.parentNode.style.display = 'none'; + } else { + chatGPTWebCustomGPT_show.parentNode.style.display = 'inline'; + } + }else{ + element.style.display = 'none'; + chatGPTWebModel_show.parentNode.style.display = 'none'; + chatGPTWebProject_show.parentNode.style.display = 'none'; + chatGPTWebCustomGPT_show.parentNode.style.display = 'none'; } } From 01142fb582634c9d675ac8e922bab462dee5a48f Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 2 Jan 2026 22:35:24 +0100 Subject: [PATCH 105/146] correctly hiding and showing the chatgpt additional prop toggle. see #102 --- pages/customprompts/mzta-custom-prompts.js | 35 +++++++--------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index f2997c45..03fa2b7a 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -640,33 +640,18 @@ function toggleApiPropertiesShow(tr) { } function toggleAdditionalPropertiesEditor(tr) { - switch(prefs.connection_type) { - case 'chatgpt_web': { - let info_toggle = tr.querySelector('.chatgpt_web_additional_info_toggle'); - info_toggle.style.display = 'block'; - let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show').innerText; - let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show').innerText; - let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show').innerText; + if(prefs.connection_type == 'chatgpt_web' && tr.querySelector('.api_type_show').innerText == '') { + let info_toggle = tr.querySelector('.chatgpt_web_additional_info_toggle'); + info_toggle.style.display = 'block'; + let chatGPTWebModel_show = tr.querySelector('.chatgpt_web_model_show').innerText; + let chatGPTWebProject_show = tr.querySelector('.chatgpt_web_project_show').innerText; + let chatGPTWebCustomGPT_show = tr.querySelector('.chatgpt_web_custom_gpt_show').innerText; - if ((chatGPTWebModel_show !== '' && chatGPTWebModel_show !== 'undefined') || - (chatGPTWebProject_show !== '' && chatGPTWebProject_show !== 'undefined') || - (chatGPTWebCustomGPT_show !== '' && chatGPTWebCustomGPT_show !== 'undefined')) { - info_toggle.click(); - } - break; + if ((chatGPTWebModel_show !== '' && chatGPTWebModel_show !== 'undefined') || + (chatGPTWebProject_show !== '' && chatGPTWebProject_show !== 'undefined') || + (chatGPTWebCustomGPT_show !== '' && chatGPTWebCustomGPT_show !== 'undefined')) { + info_toggle.click(); } - // case 'chatgpt_api': - // document.getElementById('chatgpt_api').style.display = 'block'; - // break; - // case 'ollama_api': - // document.getElementById('ollama_api').style.display = 'block'; - // break; - // case 'openai_comp_api': - // document.getElementById('openai_comp_api').style.display = 'block'; - // break; - // case 'google_gemini_api': - // document.getElementById('google_gemini_api').style.display = 'block'; - // break; } let api_info_toggle = tr.querySelector('.api_additional_info_toggle'); From 7bafb035b25837a3f63b05e1165800ddbdfa22f7 Mon Sep 17 00:00:00 2001 From: Mic Date: Fri, 2 Jan 2026 22:50:30 +0100 Subject: [PATCH 106/146] Translated using Weblate (Spanish) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/es/ --- _locales/es/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 3e461daf..2980618d 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -1301,5 +1301,8 @@ }, "Anthropic_System_Prompt": { "message": "Prompt del sistema" + }, + "reset": { + "message": "Reiniciar" } } From 2cbc8c2d0e2482dca18b29da676c9a6daa17ccb8 Mon Sep 17 00:00:00 2001 From: Mic Date: Fri, 2 Jan 2026 22:49:52 +0100 Subject: [PATCH 107/146] Translated using Weblate (French) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/fr/ --- _locales/fr/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 89cc8a12..e8081aab 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -1335,5 +1335,8 @@ }, "prefs_anthropic_temperature_Info": { "message": "Degré d'aléa injecté dans la réponse. La valeur par défaut est 1,0. La plage de valeurs s'étend di 0,0 à 1,0. Utilisez une température proche de 0,0 pour des tâches analytiques ou des choix multiples, et proche de 1,0 pour des tâches créatives et génératives. Notez que même avec une température de 0,0, les résultats ne seront pas totalement déterministes." + }, + "reset": { + "message": "Réinitialiser" } } From 68c6145828051cb869695adec15b6d3d71f3e1ca Mon Sep 17 00:00:00 2001 From: Mic Date: Fri, 2 Jan 2026 22:48:55 +0100 Subject: [PATCH 108/146] Translated using Weblate (Italian) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/it/ --- _locales/it/messages.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/_locales/it/messages.json b/_locales/it/messages.json index ae811d3f..69840ade 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -1111,7 +1111,7 @@ "message": "Scegli uno dei servizi disponibili per l'API compatibile con OpenAI oppure inseriscine uno manualmente." }, "prefs_OptionText_anthropic_max_tokens": { - "message": "Numero massimo di token di Claude" + "message": "Numero massimo di token" }, "prefs_OptionText_anthropic_max_tokens_Info": { "message": "Il numero massimo di token da generare nell'elaborazione. Il conteggio dei token del tuo prompt, sommato a max_tokens, non può superare la lunghezza di contesto del modello." @@ -1314,5 +1314,32 @@ }, "Optional_Permission_Denied_Model_Fetching": { "message": "Hai negato l’autorizzazione necessaria per recuperare i modelli per questa integrazione." + }, + "prompt_string": { + "message": "Prompt" + }, + "placeholder_mail_headers": { + "message": "Intestazioni email" + }, + "reset": { + "message": "Reset" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "Quale temperatura di campionamento utilizzare, tra 0 e 2. Valori più alti come 0,8 renderanno l'output più casuale, mentre valori più bassi come 0,2 lo renderanno più focalizzato e deterministico." + }, + "prefs_ollama_temperature_Info": { + "message": "La temperatura del modello. Aumentare la temperatura farà sì che il modello risponda in modo più creativo. Il valore predefinito è 0,8. Si consiglia di utilizzare valori compresi tra 0 e 1." + }, + "prefs_api_temperature": { + "message": "Temperatura" + }, + "prefs_openai_comp_temperature_Info": { + "message": "Quale temperatura di campionamento utilizzare, tra 0 e 2. Valori più alti come 0,8 renderanno l'output più casuale, mentre valori più bassi come 0,2 lo renderanno più focalizzato e deterministico." + }, + "prefs_google_gemini_temperature_Info": { + "message": "Questo parametro deve essere un numero compreso tra 0.0 e 2.0. Questo valore controlla la casualità dell'output. Il valore predefinito varia a seconda del modello. Lascialo vuoto per evitare di impostare il parametro nella chiamata API." + }, + "prefs_anthropic_temperature_Info": { + "message": "Quantità di casualità iniettata nella risposta. Il valore predefinito è 1,0. L'intervallo va da 0,0 a 1,0. Utilizza una temperatura più vicina a 0,0 per compiti analitici o a scelta multipla, e più vicina a 1,0 per compiti creativi e generativi. Nota che, anche con una temperatura di 0,0, i risultati non saranno completamente deterministici." } } From 97b016ab63b636a45adfd725710c06950065dc00 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 00:03:48 +0100 Subject: [PATCH 109/146] refining how to handle specific api settings. see #102 --- api_webchat/controller.js | 17 ++++++++++++++++ js/mzta-prompts.js | 8 +------- js/mzta-utils.js | 4 +++- mzta-background.js | 3 +++ pages/_lib/connection-ui.js | 2 +- pages/addtags/mzta-add-tags.js | 16 +++++++++------ pages/spamfilter/mzta-spamfilter.js | 30 +++++++++++++++++++++++++---- 7 files changed, 61 insertions(+), 19 deletions(-) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 050471d2..390d103c 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -23,6 +23,7 @@ import { prefs_default, integration_options_config } from '../options/mzta-options-default.js'; import { placeholdersUtils } from '../js/mzta-placeholders.js'; import { getAPIsInitMessageString, convertNewlinesToBr } from '../js/mzta-utils.js'; +import { loadPrompt } from '../js/mzta-prompts.js'; // Get the LLM to be used const urlParams = new URLSearchParams(window.location.search); @@ -82,6 +83,22 @@ if (worker) { let prefs_api = await browser.storage.sync.get(prefsToGet); + if (prompt_id) { + try { + const prompt = await loadPrompt(prompt_id); + if (prompt && prompt.api_type === llm) { + for (const key in options_config) { + const prefKey = `${integration_prefix}_${key}`; + if (prompt[prefKey] !== undefined) { + prefs_api[prefKey] = prompt[prefKey]; + } + } + } + } catch (e) { + console.error("[ThunderAI] Error loading prompt settings:", e); + } + } + let i18nStrings = {}; const i18n_msg_key = integration === 'openai_comp' ? 'OpenAIComp_api_request_failed' : `${integration}_api_request_failed`; i18nStrings[i18n_msg_key] = browser.i18n.getMessage(i18n_msg_key); diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index b6db041a..3f1526af 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -440,7 +440,6 @@ async function getDefaultPrompts_withProps() { prompt.chatgpt_web_project = prefs._default_prompts_properties[prompt.id].chatgpt_web_project; prompt.chatgpt_web_custom_gpt = (prefs._default_prompts_properties[prompt.id]?.chatgpt_web_custom_gpt || '').trim(); prompt.api_type = (prefs._default_prompts_properties[prompt.id]?.api_type || '').trim(); - prompt.api_model = (prefs._default_prompts_properties[prompt.id]?.api_model || '').trim(); }else{ prompt.position_display = pos; prompt.position_compose = pos; @@ -475,9 +474,6 @@ async function getCustomPrompts() { if(prompt.api_type === undefined){ prompt.api_type = ""; } - if(prompt.api_model === undefined){ - prompt.api_model = ""; - } }); return prefs._custom_prompt; } @@ -495,7 +491,6 @@ export async function setDefaultPromptsProperties(prompts) { chatgpt_web_project: (prompt.chatgpt_web_project === undefined || prompt.chatgpt_web_project === "undefined") ? "" : prompt.chatgpt_web_project, chatgpt_web_custom_gpt: (prompt.chatgpt_web_custom_gpt === undefined || prompt.chatgpt_web_custom_gpt === "undefined") ? "" : prompt.chatgpt_web_custom_gpt, api_type: (prompt.api_type === undefined || prompt.api_type === "undefined") ? "" : prompt.api_type, - api_model: (prompt.api_model === undefined || prompt.api_model === "undefined") ? "" : prompt.api_model }; }); //console.log('>>>>>>>>>>>>>> default_prompts_properties: ' + JSON.stringify(default_prompts_properties)); @@ -590,7 +585,6 @@ export async function savePrompt(prompt) { export async function clearPromptAPI(id){ let _prompt = await loadPrompt(id); - _prompt.api = ""; - _prompt.model = ""; + _prompt.api_type = ""; await savePrompt(_prompt); } \ No newline at end of file diff --git a/js/mzta-utils.js b/js/mzta-utils.js index c833bb31..f58d9b99 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -648,7 +648,9 @@ export function getConnectionType(prefsOrType, prompt, prefixOrSpecific = null) } if (specificType && specificType !== '') return specificType; - if (prompt && prompt.api && prompt.api !== '') return prompt.api; + if (prompt) { + if (prompt.api_type && prompt.api_type !== '') return prompt.api_type; + } return defaultType; } diff --git a/mzta-background.js b/mzta-background.js index e39bc0a1..1b5b8e40 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -371,6 +371,9 @@ async function openChatGPT(promptText, action, curr_tabId, prompt_name = '', do_ prefs = checkScreenDimensions(prefs); //console.log(">>>>>>>>>>>>>>>> prefs: " + JSON.stringify(prefs)); // console.log(">>>>>>>>>>>>>>>> prompt_info: " + JSON.stringify(prompt_info)); + + prefs.connection_type = getConnectionType(prefs, prompt_info); + taLog.log("Prompt length: " + promptText.length); let _max_prompt_length = prefs.max_prompt_length; if(prefs.connection_type == 'chatgpt_web'){ diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 550a1491..70c40636 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -1022,7 +1022,7 @@ export async function initializeSpecificIntegrationUI({ let prompt = await loadPrompt(promptId); if(!prompt) return; - prompt.api = conntype; + prompt.api_type = conntype; for (const [integration, options] of Object.entries(integration_options_config)) { for (const key of Object.keys(options)) { diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index a39bd217..314d62e0 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -48,11 +48,11 @@ document.addEventListener('DOMContentLoaded', async () => { let specialPrompts = await getSpecialPrompts(); let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); - if (addtags_prompt && addtags_prompt.api && addtags_prompt.api !== '') { + if (addtags_prompt && addtags_prompt.api_type && addtags_prompt.api_type !== '') { let update_prefs = {}; - update_prefs['add_tags_connection_type'] = addtags_prompt.api; + update_prefs['add_tags_connection_type'] = addtags_prompt.api_type; - let integration = addtags_prompt.api.replace('_api', ''); + let integration = addtags_prompt.api_type.replace('_api', ''); if (integration_options_config && integration_options_config[integration]) { for (const key of Object.keys(integration_options_config[integration])) { if (addtags_prompt[key] !== undefined) { @@ -344,14 +344,18 @@ async function restoreOptions() { let addtags_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_add_tags'); if (addtags_prompt) { - if (addtags_prompt.api && addtags_prompt.api !== '') { - getting['add_tags_connection_type'] = addtags_prompt.api; + 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) { + if (addtags_prompt[propName] !== undefined && addtags_prompt[propName] !== '') { getting[`add_tags_${propName}`] = addtags_prompt[propName]; + } else { + getting[`add_tags_${propName}`] = getting[propName]; } } } diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index a6f7d30e..8df6369e 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -16,7 +16,10 @@ * along with this program. If not, see . */ -import { prefs_default, integration_options_config } from '../../options/mzta-options-default.js'; +import { + prefs_default, + integration_options_config +} from '../../options/mzta-options-default.js'; import { taLogger } from '../../js/mzta-logger.js'; import { getSpecialPrompts, @@ -42,6 +45,21 @@ document.addEventListener('DOMContentLoaded', async () => { let specialPrompts = await getSpecialPrompts(); let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); + if (spamfilter_prompt && spamfilter_prompt.api_type && spamfilter_prompt.api_type !== '') { + let update_prefs = {}; + update_prefs['spamfilter_connection_type'] = spamfilter_prompt.api_type; + + let integration = spamfilter_prompt.api_type.replace('_api', ''); + if (integration_options_config && integration_options_config[integration]) { + for (const key of Object.keys(integration_options_config[integration])) { + if (spamfilter_prompt[key] !== undefined) { + update_prefs[`spamfilter_${integration}_${key}`] = spamfilter_prompt[key]; + } + } + } + await browser.storage.sync.set(update_prefs); + } + await initializeSpecificIntegrationUI({ prefix: 'spamfilter', promptId: 'prompt_spamfilter', @@ -313,14 +331,18 @@ async function restoreOptions() { let spamfilter_prompt = specialPrompts.find(prompt => prompt.id === 'prompt_spamfilter'); if (spamfilter_prompt) { - if (spamfilter_prompt.api && spamfilter_prompt.api !== '') { - getting['spamfilter_connection_type'] = spamfilter_prompt.api; + if (spamfilter_prompt.api_type && spamfilter_prompt.api_type !== '') { + getting['spamfilter_connection_type'] = spamfilter_prompt.api_type; + } else { + getting['spamfilter_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 (spamfilter_prompt[propName] !== undefined) { + if (spamfilter_prompt[propName] !== undefined && spamfilter_prompt[propName] !== '') { getting[`spamfilter_${propName}`] = spamfilter_prompt[propName]; + } else { + getting[`spamfilter_${propName}`] = getting[propName]; } } } From b558fc2ed2e84bc36da969642b398ecae3cbabca Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 00:20:41 +0100 Subject: [PATCH 110/146] fix for clickable checkbox labels --- options/mzta-options.css | 4 ++++ pages/addtags/mzta-add-tags.css | 3 +++ .../mzta-custom-dataplaceholders.css | 4 ++++ pages/customprompts/mzta-custom-prompts.css | 4 ++++ pages/customprompts/mzta-custom-prompts.html | 10 +++++----- pages/get-calendar-event/mzta-get-calendar-event.css | 3 +++ pages/get-task/mzta-get-task.css | 3 +++ pages/spamfilter/mzta-spamfilter.css | 4 ++++ 8 files changed, 30 insertions(+), 5 deletions(-) diff --git a/options/mzta-options.css b/options/mzta-options.css index f0c21d66..86d168d1 100644 --- a/options/mzta-options.css +++ b/options/mzta-options.css @@ -163,6 +163,10 @@ div#miczTranslate{ color: #292929; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} + @media (prefers-color-scheme: dark) { body { background-color: rgb(35, 34, 43); diff --git a/pages/addtags/mzta-add-tags.css b/pages/addtags/mzta-add-tags.css index 9b02a45c..268fd478 100644 --- a/pages/addtags/mzta-add-tags.css +++ b/pages/addtags/mzta-add-tags.css @@ -167,6 +167,9 @@ table#miczPrefs tr:last-child td { color: red; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} @media (prefers-color-scheme: dark) { body { diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.css b/pages/customdataplaceholders/mzta-custom-dataplaceholders.css index 888459df..02aeae07 100644 --- a/pages/customdataplaceholders/mzta-custom-dataplaceholders.css +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.css @@ -302,6 +302,10 @@ input.input_additional[type="text"]{ cursor: pointer; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} + @media (prefers-color-scheme: dark) { body { background-color: #1C1B22; diff --git a/pages/customprompts/mzta-custom-prompts.css b/pages/customprompts/mzta-custom-prompts.css index 5ff45b45..b44628d0 100644 --- a/pages/customprompts/mzta-custom-prompts.css +++ b/pages/customprompts/mzta-custom-prompts.css @@ -326,6 +326,10 @@ input.input_additional[type="text"]{ text-decoration: underline; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} + @media (prefers-color-scheme: dark) { body { background-color: #1C1B22; diff --git a/pages/customprompts/mzta-custom-prompts.html b/pages/customprompts/mzta-custom-prompts.html index 1ec1d4bb..34622d5d 100644 --- a/pages/customprompts/mzta-custom-prompts.html +++ b/pages/customprompts/mzta-custom-prompts.html @@ -62,15 +62,15 @@
    - +
    - +
    - +
    - +
    - + diff --git a/pages/get-calendar-event/mzta-get-calendar-event.css b/pages/get-calendar-event/mzta-get-calendar-event.css index 3e9f8137..d5e85b91 100644 --- a/pages/get-calendar-event/mzta-get-calendar-event.css +++ b/pages/get-calendar-event/mzta-get-calendar-event.css @@ -91,6 +91,9 @@ table#miczPrefs tr:last-child td { color: red; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} @media (prefers-color-scheme: dark) { body { diff --git a/pages/get-task/mzta-get-task.css b/pages/get-task/mzta-get-task.css index 0ce83ec5..806b5ac9 100644 --- a/pages/get-task/mzta-get-task.css +++ b/pages/get-task/mzta-get-task.css @@ -91,6 +91,9 @@ table#miczPrefs tr:last-child td { color: red; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} @media (prefers-color-scheme: dark) { body { diff --git a/pages/spamfilter/mzta-spamfilter.css b/pages/spamfilter/mzta-spamfilter.css index 85dc977f..7d330186 100644 --- a/pages/spamfilter/mzta-spamfilter.css +++ b/pages/spamfilter/mzta-spamfilter.css @@ -127,6 +127,10 @@ table#report_data th { background-color: #f4f4f4; } +label:has(input[type="checkbox"]) { + cursor: pointer; +} + @media (prefers-color-scheme: dark) { body { background-color: #1C1B22; From def2cb2372a1aab9e723d28ebcc28692137f8d11 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 00:22:24 +0100 Subject: [PATCH 111/146] addeventlistener commented out --- .../customdataplaceholders/mzta-custom-dataplaceholders.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.js b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js index 81b82f4b..5a9a9314 100644 --- a/pages/customdataplaceholders/mzta-custom-dataplaceholders.js +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js @@ -220,9 +220,9 @@ document.addEventListener('DOMContentLoaded', async () => { }; } - document.getElementById('btnManagePrompts').addEventListener('click', () => { - openTab('/pages/customprompts/mzta-custom-prompts.html'); - }); + // document.getElementById('btnManagePrompts').addEventListener('click', () => { + // openTab('/pages/customprompts/mzta-custom-prompts.html'); + // }); }, { once: true }); From b32ce4f756a609db6b1a864519a98e0fe903532c Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:04:01 +0100 Subject: [PATCH 112/146] copyright date updated to 2026 --- api_webchat/controller.js | 2 +- api_webchat/messageInput.js | 2 +- api_webchat/messagesArea.js | 2 +- js/api/anthropic.js | 2 +- js/api/google_gemini.js | 2 +- js/api/ollama.js | 2 +- js/api/openai_comp.js | 2 +- js/api/openai_comp_configs.js | 2 +- js/api/openai_responses.js | 2 +- js/mzta-addatags-exclusion-list.js | 2 +- js/mzta-chatgpt-loader.js | 2 +- js/mzta-chatgpt.js | 2 +- js/mzta-compose-script.js | 2 +- js/mzta-logger.js | 2 +- js/mzta-menus.js | 2 +- js/mzta-placeholders-autocomplete.js | 2 +- js/mzta-placeholders.js | 2 +- js/mzta-prompts.js | 2 +- js/mzta-spamreport.js | 2 +- js/mzta-special-commands.js | 2 +- js/mzta-store.js | 2 +- js/mzta-utils-prompt.js | 2 +- js/mzta-utils.js | 2 +- js/mzta-working-status.js | 2 +- js/tb115_segmenter/tb115_loader.js | 2 +- js/tb115_segmenter/tb115_polyfill.js | 2 +- js/workers/model-worker-anthropic.js | 2 +- js/workers/model-worker-google_gemini.js | 2 +- js/workers/model-worker-ollama.js | 2 +- js/workers/model-worker-openai_comp.js | 2 +- js/workers/model-worker-openai_responses.js | 2 +- mzta-background.js | 2 +- options/mzta-options-default.js | 2 +- options/mzta-options.js | 2 +- options/mzta-release-notes.js | 2 +- pages/_lib/connection-ui.js | 2 +- pages/addtags/mzta-add-tags.js | 2 +- pages/customdataplaceholders/mzta-custom-dataplaceholders.js | 2 +- pages/customprompts/mzta-custom-prompts.js | 2 +- pages/get-calendar-event/mzta-get-calendar-event.js | 2 +- pages/get-task/mzta-get-task.js | 2 +- pages/onboarding/onboarding.js | 2 +- pages/spamfilter/mzta-spamfilter.js | 2 +- popup/mzta-popup.js | 2 +- 44 files changed, 44 insertions(+), 44 deletions(-) diff --git a/api_webchat/controller.js b/api_webchat/controller.js index 390d103c..6dec60df 100644 --- a/api_webchat/controller.js +++ b/api_webchat/controller.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/api_webchat/messageInput.js b/api_webchat/messageInput.js index aba7c272..b5b2a6b0 100644 --- a/api_webchat/messageInput.js +++ b/api_webchat/messageInput.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/api_webchat/messagesArea.js b/api_webchat/messagesArea.js index 3696dbe2..7036c30f 100644 --- a/api_webchat/messagesArea.js +++ b/api_webchat/messagesArea.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/anthropic.js b/js/api/anthropic.js index dcf438c5..2fa9ae78 100644 --- a/js/api/anthropic.js +++ b/js/api/anthropic.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/google_gemini.js b/js/api/google_gemini.js index e16c52e5..caea5eb0 100644 --- a/js/api/google_gemini.js +++ b/js/api/google_gemini.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/ollama.js b/js/api/ollama.js index f9f7e0ad..07d5a066 100644 --- a/js/api/ollama.js +++ b/js/api/ollama.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/openai_comp.js b/js/api/openai_comp.js index 683a0b8c..19d1d2cf 100644 --- a/js/api/openai_comp.js +++ b/js/api/openai_comp.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/openai_comp_configs.js b/js/api/openai_comp_configs.js index 35ce9cd9..4eb7bbd4 100644 --- a/js/api/openai_comp_configs.js +++ b/js/api/openai_comp_configs.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/api/openai_responses.js b/js/api/openai_responses.js index 174c4f4d..229cc0c4 100644 --- a/js/api/openai_responses.js +++ b/js/api/openai_responses.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-addatags-exclusion-list.js b/js/mzta-addatags-exclusion-list.js index 47e35ece..1b04b645 100644 --- a/js/mzta-addatags-exclusion-list.js +++ b/js/mzta-addatags-exclusion-list.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-chatgpt-loader.js b/js/mzta-chatgpt-loader.js index 0e3685df..28bb8272 100644 --- a/js/mzta-chatgpt-loader.js +++ b/js/mzta-chatgpt-loader.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-chatgpt.js b/js/mzta-chatgpt.js index a5dbda64..4ccdb448 100644 --- a/js/mzta-chatgpt.js +++ b/js/mzta-chatgpt.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-compose-script.js b/js/mzta-compose-script.js index 6d11c492..972a32de 100644 --- a/js/mzta-compose-script.js +++ b/js/mzta-compose-script.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-logger.js b/js/mzta-logger.js index be7292fc..eb68ec66 100644 --- a/js/mzta-logger.js +++ b/js/mzta-logger.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-menus.js b/js/mzta-menus.js index c2a54999..546b69c0 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-placeholders-autocomplete.js b/js/mzta-placeholders-autocomplete.js index d4f03f3d..ecfd7028 100644 --- a/js/mzta-placeholders-autocomplete.js +++ b/js/mzta-placeholders-autocomplete.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-placeholders.js b/js/mzta-placeholders.js index 27eeb858..bfb841c7 100644 --- a/js/mzta-placeholders.js +++ b/js/mzta-placeholders.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 3f1526af..f9ac22a1 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-spamreport.js b/js/mzta-spamreport.js index abfaae83..99b4efc5 100644 --- a/js/mzta-spamreport.js +++ b/js/mzta-spamreport.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 95a0d14f..79267b98 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-store.js b/js/mzta-store.js index 1b4e3f6c..5729aa4e 100644 --- a/js/mzta-store.js +++ b/js/mzta-store.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-utils-prompt.js b/js/mzta-utils-prompt.js index 896f6406..d1c638b7 100644 --- a/js/mzta-utils-prompt.js +++ b/js/mzta-utils-prompt.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-utils.js b/js/mzta-utils.js index f58d9b99..a99c70a9 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/mzta-working-status.js b/js/mzta-working-status.js index 9f220d0f..81f2cb76 100644 --- a/js/mzta-working-status.js +++ b/js/mzta-working-status.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/tb115_segmenter/tb115_loader.js b/js/tb115_segmenter/tb115_loader.js index 0c2fc7da..df476c7c 100644 --- a/js/tb115_segmenter/tb115_loader.js +++ b/js/tb115_segmenter/tb115_loader.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/tb115_segmenter/tb115_polyfill.js b/js/tb115_segmenter/tb115_polyfill.js index ae06b97a..6760cd9a 100644 --- a/js/tb115_segmenter/tb115_polyfill.js +++ b/js/tb115_segmenter/tb115_polyfill.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/workers/model-worker-anthropic.js b/js/workers/model-worker-anthropic.js index 9af3dc17..21452ca4 100644 --- a/js/workers/model-worker-anthropic.js +++ b/js/workers/model-worker-anthropic.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/workers/model-worker-google_gemini.js b/js/workers/model-worker-google_gemini.js index 4b6fc138..efd1b9c7 100644 --- a/js/workers/model-worker-google_gemini.js +++ b/js/workers/model-worker-google_gemini.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/workers/model-worker-ollama.js b/js/workers/model-worker-ollama.js index 3987df33..6a8d1310 100644 --- a/js/workers/model-worker-ollama.js +++ b/js/workers/model-worker-ollama.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/workers/model-worker-openai_comp.js b/js/workers/model-worker-openai_comp.js index a541ffa8..d2685500 100644 --- a/js/workers/model-worker-openai_comp.js +++ b/js/workers/model-worker-openai_comp.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/js/workers/model-worker-openai_responses.js b/js/workers/model-worker-openai_responses.js index 89803673..8f3189ee 100644 --- a/js/workers/model-worker-openai_responses.js +++ b/js/workers/model-worker-openai_responses.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/mzta-background.js b/mzta-background.js index 1b5b8e40..915f12ab 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/options/mzta-options-default.js b/options/mzta-options-default.js index fbecbfb6..66b24890 100644 --- a/options/mzta-options-default.js +++ b/options/mzta-options-default.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/options/mzta-options.js b/options/mzta-options.js index 2f8c4424..16b130fd 100644 --- a/options/mzta-options.js +++ b/options/mzta-options.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/options/mzta-release-notes.js b/options/mzta-release-notes.js index 6559e014..c3270305 100644 --- a/options/mzta-release-notes.js +++ b/options/mzta-release-notes.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/_lib/connection-ui.js b/pages/_lib/connection-ui.js index 70c40636..37c779ed 100644 --- a/pages/_lib/connection-ui.js +++ b/pages/_lib/connection-ui.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 314d62e0..7f323fd8 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/customdataplaceholders/mzta-custom-dataplaceholders.js b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js index 5a9a9314..2c2e896a 100644 --- a/pages/customdataplaceholders/mzta-custom-dataplaceholders.js +++ b/pages/customdataplaceholders/mzta-custom-dataplaceholders.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 03fa2b7a..2b01f6e6 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/get-calendar-event/mzta-get-calendar-event.js b/pages/get-calendar-event/mzta-get-calendar-event.js index 303ac444..2102083a 100644 --- a/pages/get-calendar-event/mzta-get-calendar-event.js +++ b/pages/get-calendar-event/mzta-get-calendar-event.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/get-task/mzta-get-task.js b/pages/get-task/mzta-get-task.js index 84df2e8e..685fa7f8 100644 --- a/pages/get-task/mzta-get-task.js +++ b/pages/get-task/mzta-get-task.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/onboarding/onboarding.js b/pages/onboarding/onboarding.js index 747aedad..ccb9a1ce 100644 --- a/pages/onboarding/onboarding.js +++ b/pages/onboarding/onboarding.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index 8df6369e..e2e0a36a 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 diff --git a/popup/mzta-popup.js b/popup/mzta-popup.js index d73aaf14..d5d69664 100644 --- a/popup/mzta-popup.js +++ b/popup/mzta-popup.js @@ -1,6 +1,6 @@ /* * ThunderAI [https://micz.it/thunderbird-addon-thunderai/] - * Copyright (C) 2024 - 2025 Mic (m@micz.it) + * 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 From 441a2d583586ba22758ddaed96aa7da9b126cba6 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:09:33 +0100 Subject: [PATCH 113/146] info comment updated. see #102 --- js/mzta-prompts.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index f9ac22a1..3cf4cf67 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -75,9 +75,7 @@ API Connection Type : api type - API Model - : api model - + << All the API settings defined in the default options, with the same IDs. >> */ const defaultPrompts = [ From fdc8d0920b3674a7a0c72cc38067b3afe757d237 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:10:31 +0100 Subject: [PATCH 114/146] api_model removed. see #102 --- js/mzta-prompts.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 3cf4cf67..9ab9bff8 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -94,7 +94,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -113,7 +112,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -132,7 +130,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -151,7 +148,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -170,7 +166,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -189,7 +184,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -208,7 +202,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -227,7 +220,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -246,7 +238,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -265,7 +256,6 @@ const defaultPrompts = [ chatgpt_web_project: '', chatgpt_web_custom_gpt: '', api_type: '', - api_model: '', is_default: "1", is_special: "0", }, @@ -284,7 +274,6 @@ const specialPrompts = [ define_response_lang: "0", use_diff_viewer: "0", api_type: '', - api_model: '', is_default: "1", is_special: "1", }, @@ -300,7 +289,6 @@ const specialPrompts = [ define_response_lang: "0", use_diff_viewer: "0", api_type: '', - api_model: '', is_default: "1", is_special: "1", }, @@ -316,7 +304,6 @@ const specialPrompts = [ define_response_lang: "0", use_diff_viewer: "0", api_type: '', - api_model: '', is_default: "1", is_special: "1", }, @@ -332,7 +319,6 @@ const specialPrompts = [ define_response_lang: "0", use_diff_viewer: "0", api_type: '', - api_model: '', is_default: "1", is_special: "1", }, From 0b002e902c95487567fc29bf561e598aab7056e0 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sat, 3 Jan 2026 23:11:26 +0100 Subject: [PATCH 115/146] Translated using Weblate (Swedish) Currently translated at 45.6% (197 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 522 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 501458e0..7d9b5c0b 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -67,5 +67,527 @@ }, "prefs_OptionText_chatgpt_win_width": { "message": "Bredd" + }, + "prompt_summarize_this": { + "message": "Sammanfatta detta" + }, + "prompt_translate_this": { + "message": "Översätt detta" + }, + "more_info_string": { + "message": "Mer information" + }, + "prompt_classify": { + "message": "Klassificera" + }, + "customPrompts_reloading_menus": { + "message": "Laddar om menyer..." + }, + "customPrompts_form_required_fields": { + "message": "Obligatoriska fält" + }, + "customPrompts_add_to_menu_reading": { + "message": "Läser ett e-postmeddelande" + }, + "customPrompts_add_to_menu_composing": { + "message": "Skriver ett e-postmeddelande" + }, + "chatgpt_win_working": { + "message": "Arbete pågår..." + }, + "chatgpt_win_job_completed": { + "message": "Färdigt!" + }, + "chatgpt_win_job_completed_select": { + "message": "Markera den text du vill använda och klicka på knappen." + }, + "chatgpt_win_get_answer": { + "message": "Använd det valda svaret" + }, + "prefs_OptionText_release_notes": { + "message": "Versionsinformation" + }, + "prefsInfoTitle": { + "message": "Viktig information" + }, + "placeholder_tags_current_email": { + "message": "E-posttaggar" + }, + "placeholder_tags_full_list": { + "message": "Befintliga taggar" + }, + "prefs_OptionText_add_tags_maxnum": { + "message": "Maximalt antal taggar" + }, + "prefs_OptionText_add_tags_maxnum_Info": { + "message": "Det maximala antalet taggar som föreslås av AI:n. Ställ den på 0 om du inte vill begränsa antalet taggar." + }, + "prompt_add_tags_maxnum": { + "message": "Begränsa antalet taggar till" + }, + "prefs_OptionText_add_tags_hide_exclusions": { + "message": "Dölj uteslutna taggar" + }, + "prefs_OptionText_add_tags_hide_exclusions_Info": { + "message": "Om markerad kommer taggarna som finns i undantagslistan att döljas i bekräftelsedialogrutan." + }, + "prefs_OptionText_btnManageTagsInfo": { + "message": "Hantera tagginställningar" + }, + "AddTags_PageTitle": { + "message": "Hantera tagginställningar" + }, + "AddTags_excl_list_title": { + "message": "Undantagslista" + }, + "AddTags_excl_list_infoline": { + "message": "Detta är en lista över taggar som inte får läggas till i e-postmeddelanden." + }, + "save": { + "message": "Spara" + }, + "reset_default": { + "message": "Återställ till standard" + }, + "reset": { + "message": "Återställ" + }, + "addtags_excl_list_infoline2": { + "message": "Lägg till ett ord per rad, eller separera med kommatecken." + }, + "addtags_dialog_title": { + "message": "Lägg till taggar i e-postmeddelandet" + }, + "addtags_exclude_tag": { + "message": "Uteslut tagg" + }, + "addtags_no_tags_received": { + "message": "Inga taggar mottagna från AI:n." + }, + "addtags_no_valid_tags": { + "message": "Inga giltiga taggar hittades efter filtrering med undantagslistan." + }, + "thunderai_error_title": { + "message": "ThunderAI-fel" + }, + "thunderai_warning_title": { + "message": "ThunderAI-varning" + }, + "prefs_OptionText_add_tags_first_uppercase_Info": { + "message": "Om markerad kommer taggarna att ställas in på gemener med endast den första bokstaven som versal." + }, + "prefs_OptionText_add_tags_first_uppercase": { + "message": "Första bokstaven som versal" + }, + "prompt_reply": { + "message": "Svara på detta e-postmeddelande" + }, + "prompt_reply_advanced": { + "message": "Svara på denna tråd" + }, + "prompt_reply_custom_command": { + "message": "Svara med kommando" + }, + "prompt_rewrite_polite": { + "message": "Skriv om artigt" + }, + "prompt_rewrite_formal": { + "message": "Skriv om formellt" + }, + "customPrompts_managePrompts": { + "message": "Hantera promptar" + }, + "prompt_lang": { + "message": "Svara på" + }, + "customPrompts_start_saving": { + "message": "Sparar promptar..." + }, + "customPrompts_reindexing_list": { + "message": "Omindexerar listan..." + }, + "customPrompts_filtering_prompts": { + "message": "Filtrerar promptar..." + }, + "customPrompts_saving_default_prompts": { + "message": "Sparar standardpromptar..." + }, + "customPrompts_saving_custom_prompts": { + "message": "Sparar anpassade promptar..." + }, + "customPrompts_saved": { + "message": "Promptar sparade!" + }, + "customPrompts_form_label_ID": { + "message": "Id" + }, + "customPrompts_form_label_ID_rules": { + "message": "Måste vara unikt, med gemener och utan mellanslag" + }, + "customPrompts_form_label_Text": { + "message": "Prompttext" + }, + "customPrompts_form_label_need_selected": { + "message": "Textval behövs" + }, + "customPrompts_form_label_need_signature": { + "message": "Lägg alltid till signaturen" + }, + "customPrompts_form_label_need_custom_text": { + "message": "Be om ytterligare text" + }, + "customPrompts_form_label_use_diff_viewer": { + "message": "Aktivera visaren för textjämförelse" + }, + "customPrompts_form_label_use_diff_viewer_title": { + "message": "Textjämförelsevisaren kan väljas när åtgärden är inställd på \"Ersätt text\"." + }, + "customPrompts_btnAddNewCommit": { + "message": "Lägg till prompten" + }, + "customPrompts_add_to_menu": { + "message": "Lägg till i meny" + }, + "customPrompts_close_button": { + "message": "Stäng-knapp" + }, + "customPrompts_do_reply": { + "message": "Svara" + }, + "customPrompts_substitute_text": { + "message": "Ersätt text" + }, + "chatgpt_textarea_not_found_error": { + "message": "Det verkar som att ChatGPT-sidan tar för lång tid att ladda. Om den är klar klickar du på knappen till höger. Om problemet kvarstår kontrollerar du tjänstens status." + }, + "chatgpt_sendbutton_not_found_error": { + "message": "Klicka på skicka-knappen för att skicka in prompten." + }, + "chatgpt_user_not_logged_in": { + "message": "Du är inte inloggad på ChatGPT. Logga in med dina inloggningsuppgifter, stäng ChatGPT-fönstret och upprepa sedan åtgärden du försökte göra. Du kommer att förbli inloggad efteråt." + }, + "chatgpt_win_model_warning": { + "message": "Av någon anledning är det inte möjligt att verifiera om rätt modell är laddad. För tillfället kan du trycka på den blå knappen för att fortsätta." + }, + "chatgpt_win_custom_text": { + "message": "Infoga här den ytterligare texten för prompten." + }, + "chatgpt_force_completion": { + "message": "tvinga slutförande" + }, + "prompt_this": { + "message": "Prompt detta" + }, + "prompt_string": { + "message": "Prompt" + }, + "customPrompts_managePrompts_info_default": { + "message": "Standardpromptar kan inte redigeras. Du kan inaktivera dem och sedan kopiera prompttexten och klistra in den i en ny för att skapa en modifierad version." + }, + "customPrompts_managePrompts_info_default_2": { + "message": "Du kan importera och exportera promptar. Befintliga promptar med samma ID kommer att skrivas över. Promptar med nya ID:n kommer att läggas till." + }, + "customPrompts_managePrompts_info_default_3": { + "message": "Om allt är korrekt, klicka på knappen \"Spara alla\" efter importen." + }, + "chatgpt_force_completion_title": { + "message": "Klicka här för att visa knappen \"Använd senaste svar\" om ChatGPT har slutfört sitt arbete men knappen inte har visats." + }, + "msg_prompt_too_long": { + "message": "Texten du angav är för lång. Du måste förkorta den." + }, + "prefs_status_page": { + "message": "tjänstestatus" + }, + "prefs_OptionText_chatgpt_win_text": { + "message": "AI-chattfönstrets dimensioner" + }, + "prefs_OptionText_default_sign_name": { + "message": "Standardsignaturnamn" + }, + "prefs_OptionText_default_chatgpt_lang": { + "message": "Standardspråk för svaren" + }, + "prefs_OptionText_reply_all": { + "message": "Svara alla" + }, + "prefs_OptionText_reply_sender": { + "message": "Svara till avsändaren" + }, + "prefs_OptionText_reply_type": { + "message": "Svarstyp" + }, + "prefs_OptionText_reply_type_Info": { + "message": "Detta är standardsvarstypen som används när du svarar på ett e-postmeddelande. Du kan välja den andra typen senare i svarsdialogrutan." + }, + "prefs_OptionText_btnManagePrompts": { + "message": "Hantera dina promptar" + }, + "prefs_OptionText_btnManageCustomDataPH": { + "message": "Hantera dina dataplatshållare" + }, + "prefsInfoDesc_1": { + "message": "Det kan hända att ChatGPT:s webbgränssnitt ändras på ett sätt som stör hur tillägget fungerar. Kontrollera sidan \"Tjänststatus\" som är länkad längst ner på den här sidan. Kom också ihåg att första gången du använder ThunderAI måste du logga in på ChatGPT." + }, + "prefsInfoDesc_2": { + "message": "För att använda ChatGPT API behöver du en OpenAI ChatGPT API-nyckel och måste välja en modell." + }, + "prefsInfoDesc_3": { + "message": "För att använda integrationen med Ollama måste du konfigurera en lokal Ollama-server. När servern är igång anger du dess adress i det angivna fältet i applikationen. För att säkerställa korrekt kommunikation mellan ThunderAI och Ollama-servern, kom ihåg att ange OLLAMA_ORIGINS=moz-extension://*." + }, + "prefsInfoDesc_4": { + "message": "För att använda den här integrationen behöver du konfigurera en lokal server som är kompatibel med OpenAI API, som LM Studio. När servern är igång anger du dess adress i det angivna fältet i applikationen. För att säkerställa korrekt kommunikation mellan ThunderAI och den lokala servern, kom ihåg att ställa in CORS-inställningarna korrekt." + }, + "prefsInfoDesc_5": { + "message": "Kom ihåg att du kan öppna ThunderAI-menyn med kortkommandot CTRL+ALT+A." + }, + "prefsInfoDesc_6": { + "message": "Du kan ändra genvägen genom att klicka på kugghjulsikonen längst upp till höger på den här sidan och välja \"Hantera genväg för tillägg\"." + }, + "prefsDonation_1": { + "message": "Gillar du det här tillägget?" + }, + "prefsDonation_2": { + "message": "Överväg att göra en donation!" + }, + "backToOptionsText": { + "message": "Alternativ" + }, + "TranslateText": { + "message": "Vill du hjälpa till att översätta det här tillägget?" + }, + "TranslateLink": { + "message": "Ta reda på hur!" + }, + "customPrompts_ExportAll": { + "message": "Exportera alla promptar" + }, + "customPrompts_Import": { + "message": "Importera nya promptar" + }, + "importPrompts_confirmText": { + "message": "Du håller på att importera nya promptar." + }, + "customPrompts_start_import": { + "message": "Startar import av anpassade promptar..." + }, + "customPrompts_import_completed": { + "message": "Import av anpassade promptar är klar! Du måste klicka på knappen \"Spara alla\" för att spara dina ändringar." + }, + "importPrompts_invalidFile": { + "message": "Filen du försöker importera är inte en giltig fil med anpassade promptar." + }, + "importPrompts_invalidPrompts": { + "message": "Filen du försöker importera innehåller inga giltiga promptar." + }, + "currently_used_prompt": { + "message": "För närvarande använt promptnamn" + }, + "customprompts_form_label_define_response_lang": { + "message": "Definiera svarsspråket i prompten" + }, + "prefs_Connection_type": { + "message": "Anslutningstyp" + }, + "prefs_Connection_type_ChatGPT_Web": { + "message": "ChatGPT-webbgränssnitt" + }, + "prefs_Connection_type_ChatGPT_API": { + "message": "ChatGPT OpenAI API" + }, + "prefs_ChatGPT_API_Key": { + "message": "ChatGPT API-nyckel" + }, + "ChatGPT_Models": { + "message": "ChatGPT-modeller" + }, + "ChatGPT_Models_Fetch": { + "message": "Uppdatera listan över ChatGPT-modeller" + }, + "ChatGPT_Models_Error_fetching": { + "message": "Fel vid försök att hämta ChatGPT-modeller" + }, + "Loading": { + "message": "Laddar..." + }, + "error": { + "message": "ThunderAI-fel!" + }, + "chatgpt_empty_apikey": { + "message": "Du har inte lagt till en API-nyckel för ChatGPT API. Vänligen ange en på alternativsidan." + }, + "chatgpt_empty_model": { + "message": "Du har inte valt någon modell för ChatGPT API. Välj en på alternativsidan." + }, + "chagpt_api_send_button": { + "message": "Använda modell" + }, + "Debug": { + "message": "Felsök" + }, + "prefs_OptionText_do_debug_info": { + "message": "Aktivera felsökningssystemet" + }, + "prefs_Connection_type_Ollama_API": { + "message": "Ollama API (Lokal LLM)" + }, + "prefs_Connection_type_OpenAI_Comp_API": { + "message": "OpenAI-kompatibelt API" + }, + "prefs_API_Host": { + "message": "Värdadress" + }, + "Ollama_Models": { + "message": "Ollama-modeller" + }, + "Ollama_Models_Fetch": { + "message": "Uppdatera listan över Ollama-modeller" + }, + "Ollama_Models_Error_fetching": { + "message": "Fel vid försök att hämta Ollama-modeller" + }, + "API_Models_Error_NoModels": { + "message": "Inga modeller hittades" + }, + "ollama_empty_host": { + "message": "Du har inte lagt till en värdadress för Ollama API. Vänligen ange en på alternativsidan." + }, + "ollama_empty_model": { + "message": "Du har inte valt någon modell för Ollama API. Välj en på alternativsidan." + }, + "error_connection_interrupted": { + "message": "Anslutningen till servern avbröts oväntat" + }, + "ollama_api_request_failed": { + "message": "Ollama API-begäran misslyckades" + }, + "chatgpt_api_request_failed": { + "message": "OpenAI ChatGPT API-begäran misslyckades" + }, + "WaitingServerResponse": { + "message": "Väntar på serversvar" + }, + "prefs_API_Host_Info": { + "message": "Något liknande" + }, + "OpenAIComp_Models": { + "message": "OpenAI-kompatibla API-modeller" + }, + "OpenAIComp_Models_Fetch": { + "message": "Uppdatera listan över OpenAI-kompatibla API-modeller" + }, + "OpenAIComp_Models_Error_fetching": { + "message": "Fel vid försök att hämta OpenAI-kompatibla API-modeller" + }, + "OpenAIComp_empty_host": { + "message": "Du har inte lagt till en värdadress för OpenAI-kompatibla API:et. Vänligen ange en på alternativsidan." + }, + "OpenAIComp_empty_model": { + "message": "Du har inte valt en modell för OpenAI-kompatibelt API. Välj en på alternativsidan." + }, + "OpenAIComp_api_request_failed": { + "message": "OpenAI Comp API-begäran misslyckades" + }, + "prefs_OpenAIComp_ChatName": { + "message": "Chattnamn" + }, + "prefs_OpenAIComp_ChatName_Info": { + "message": "Detta är namnet som kommer att användas i AI-chatten." + }, + "StorageSpace": { + "message": "Totalt upptaget lagringsutrymme" + }, + "SearchPrompt": { + "message": "Sök promptar" + }, + "prefs_OptionText_dynamic_menu_force_enter_info": { + "message": "Om markerat, skickas den markerade prompten från menyn automatiskt genom att använda kortkommandot CTRL+ALT+A. Annars visas promptnamnet för användaren, vilket kräver ytterligare ett tryck på Enter-tangenten för att skicka den." + }, + "prefs_OptionText_dynamic_menu_force_enter": { + "message": "Meny: skicka omedelbart prompt" + }, + "prefs_OptionText_dynamic_menu_order_alphabet": { + "message": "Meny: ordna alfabetiskt" + }, + "prefs_OptionText_dynamic_menu_order_alphabet_info": { + "message": "Om markerat kommer promptar i menyn att ordnas alfabetiskt." + }, + "prefs_OptionText_chatgpt_win_dims_info": { + "message": "Ställ in värdet till 0 om du inte vill ange fönsterstorleken." + }, + "prefs_OpenAIComp_API_Key": { + "message": "OpenAI Comp API-nyckel" + }, + "Optional": { + "message": "Valfri" + }, + "OpenChatGPTTab": { + "message": "Öppna fliken ChatGPT" + }, + "OpenChatGPTTab_Info": { + "message": "Vid inloggningsproblem i ThunderAI-fönstret, öppna ChatGPT i en ny flik med knappen till höger, logga in, stäng sedan fliken och fortsätt använda ThunderAI." + }, + "OpenChatGPTTab_Info2": { + "message": "Om du öppnar ChatGPT Web härifrån tillämpas alla konfigurerade inställningar för modellen, projektet och den anpassade GPT:n." + }, + "placeholder_mail_text_body": { + "message": "Mejltext" + }, + "placeholder_mail_html_body": { + "message": "HTML-mejltext" + }, + "placeholder_mail_subject": { + "message": "Ämne för e-postmeddelande" + }, + "placeholder_folder_name": { + "message": "Mappnamn" + }, + "placeholder_folder_path": { + "message": "Mappsökväg" + }, + "placeholder_mail_headers": { + "message": "E-postrubriker" + }, + "placeholder_selected_text": { + "message": "Vald text" + }, + "placeholder_junk_score": { + "message": "Skräppoäng" + }, + "placeholder_recipients": { + "message": "Mottagare" + }, + "placeholder_cc_list": { + "message": "CC-lista" + }, + "placeholder_author": { + "message": "Författare" + }, + "placeholder_account_email_address": { + "message": "Kontots e-postadress" + }, + "prefs_OptionText_placeholders_use_default_value": { + "message": "Platshållare: använd standardvärde" + }, + "prefs_OptionText_placeholders_use_default_value_info": { + "message": "Om markerat kommer platshållarna att fyllas med standardvärdena när inget värde anges. Annars kommer platshållarna att behållas." + }, + "prefs_OptionText_max_prompt_length": { + "message": "Max promptlängd" + }, + "prefs_OptionText_max_prompt_length_Info": { + "message": "Detta är det maximala antalet tecken som kan användas i en prompt. Annars visas ett felmeddelande. Värdet kan inte redigeras för ChatGPT-webbgränssnittet. Ställ in det på 0 för att inaktivera kontrollen." + }, + "prefs_OptionText_chatgpt_web_model": { + "message": "ChatGPT webbmodell" + }, + "prefs_OptionText_chatgpt_web_model_info": { + "message": "Det här är modellen som kommer att tillämpas för ChatGPT:s webbgränssnitt. Om ingen modell anges eller om en felaktig modell anges, kommer standardmodellen att ställas in av ChatGPT på webbsidan. Den här inställningen fungerar inte med ett gratis ChatGPT-konto." + }, + "prefs_OptionText_chatgpt_web_tempchat": { + "message": "ChatGPT Web tillfällig chatt" + }, + "prefs_OptionText_chatgpt_web_tempchat_info": { + "message": "Om markerad kommer den tillfälliga chatten att användas i ChatGPT:s webbgränssnitt." } } From 07477b6d38b493f38ae6e15d54b0ab4cf90ff5d0 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:36:47 +0100 Subject: [PATCH 116/146] using specific api configuration in special prompts --- js/mzta-special-commands.js | 54 +++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/js/mzta-special-commands.js b/js/mzta-special-commands.js index 79267b98..716b232e 100644 --- a/js/mzta-special-commands.js +++ b/js/mzta-special-commands.js @@ -28,7 +28,6 @@ prompt = ""; worker = null; llm = ""; - custom_model = ""; full_message = ""; logger = null; do_debug = false; @@ -38,16 +37,14 @@ let { prompt = '', llm = '', - custom_model = '', do_debug = false, config = {} } = args; this.prompt = prompt; this.llm = llm; - this.custom_model = custom_model; this.config = config; - this.logger = new taLogger('mzta_specialCommand', do_debug); this.do_debug = do_debug; + this.logger = new taLogger('mzta_specialCommand', do_debug); const worker_path_map = { chatgpt_api: './workers/model-worker-openai_responses.js', @@ -67,7 +64,17 @@ } async initWorker() { - const integration = this.llm.replace('_api', ''); + let integration = this.llm.replace('_api', ''); + let use_specific_api = false; + + this.logger.log("integration: " + integration); + + if (this.config.api_type && this.config.api_type !== '') { + integration = this.config.api_type.replace('_api', ''); + use_specific_api = true; + this.logger.log("use_specific_api: " + use_specific_api); + this.logger.log("specific integration: " + integration); + } const options_config = integration_options_config[integration]; if (!options_config) { @@ -75,13 +82,15 @@ throw new Error("Invalid integration type: " + integration); } - let prefsToGet = {}; - for (const key in options_config) { + const prefsToGet = {}; + const configKeys = Object.keys(options_config); + + for (const key of configKeys) { const prefKey = `${integration}_${key}`; prefsToGet[prefKey] = prefs_default[prefKey]; } - let prefs_api = await browser.storage.sync.get(prefsToGet); + const prefs_api = await browser.storage.sync.get(prefsToGet); let workerInitMessage = { type: 'init', @@ -89,24 +98,23 @@ i18nStrings: '' }; - for (const key in options_config) { + for (const key of configKeys) { const prefKey = `${integration}_${key}`; + let value = prefs_api[prefKey]; - const configValue = this.config[prefKey]; - - if (configValue !== undefined) { - if (typeof options_config[key] === 'boolean') { - prefs_api[prefKey] = (configValue === true || configValue === 'true' || configValue === 1); - } else { - prefs_api[prefKey] = configValue; - } - } - - if (key === 'model') { - workerInitMessage[prefKey] = this.custom_model !== '' ? this.custom_model : prefs_api[prefKey]; - } else { - workerInitMessage[prefKey] = prefs_api[prefKey]; + if(use_specific_api){ + const configValue = this.config[prefKey]; + + if (configValue !== undefined) { + if (typeof options_config[key] === 'boolean') { + value = (configValue === true || configValue === 'true' || configValue === 1); + } else { + value = configValue; + } + } } + + workerInitMessage[prefKey] = value; } this.worker.postMessage(workerInitMessage); From 57f1d637ffe131400c8719f217c3596906b44ed3 Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:43:57 +0100 Subject: [PATCH 117/146] added two commented debug lines --- mzta-background.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mzta-background.js b/mzta-background.js index 915f12ab..5d6c9bc0 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1041,7 +1041,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']), do_debug: prefs_default.do_debug, }); - + // console.log(">>>>>>>>>>>>>>>> getDynamicSettingsDefaults: " + JSON.stringify(getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']))); for await (let message of messages) { let curr_fullMessage = null; let msg_text = null; @@ -1083,6 +1083,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { specialFullPrompt_add_tags = taPromptUtils.finalizePrompt_add_tags(specialFullPrompt_add_tags, prefs_aats.add_tags_maxnum, prefs_aats.add_tags_force_lang, prefs_aats.default_chatgpt_lang, prefs_aats.add_tags_auto_uselist, prefs_aats.add_tags_auto_uselist_list); taLog.log("Special prompt: " + specialFullPrompt_add_tags); // console.log(">>>>>>>>>> curr_prompt_add_tags.model: " + curr_prompt_add_tags.model); + // console.log(">>>>>>>>>>>>>>>>> getConnectionType add_tags:" + JSON.stringify(getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags'))); let cmd_addTags = new mzta_specialCommand({ prompt: specialFullPrompt_add_tags, llm: getConnectionType(prefs_aats, curr_prompt_add_tags, 'add_tags'), From fd97d302ef99aa3e6daa31526356a1955c4f7f7d Mon Sep 17 00:00:00 2001 From: mic Date: Sat, 3 Jan 2026 23:50:19 +0100 Subject: [PATCH 118/146] improved the uniqueness of the tag IDs --- js/mzta-utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index a99c70a9..b182ad99 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -408,10 +408,11 @@ export async function createTag(tag) { let prefs_tag = await browser.storage.sync.get({ add_tags_first_uppercase: prefs_default.add_tags_first_uppercase }); if(prefs_tag.add_tags_first_uppercase) tag = tag.toLowerCase().charAt(0).toUpperCase() + tag.toLowerCase().slice(1); try { + const tagKey = '$ta-' + generateCallID(16) + '-' + sanitizeString(tag); // Ensure uniqueness with a longer random ID if(await isThunderbird128OrGreater()) { - return browser.messages.tags.create('$ta-'+sanitizeString(tag), tag, generateHexColorForTag()); + return browser.messages.tags.create(tagKey, tag, generateHexColorForTag()); }else{ - return browser.messages.createTag('$ta-'+sanitizeString(tag), tag, generateHexColorForTag()); + return browser.messages.createTag(tagKey, tag, generateHexColorForTag()); } } catch (error) { console.error('[ThunderAI] Error creating tag:', error); From 1b5c90403084572b9a63d0ad7cd6c29565079ec8 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:12:28 +0100 Subject: [PATCH 119/146] the custom prompts reset button is cearling all specific api settings in the prompt. see #601 --- js/mzta-prompts.js | 22 ++++++++++++--- pages/customprompts/mzta-custom-prompts.js | 31 ++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/js/mzta-prompts.js b/js/mzta-prompts.js index 9ab9bff8..b598cbce 100644 --- a/js/mzta-prompts.js +++ b/js/mzta-prompts.js @@ -78,6 +78,8 @@ << All the API settings defined in the default options, with the same IDs. >> */ +import { integration_options_config } from "../../options/mzta-options-default.js"; + const defaultPrompts = [ { id: 'prompt_reply', @@ -433,6 +435,7 @@ async function getDefaultPrompts_withProps() { }) // console.log('>>>>>>>>>>>> getDefaultPrompts_withProps [prop saved] defaultPrompts_prop: ' + JSON.stringify(defaultPrompts_prop)); } + // console.log('>>>>>>>>>>>> getDefaultPrompts_withProps [final] defaultPrompts_prop: ' + JSON.stringify(defaultPrompts_prop)); return defaultPrompts_prop; } @@ -482,6 +485,7 @@ export async function setDefaultPromptsProperties(prompts) { } export async function setCustomPrompts(prompts) { + // console.log(">>>>>>>>>>>> setCustomPrompts prompts: " + JSON.stringify(prompts)); await browser.storage.local.set({_custom_prompt: prompts}); } @@ -534,7 +538,7 @@ export async function savePrompt(prompt) { throw new Error("Invalid prompt: " + JSON.stringify(prompt)); } // Special Prompt - if (prompt.is_special === "1") { + if ((prompt.is_special === "1")||(prompt.is_special === 1)) { let specialPrompts = await getSpecialPrompts(); let index = specialPrompts.findIndex(p => p.id === prompt.id); if (index === -1) { @@ -546,7 +550,7 @@ export async function savePrompt(prompt) { return; } // Custom Prompt - if (prompt.is_default === "0") { + if ((prompt.is_default === "0")||(prompt.is_default === 0)) { let customPrompts = await getCustomPrompts(); let index = customPrompts.findIndex(p => p.id === prompt.id); if (index === -1) { @@ -554,9 +558,10 @@ export async function savePrompt(prompt) { } else { customPrompts[index] = prompt; } + // console.log(">>>>>>>>>>>> savePrompt customPrompts: " + JSON.stringify(customPrompts)); await setCustomPrompts(customPrompts); } else { // Default Prompt - let defaultPrompts = getDefaultPrompts_withProps(); + let defaultPrompts = await getDefaultPrompts_withProps(); let index = defaultPrompts.findIndex(p => p.id === prompt.id); if (index === -1) { defaultPrompts.push(prompt); @@ -569,6 +574,17 @@ export async function savePrompt(prompt) { export async function clearPromptAPI(id){ let _prompt = await loadPrompt(id); + // console.log(">>>>>>>>>>>>> clearPromptAPI _prompt BEFORE: " + JSON.stringify(_prompt)); _prompt.api_type = ""; + // Reset all integration-specific settings to their default values + for (const [integration, options] of Object.entries(integration_options_config)) { + for (const key of Object.keys(options)) { + const propName = `${integration}_${key}`; + if (_prompt.hasOwnProperty(propName)) { + _prompt[propName] = ''; + } + } + } + // console.log(">>>>>>>>>>>>> clearPromptAPI _prompt AFTER: " + JSON.stringify(_prompt)); await savePrompt(_prompt); } \ No newline at end of file diff --git a/pages/customprompts/mzta-custom-prompts.js b/pages/customprompts/mzta-custom-prompts.js index 2b01f6e6..2a70510e 100644 --- a/pages/customprompts/mzta-custom-prompts.js +++ b/pages/customprompts/mzta-custom-prompts.js @@ -482,6 +482,37 @@ function handleEditClick(e) { 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(); } }).then(() => { populateConnectionUI(tr, id, prefix, selectId); From 4e1b20026bd15eb78cbe3b6291c499acba2288f1 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:14:28 +0100 Subject: [PATCH 120/146] version set to 3.8.0pre4 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index e18ffa08..5128f779 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "ThunderAI", "description": "__MSG_extensionDescription__", - "version": "3.8.0pre3", + "version": "3.8.0pre4", "author": "Mic (m@micz.it)", "homepage_url": "https://micz.it/thunderbird-addon-thunderai/", "browser_specific_settings": { From 1a28f5efba4741951c82e9e7530eed2479229ca2 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:30:39 +0100 Subject: [PATCH 121/146] log improved --- mzta-background.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mzta-background.js b/mzta-background.js index 5d6c9bc0..e2161b66 100644 --- a/mzta-background.js +++ b/mzta-background.js @@ -1041,7 +1041,7 @@ async function processEmails(messages, addTagsAuto, spamFilter) { ...getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']), do_debug: prefs_default.do_debug, }); - // console.log(">>>>>>>>>>>>>>>> getDynamicSettingsDefaults: " + JSON.stringify(getDynamicSettingsDefaults(['use_specific_integration', 'connection_type']))); + // console.log(">>>>>>>>>>>>>>>> prefs_aats: " + JSON.stringify(prefs_aats)); for await (let message of messages) { let curr_fullMessage = null; let msg_text = null; From f478516d608c9c59e743d9c47b731eadf6dd5242 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:31:06 +0100 Subject: [PATCH 122/146] clearing add_tags_connection_type pref when needed --- pages/addtags/mzta-add-tags.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pages/addtags/mzta-add-tags.js b/pages/addtags/mzta-add-tags.js index 7f323fd8..c2a20275 100644 --- a/pages/addtags/mzta-add-tags.js +++ b/pages/addtags/mzta-add-tags.js @@ -80,6 +80,7 @@ document.addEventListener('DOMContentLoaded', async () => { let addtags_textarea = document.getElementById('addtags_prompt_text'); let addtags_save_btn = document.getElementById('btn_save_prompt'); let addtags_reset_btn = document.getElementById('btn_reset_prompt'); + let add_tags_use_specific_integration = document.getElementById('add_tags_use_specific_integration'); addtags_textarea.addEventListener('input', (event) => { addtags_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_add_tags_full_text')); @@ -91,6 +92,12 @@ document.addEventListener('DOMContentLoaded', async () => { } }); + add_tags_use_specific_integration.addEventListener('change', (event) => { + if (!event.target.checked) { + browser.storage.sync.set({ add_tags_connection_type: '' }); + } + }); + let add_tags_auto_el = document.getElementById('add_tags_auto'); let add_tags_auto_only_inbox_tr = document.getElementById('add_tags_auto_only_inbox_tr'); let account_selector_container = document.getElementById('account_selector_container'); From 303bd86bac1f41208df4167f9df8e665447c3d98 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:33:20 +0100 Subject: [PATCH 123/146] clearing spamfilter_connection_type pref when needed --- pages/spamfilter/mzta-spamfilter.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pages/spamfilter/mzta-spamfilter.js b/pages/spamfilter/mzta-spamfilter.js index e2e0a36a..a40cbe21 100644 --- a/pages/spamfilter/mzta-spamfilter.js +++ b/pages/spamfilter/mzta-spamfilter.js @@ -80,6 +80,7 @@ document.addEventListener('DOMContentLoaded', async () => { let spamfilter_textarea = document.getElementById('spamfilter_prompt_text'); let spamfilter_save_btn = document.getElementById('btn_save_prompt'); let spamfilter_reset_btn = document.getElementById('btn_reset_prompt'); + let spamfilter_use_specific_integration = document.getElementById('spamfilter_use_specific_integration'); spamfilter_textarea.addEventListener('input', (event) => { spamfilter_reset_btn.disabled = (event.target.value === browser.i18n.getMessage('prompt_spamfilter_full_text')); @@ -91,6 +92,12 @@ document.addEventListener('DOMContentLoaded', async () => { } }); + spamfilter_use_specific_integration.addEventListener('change', (event) => { + if (!event.target.checked) { + browser.storage.sync.set({ spamfilter_connection_type: '' }); + } + }); + spamfilter_reset_btn.addEventListener('click', () => { spamfilter_textarea.value = browser.i18n.getMessage('prompt_spamfilter_full_text'); spamfilter_reset_btn.disabled = true; From d0fac711fb27e242f73d5edfa16b7046b56df9f4 Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:43:39 +0100 Subject: [PATCH 124/146] getConnectionType improved. see #604 --- js/mzta-utils.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/js/mzta-utils.js b/js/mzta-utils.js index b182ad99..67ce0823 100644 --- a/js/mzta-utils.js +++ b/js/mzta-utils.js @@ -627,25 +627,18 @@ export function isAPIKeyValue(id){ return id.endsWith('_api_key'); } -export function getConnectionType(prefsOrType, prompt, prefixOrSpecific = null) { +export function getConnectionType(prefs, prompt, prefix = null) { let defaultType = ''; let specificType = ''; - if (typeof prefsOrType === 'object' && prefsOrType !== null) { - // New signature: (prefs, prompt, prefix) - defaultType = prefsOrType.connection_type; - if (typeof prefixOrSpecific === 'string' && prefixOrSpecific) { - const prefix = prefixOrSpecific; - const useSpecific = getDynamicSettingValue(prefsOrType, prefix, 'use_specific_integration'); + if (prefs !== null) { + defaultType = prefs.connection_type; + if (typeof prefix === 'string' && prefix) { + const useSpecific = getDynamicSettingValue(prefs, prefix, 'use_specific_integration'); if (useSpecific) { - specificType = getDynamicSettingValue(prefsOrType, prefix, 'connection_type'); + specificType = getDynamicSettingValue(prefs, prefix, 'connection_type'); } } - } else { - // Old signature / Direct usage: (connection_type_string, prompt, [specific_type_string]) - if (typeof prefixOrSpecific === 'string') { - specificType = prefixOrSpecific; - } } if (specificType && specificType !== '') return specificType; From 1779a30c84d6069eb4d1ba4fb8c17519cf3325eb Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 17:47:53 +0100 Subject: [PATCH 125/146] getConnectionType call updated. see #604 --- js/mzta-menus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mzta-menus.js b/js/mzta-menus.js index 546b69c0..a74124ed 100644 --- a/js/mzta-menus.js +++ b/js/mzta-menus.js @@ -206,7 +206,7 @@ export class mzta_Menus { default_chatgpt_lang: prefs_default.default_chatgpt_lang, do_debug: prefs_default.do_debug, }); - let def_conntype = getConnectionType(prefs_at.connection_type, curr_prompt); + let def_conntype = getConnectionType(prefs_at, curr_prompt, 'add_tags'); if((def_conntype === '')||(def_conntype === null)||(def_conntype === undefined)||(def_conntype === 'chatgpt_web')){ console.error("[ThunderAI | AddTags] Invalid connection type: " + def_conntype); taWorkingStatus.stopWorking(); From 4aeab58a3511ef7c16baf0669393124d59882a6b Mon Sep 17 00:00:00 2001 From: mic Date: Sun, 4 Jan 2026 23:29:50 +0100 Subject: [PATCH 126/146] release notes updated --- CHANGELOG.md | 3 ++- options/mzta-release-notes.html | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7f39c44..33b28cd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,9 @@ -

    Version 3.8.0 - ??/??/2025

    +

    Version 3.8.0 - ??/??/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].
    • [All APIs] Added the temperature parameter [#561].
    • [OpenAI API] Model filtering improved when choosing a model in the options page.
    • diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 6107811c..2863c054 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -7,8 +7,9 @@

      ThunderAI Release Notes

      -

      Version 3.8.0 - ??/??/2025

      +

      Version 3.8.0 - ??/??/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].
      • [All APIs] Added the temperature parameter [#561].
      • [OpenAI API] Model filtering improved when choosing a model in the options page.
      • From b0536bea271b3c99963f4a9888b53c3a4d0a3250 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sat, 3 Jan 2026 23:14:19 +0100 Subject: [PATCH 127/146] Translated using Weblate (Swedish) Currently translated at 47.2% (204 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 7d9b5c0b..9e17ca21 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -528,7 +528,7 @@ "message": "Vid inloggningsproblem i ThunderAI-fönstret, öppna ChatGPT i en ny flik med knappen till höger, logga in, stäng sedan fliken och fortsätt använda ThunderAI." }, "OpenChatGPTTab_Info2": { - "message": "Om du öppnar ChatGPT Web härifrån tillämpas alla konfigurerade inställningar för modellen, projektet och den anpassade GPT:n." + "message": "Om du öppnar ChatGPT webbgränssnitt härifrån tillämpas alla konfigurerade inställningar för modellen, projektet och den anpassade GPT:n." }, "placeholder_mail_text_body": { "message": "Mejltext" @@ -585,9 +585,27 @@ "message": "Det här är modellen som kommer att tillämpas för ChatGPT:s webbgränssnitt. Om ingen modell anges eller om en felaktig modell anges, kommer standardmodellen att ställas in av ChatGPT på webbsidan. Den här inställningen fungerar inte med ett gratis ChatGPT-konto." }, "prefs_OptionText_chatgpt_web_tempchat": { - "message": "ChatGPT Web tillfällig chatt" + "message": "ChatGPT webbgränssnitt tillfällig chatt" }, "prefs_OptionText_chatgpt_web_tempchat_info": { "message": "Om markerad kommer den tillfälliga chatten att användas i ChatGPT:s webbgränssnitt." + }, + "chatgpt_btn_model": { + "message": "Använd den nuvarande modellen" + }, + "SendingPrompt": { + "message": "Skickar prompt..." + }, + "AllowedValues": { + "message": "Tillåtna värden" + }, + "prefs_OptionText_btnManagePrompts_infoline": { + "message": "Du kan använda ytterligare dataplatshållare." + }, + "prefs_OptionText_openai_comp_use_v1": { + "message": "Behåll \"v1\"-kompatibiliteten" + }, + "prefs_OptionText_openai_comp_use_v1_info": { + "message": "Om markerat kommer segmentet \"v1\" i sökvägen för API-anrop att behållas, som \"http://localhost:1234/v1/chat/completions\"." } } From 71ea10dd55f1d0226ab8a823a99579e8bd920ad3 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sat, 3 Jan 2026 23:14:53 +0100 Subject: [PATCH 128/146] Translated using Weblate (Swedish) Currently translated at 47.4% (205 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 9e17ca21..b5ea87d8 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -607,5 +607,11 @@ }, "prefs_OptionText_openai_comp_use_v1_info": { "message": "Om markerat kommer segmentet \"v1\" i sökvägen för API-anrop att behållas, som \"http://localhost:1234/v1/chat/completions\"." + }, + "prefs_OptionText_openai_comp_info_remote": { + "message": "Här kan du även ange en fjärrserveradress." + }, + "prefs_OptionText_owl_warning": { + "message": "Det verkar som att minst ett av dina konton använder tillägget Owl for Exchange. Det finns ett känt problem mellan Thunderbird och Owl, vilket för närvarande åtgärdas. För närvarande kan du använda ThunderAI när du skriver e-postmeddelanden, men inte när du läser dem." } } From b3af371a6bff446277223683f5c896f09adde6c9 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sat, 3 Jan 2026 23:17:14 +0100 Subject: [PATCH 129/146] Translated using Weblate (Swedish) Currently translated at 49.5% (214 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index b5ea87d8..5b2c96e4 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -613,5 +613,32 @@ }, "prefs_OptionText_owl_warning": { "message": "Det verkar som att minst ett av dina konton använder tillägget Owl for Exchange. Det finns ett känt problem mellan Thunderbird och Owl, vilket för närvarande åtgärdas. För närvarande kan du använda ThunderAI när du skriver e-postmeddelanden, men inte när du läser dem." + }, + "prefs_OptionText_chatgpt_web_model_tooltip": { + "message": "Klicka på ett värde för att ställa in det." + }, + "prompt_reply_full_text": { + "message": "Svara på följande e-postmeddelande. Svara endast med den text som behövs och utan extra kommentarer eller annan text." + }, + "prompt_reply_additional_text": { + "message": "Lägg inte till ämnesraden i svaret." + }, + "reply_same_lang": { + "message": "Svara på samma språk." + }, + "sign_msg_as": { + "message": "Signera meddelandet som" + }, + "prompt_reply_advanced_full_text": { + "message": "Svara på följande e-postmeddelande \"{%selected_text%}\", med tanke på att detta är hela tråden med e-postmeddelanden \"{%mail_html_body%}\". Svara endast med den text som behövs och utan extra kommentarer eller annan text." + }, + "prompt_reply_custom_command_full_text": { + "message": "Svara på följande e-postmeddelande \"{%mail_text_body%}\". {%additional_text%}. Svara endast med den text som behövs och utan extra kommentarer eller annan text." + }, + "prompt_rewrite_full_text": { + "message": "Skriv om följande text för att vara mer artig. Svara endast med den omskrivna texten och utan extra kommentarer eller annan text." + }, + "prompt_rewrite_formal_full_text": { + "message": "Skriv om följande text för att göra den mer formell. Svara endast med den omskrivna texten och utan extra kommentarer eller annan text." } } From dacfc6377ba256b4929a9f8d7473499d9ca85a6e Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sun, 4 Jan 2026 20:01:50 +0100 Subject: [PATCH 130/146] Translated using Weblate (Swedish) Currently translated at 62.2% (269 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 169 +++++++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 2 deletions(-) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 5b2c96e4..baf352f4 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -54,7 +54,7 @@ "message": "Försöka igen" }, "placeholder_selected_html": { - "message": "Vald HTML" + "message": "Markerad HTML" }, "placeholder_additional_text": { "message": "Ytterligare text" @@ -549,7 +549,7 @@ "message": "E-postrubriker" }, "placeholder_selected_text": { - "message": "Vald text" + "message": "Makerad text" }, "placeholder_junk_score": { "message": "Skräppoäng" @@ -640,5 +640,170 @@ }, "prompt_rewrite_formal_full_text": { "message": "Skriv om följande text för att göra den mer formell. Svara endast med den omskrivna texten och utan extra kommentarer eller annan text." + }, + "prompt_summarize_this_full_text": { + "message": "Sammanfatta följande e-postmeddelande i en punktlista." + }, + "prompt_translate_this_full_text": { + "message": "Översätt följande e-postmeddelande till" + }, + "prompt_this_full_text": { + "message": "Svara endast med den text som behövs och utan extra kommentarer eller annan text." + }, + "prefs_OptionText_add_tags": { + "message": "Lägg till taggar i e-postmeddelanden" + }, + "prefs_OptionText_add_tags_Info": { + "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att tillämpa taggar på e-postmeddelanden." + }, + "prompt_add_tags": { + "message": "Lägg till taggar i det här e-postmeddelandet" + }, + "prompt_proofread_this": { + "message": "Korrekturläs detta e-postmeddelande" + }, + "prompt_proofread_this_full_text": { + "message": "Korrekturläs följande e-postmeddelande och korrigera eventuella stavfel eller grammatikfel. Svara endast med den korrigerade texten och utan extra kommentarer eller annan text.\n\n\"{%mail_typed_text%}\"" + }, + "AddTags_info_default": { + "message": "På den här sidan kan du ändra standardprompten som används för att lägga till taggar i e-postmeddelanden och hantera undantagslistan." + }, + "AddTags_prompt_text_title": { + "message": "Aktuell prompttext" + }, + "prefs_SurveyLinkText": { + "message": "Dela din feedback och hjälp till att förbättra ThunderAI!" + }, + "prefs_SurveyLinkText2": { + "message": "Klicka här, det tar bara en minut!" + }, + "prefs_OpenAIComp_ForceModel": { + "message": "Infoga modell manuellt" + }, + "OpenAIComp_force_model_ask": { + "message": "Ange här modellnamnet du vill använda." + }, + "prefs_OptionText_add_tags_force_lang": { + "message": "Tvinga språk" + }, + "prefs_OptionText_add_tags_force_lang_Info": { + "message": "Om markerat kommer taggarnas språk att tvingas matcha språket som definierats på ThunderAI-inställningssidan, om det anges." + }, + "prompt_add_tags_force_lang": { + "message": "Taggarna måste vara skrivna på" + }, + "prefs_Connection_type_Google_Gemini_API": { + "message": "Google Gemini API" + }, + "prefs_GoogleGemini_API_Key": { + "message": "API-nyckel" + }, + "GoogleGemini_Models": { + "message": "Google Gemini API-modeller" + }, + "GoogleGemini_Models_Fetch": { + "message": "Uppdatera listan över Google Gemini-modeller" + }, + "GoogleGemini_Models_Error_fetching": { + "message": "Fel vid försök att hämta Google Gemini-modeller" + }, + "google_gemini_api_request_failed": { + "message": "Google Gemini API-begäran misslyckades" + }, + "google_gemini_empty_apikey": { + "message": "Du har inte lagt till en API-nyckel för Google Gemini API. Vänligen ange en på alternativsidan." + }, + "google_gemini_empty_model": { + "message": "Du har inte valt någon modell för Google Gemini API. Välj en på alternativsidan." + }, + "GoogleGemini_SystemInstruction": { + "message": "Systeminstruktion" + }, + "GoogleGemini_SystemInstruction_Info": { + "message": "När du anger en systeminstruktion ger du modellen ytterligare kontext för att förstå uppgiften, ge mer anpassade svar och följa specifika riktlinjer för den prompt som skickas." + }, + "ChatGPT_Developer_Messages": { + "message": "Utvecklarmeddelanden" + }, + "ChatGPT_Developer_Messages_Info": { + "message": "När du anger utvecklarmeddelandena ger du modellen ytterligare kontext för att förstå uppgiften, ge mer anpassade svar och följa specifika riktlinjer för den prompt som skickas." + }, + "prefs_OptionText_btnManagePrompts_infoline3": { + "message": "Du kan använda dataplatshållaren {%tags_full_list%} i prompten för att lista tillgängliga taggar. Med en lämplig prompt kan du sedan tvinga taggarna att endast väljas från listan över de som redan finns." + }, + "prefs_OptionText_get_calendar_event": { + "message": "Lägg till en ny kalenderhändelse från markerad text" + }, + "thunderai_def_lang": { + "message": "Standardspråk som definierat i ThunderAI-alternativ." + }, + "placeholder_mail_attachments_info": { + "message": "Information om bilagorna i e-postmeddelandet" + }, + "prefs_OptionText_spamfilter": { + "message": "Automatiskt skräppostfilter" + }, + "prefs_OptionText_spamfilter_Info": { + "message": "Om markerat kommer ThunderAI automatiskt att flytta skräppostmeddelanden till skräppostmappen." + }, + "prefs_OptionText_btnManageSpamFilterInfo": { + "message": "Hantera inställningar för skräppostfilter" + }, + "SpamFilter_PageTitle": { + "message": "Hantera inställningar för skräppostfilter" + }, + "SpamFilter_info_default": { + "message": "På den här sidan kan du ändra standardprompten som används för att upptäcka skräppost." + }, + "SpamFilter_prompt_text_title": { + "message": "Aktuell prompttext" + }, + "prompt_spamfilter": { + "message": "Upptäck skräppostmeddelanden" + }, + "SpamFilter_prompt_prefs_title": { + "message": "Alternativ för skräppostfilter" + }, + "prefs_OptionText_use_specific_integration": { + "message": "Använd specifik modell och API" + }, + "prefs_OptionText_spamfilter_use_specific_integration_Info": { + "message": "Om markerat kommer modellen och API:et som anges nedan att användas för spamfiltret, oavsett vilket som valts på ThunderAI-alternativsidan." + }, + "prefs_OptionText_spamfilter_threshold_Info": { + "message": "Om värdet som returneras av AI:n överstiger detta tröskelvärde flyttas e-postmeddelandet till skräppostmappen." + }, + "spamfilter_threshold_too_low": { + "message": "Tröskeln för skräppost är för låg! Du kommer troligtvis att markera för många e-postmeddelanden som skräppost!" + }, + "spamfilter_threshold_zero": { + "message": "Tröskeln för skräppost är noll! Du kommer att markera alla e-postmeddelanden som skräppost!" + }, + "Subject": { + "message": "Ämne" + }, + "From": { + "message": "Från" + }, + "Spam_Value": { + "message": "Skräppostvärde" + }, + "Moved_to_Spam": { + "message": "Flyttad till skräppost" + }, + "Explanation": { + "message": "Förklaring" + }, + "Report_Date": { + "message": "Rapportdatum" + }, + "spamfilter_moved": { + "message": "Ja" + }, + "spamfilter_not_moved": { + "message": "Nej" + }, + "context_menu_mzta-add-tags": { + "message": "Lägg till taggar" } } From daaaaf7e2da4e2029b43b5666db60ff93da8984e Mon Sep 17 00:00:00 2001 From: Thomas Hegghammer <64712218+Hegghammer@users.noreply.github.com> Date: Sun, 4 Jan 2026 22:21:10 +0100 Subject: [PATCH 131/146] =?UTF-8?q?Added=20translation=20using=20Weblate?= =?UTF-8?q?=20(Norwegian=20Bokm=C3=A5l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _locales/nb_NO/messages.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 _locales/nb_NO/messages.json diff --git a/_locales/nb_NO/messages.json b/_locales/nb_NO/messages.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/_locales/nb_NO/messages.json @@ -0,0 +1 @@ +{} From e418e848a948c78cfcf61dc189ae220cc01674c3 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sun, 4 Jan 2026 23:29:53 +0100 Subject: [PATCH 132/146] Translated using Weblate (Swedish) Currently translated at 89.1% (385 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 358 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index baf352f4..40a4568b 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -805,5 +805,363 @@ }, "context_menu_mzta-add-tags": { "message": "Lägg till taggar" + }, + "context_menu_mzta-spamfilter": { + "message": "Analysera för skräppost" + }, + "prefs_OptionText_add_tags_context_menu": { + "message": "Visa snabbmenyn \"Lägg till taggar\"" + }, + "prefs_OptionText_add_tags_context_menu_Info": { + "message": "Om markerat visas snabbmenyn \"Lägg till taggar\" när du högerklickar på ett e-postmeddelande i meddelandelistan." + }, + "prefs_OptionText_spamfilter_context_menu": { + "message": "Visa snabbmenyalternativet \"Analysera för skräppost\"" + }, + "prefs_OptionText_spamfilter_context_menu_Info": { + "message": "Om markerat visas snabbmenyn \"Analysera för skräppost\" när du högerklickar på ett e-postmeddelande i meddelandelistan." + }, + "noActiveCalendar": { + "message": "Ingen redigerbar kalender hittades!" + }, + "btn_show_differences": { + "message": "Visa skillnader" + }, + "chatgpt_win_diff_title": { + "message": "Skillnader mellan originaltexten och den modifierade texten" + }, + "apiwebchat_you": { + "message": "Du" + }, + "apiwebchat_info": { + "message": "Information" + }, + "apiwebchat_error": { + "message": "Fel" + }, + "apiwebchat_use_this_answer": { + "message": "Använd detta svar" + }, + "apiwebchat_stopping": { + "message": "Stoppar" + }, + "apiwebchat_receiving_data": { + "message": "Mottar data" + }, + "hyprland_warning": { + "message": "Om du har problem med att öppna AI-chattfönstret kan du prova att ställa in höjd- och breddvärdena till 0. Det här problemet kan uppstå i vissa Linux-miljöer, till exempel när du använder Hyprland." + }, + "remember_CORS": { + "message": "Kom ihåg att du måste konfigurera CORS-inställningarna på servern!" + }, + "maybe_CORS_openai_comp": { + "message": "Att använda OpenAI-kompatibelt API kan kräva att CORS-inställningar konfigureras på servern." + }, + "CORS_alternative_1": { + "message": "Problem med att ställa in CORS?" + }, + "CORS_alternative_2": { + "message": "Tryck på knappen nedan för att ge behörighet för att undvika eventuella CORS-problem." + }, + "customPrompts_Properties": { + "message": "Egenskaper" + }, + "customPrompts_show_additional_info": { + "message": "Visa ytterligare egenskaper" + }, + "customPrompts_hide_additional_info": { + "message": "Dölj ytterligare egenskaper" + }, + "customPrompts_show_additional_info_show": { + "message": "Ytterligare egenskaper" + }, + "prefs_OptionText_CustomGPT_Warn": { + "message": "Om ett projekt anges i alternativen eller i en prompt kommer det att åsidosätta inställningen för anpassad GPT." + }, + "prefs_OptionText_Project_No_temporary_chat_warn": { + "message": "Om ett projekt anges i alternativen eller i en prompt kommer den tillfälliga chatten inte att användas." + }, + "prefs_Anthropic_API_Key": { + "message": "Claude API-nyckel" + }, + "prefs_Connection_type_Anthropic_API": { + "message": "Claude API" + }, + "Anthropic_Models": { + "message": "Claude-modeller" + }, + "Anthropic_Models_Fetch": { + "message": "Uppdatera listan med Claude-modeller" + }, + "Anthropic_Models_Error_fetching": { + "message": "Fel vid försök att hämta Claude-modeller" + }, + "Anthropic_Version": { + "message": "Claude API-version" + }, + "Anthropic_Version_Info": { + "message": "KRÄVS. Ändra inte detta värde om du inte vet vad du gör. Mer information finns på:" + }, + "prefs_OptionText_anthropic_max_tokens": { + "message": "Max antal tokens" + }, + "prefs_OptionText_anthropic_max_tokens_Info": { + "message": "Det maximala antalet tokens som ska genereras i slutförandet. Antalet tokens för din prompt plus max_tokens får inte överstiga modellens kontextlängd." + }, + "anthropic_empty_apikey": { + "message": "Du har inte lagt till en API-nyckel för Claude API. Vänligen ange en på alternativsidan." + }, + "anthropic_empty_model": { + "message": "Du har inte valt någon modell för Claude API. Välj en på alternativsidan." + }, + "anthropic_empty_version": { + "message": "Du har inte lagt till en versionssträng för Claude API. Vänligen infoga en på alternativsidan." + }, + "anthropic_api_request_failed": { + "message": "Claude API-begäran misslyckades" + }, + "_api_connecting": { + "message": "Försöker ansluta till $api_string$ med följande konfiguration...", + "placeholders": { + "api_string": { + "content": "$1" + } + } + }, + "_api_connecting_model": { + "message": "Modell" + }, + "_api_connecting_host": { + "message": "Värd" + }, + "_api_connecting_version": { + "message": "Version" + }, + "prefs_OpenAIComp_AvailableServices": { + "message": "Tillgängliga tjänster" + }, + "prefs_OpenAIComp_AvailableServices_Info": { + "message": "Välj en av tjänsterna som är tillgängliga för OpenAI Compatible API eller infoga en manuellt." + }, + "Custom": { + "message": "Anpassad" + }, + "OpenAIComp_Configs_ConfirmApply": { + "message": "Är du säker på att du vill använda konfigurationen \"$config_name$\"?", + "placeholders": { + "config_name": { + "content": "$1" + } + } + }, + "apiwebchat_selection_info": { + "message": "Om du väljer text kommer endast den delen att beaktas." + }, + "ChatGPT_chatgpt_api_store": { + "message": "Använd lagring" + }, + "ChatGPT_chatgpt_api_store_info": { + "message": "Om markerat kommer dina chattar att lagras av OpenAI." + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "Vilken samplingstemperatur som ska användas, mellan 0 och 2. Högre värden som 0,8 gör utdata mer slumpmässig, medan lägre värden som 0,2 gör den mer fokuserad och deterministisk." + }, + "prefs_ollama_temperature_Info": { + "message": "Modellens temperatur. Att öka temperaturen gör att modellen svarar mer kreativt. Standardvärdet är 0,8. Det rekommenderas att använda värden mellan 0 och 1." + }, + "prefs_ollama_think": { + "message": "Aktivera tänkande" + }, + "prefs_ollama_think_Info": { + "message": "Om markerat kommer modellen att tänka innan den svarar. Det här alternativet fungerar bara med modeller som stöder funktionen \"tänk\"." + }, + "chatgpt_win_change_reply_type": { + "message": "Klicka för att ändra svarstypen" + }, + "SelectAll": { + "message": "Markera alla" + }, + "DeselectAll": { + "message": "Avmarkera alla" + }, + "Anthropic_System_Prompt": { + "message": "Systemprompt" + }, + "Anthropic_System_Prompt_Info": { + "message": "Du kan förbättra Claudes prestanda genom att använda en systemprompt för att ge den en roll. Denna teknik, känd som rollprompt, är det mest kraftfulla sättet att använda systempromptar med Claude. Rätt roll kan förvandla Claude från en allmän assistent till din virtuella domänexpert." + }, + "Optional_Permission_Denied_Model_Fetching": { + "message": "Du har nekat den valfria behörighet som krävs för att hämta modeller för den här integrationen." + }, + "Select_your_timezone": { + "message": "Välj din tidszon" + }, + "prefs_OptionText_calendar_enforce_timezone": { + "message": "Tvinga fram den angivna tidszonen" + }, + "prefs_OptionText_calendar_enforce_timezone_Info": { + "message": "Om markerad kommer den angivna tidszonen att tillämpas för kalenderhändelser och uppgifter." + }, + "prefs_OptionText_btnManageCalendarEventInfo": { + "message": "Hantera inställningar för kalenderhändelser" + }, + "GetCalendarEvent_PageTitle": { + "message": "Hantera inställningar för kalenderhändelser" + }, + "GetCalendarEvent_info_default": { + "message": "På den här sidan kan du ändra standardprompten som används för att hämta en kalenderhändelse från markerad text." + }, + "GetCalendarEvent_prompt_text_title": { + "message": "Aktuell prompttext" + }, + "prefs_OptionText_AdvancedPromptResponse_infoline2": { + "message": "Du kan ändra prompten som du vill, men svaret som tas emot från AI:n måste vara i JSON-format enligt standardprompten!" + }, + "prefs_OptionText_get_calendar_event_Sparks_not_present": { + "message": "För att använda kalenderhändelser och uppgifter, installera ThunderAI Sparks-tillägget." + }, + "prefs_OptionText_get_calendar_event_Sparks_wrong_version": { + "message": "För att använda kalenderhändelser och uppgifter, installera en uppdaterad version av ThunderAI Sparks-tillägget." + }, + "GetTask_PageTitle": { + "message": "Hantera inställningar för uppgifter" + }, + "GetTask_info_default": { + "message": "På den här sidan kan du ändra standardprompten som används för att hämta en uppgift från markerad text." + }, + "prefs_OptionText_btnManageTaskInfo": { + "message": "Hantera inställningar för uppgifter" + }, + "prefs_OptionText_download_now": { + "message": "Ladda ner ThunderAI Sparks nu!" + }, + "placeholder_mail_datetime": { + "message": "Datum och tid för e-postmeddelandet" + }, + "placeholder_current_datetime": { + "message": "Aktuellt datum och tid" + }, + "calendar_getting_data_error": { + "message": "Fel vid hämtning av kalenderhändelsedata" + }, + "calendar_opening_dialog_error": { + "message": "Fel vid öppning av dialogrutan för kalenderhändelse" + }, + "task_getting_data_error": { + "message": "Fel vid hämtning av uppgiftsdata" + }, + "task_opening_dialog_error": { + "message": "Fel vid öppning av uppgiftsdialogrutan" + }, + "no_valid_data_received": { + "message": "Inga giltiga data mottagna från AI:n." + }, + "prefs_OptionText_add_tags_auto": { + "message": "Lägg till taggar automatiskt" + }, + "prefs_OptionText_add_tags_auto_Info": { + "message": "Om markerat kommer AI:n automatiskt att lägga till taggar till nyligen mottagna e-postmeddelanden." + }, + "prefs_OptionText_add_tags_auto_Info2": { + "message": "Välj vilket konto du vill aktivera den här funktionen för längst ner på sidan." + }, + "prefs_OptionText_add_tags_auto_force_existing": { + "message": "Tvinga fram befintliga taggar" + }, + "prefs_OptionText_add_tags_auto_force_existing_Info": { + "message": "Om markerat kommer AI:n endast att lägga till befintliga taggar och inte skapa nya taggar." + }, + "prefs_OptionText_add_tags_auto_uselist": { + "message": "Använd endast dessa taggar" + }, + "prefs_OptionText_add_tags_auto_uselist_Info": { + "message": "Om markerat kommer AI:n endast att lägga till taggar från listan nedan." + }, + "prefs_OptionText_add_tags_auto_uselist_list_Info": { + "message": "Listan måste innehålla minst en tagg. Lägg till en tagg per rad, eller separera med ett kommatecken." + }, + "prompt_add_tags_use_list": { + "message": "Använd endast taggarna i den här kommaseparerade listan" + }, + "prefs_OptionText_add_tags_auto_only_inbox": { + "message": "Lägg bara till taggar i e-postmeddelanden i inkorgen" + }, + "prefs_OptionText_add_tags_auto_only_inbox_Info": { + "message": "Om markerat kommer AI:n bara att lägga till taggar till e-postmeddelanden som tas emot i inkorgen." + }, + "prefs_OptionText_add_tags_use_specific_integration_Info": { + "message": "Om markerat kommer modellen och API:et som anges nedan att användas för att lägga till taggar i e-postmeddelanden, oavsett vilket som valts på ThunderAI-alternativsidan." + }, + "placeholder_thunderai_def_sign": { + "message": "Standardsignatur som definierad i ThunderAI-alternativ." + }, + "empty": { + "message": "Den här platshållaren lägger inte till någon text, men den förhindrar att e-postmeddelandets brödtext läggs till automatiskt i slutet av prompten." + }, + "prefs_OptionText_spamfilter_threshold": { + "message": "Tröskel skräppost" + }, + "spamfilter_no_reports": { + "message": "Inga meddelanden har ännu granskats för skräppost. Här hittar du en lista över de senaste 100 skräppostrapporterna för den aktuella sessionen." + }, + "SpamReport_Title": { + "message": "Rapporter om skräppostfilter" + }, + "customDataPH_ExportAll": { + "message": "Exportera alla anpassade dataplatshållare" + }, + "customDataPH_Import": { + "message": "Importera nya dataplatshållare" + }, + "customDataPH_form_label_Text": { + "message": "Dataplatshållartext" + }, + "customDataPH_saving_custom": { + "message": "Sparar anpassade dataplatshållare..." + }, + "customDataPH_saved": { + "message": "Anpassade dataplatshållare sparade!" + }, + "customDataPH_btnAddNewCommit": { + "message": "Lägg till dataplatshållaren" + }, + "importCustomDataPH_confirmText": { + "message": "Du håller på att importera nya anpassade dataplatshållare." + }, + "importCustomDataPH_start_import": { + "message": "Startar import av anpassade dataplatshållare..." + }, + "importCustomDataPH_import_completed": { + "message": "Import av anpassade dataplatshållare är klar! Du måste klicka på knappen \"Spara alla\" för att spara dina ändringar." + }, + "importCustomDataPH_invalidFile": { + "message": "Filen du försöker importera är inte en giltig anpassad dataplatshållarfil." + }, + "importCustomDataPH_invalidDataPHs": { + "message": "Filen du försöker importera innehåller inga giltiga anpassade dataplatshållare." + }, + "customDataPH_add_to_menu": { + "message": "Kan användas i promptar som lagts till i menyn" + }, + "prefs_OptionText_chatgpt_web_br_replace_info": { + "message": "Observera att alla
        -taggar i AI:ns svar kommer att ersättas med radbrytningar." + }, + "prefs_OpenAIComp_ClearModelsList": { + "message": "Rensa modelllistan" + }, + "OpenAIComp_ClearModelsList_Confirm": { + "message": "Är du säker på att du vill rensa modellistan? Den här åtgärden kan inte ångras." + }, + "prefs_api_temperature": { + "message": "Temperatur" + }, + "prefs_openai_comp_temperature_Info": { + "message": "Vilken samplingstemperatur som ska användas, mellan 0 och 2. Högre värden som 0,8 gör utdata mer slumpmässig, medan lägre värden som 0,2 gör den mer fokuserad och deterministisk." + }, + "chatgpt_click_force_completion": { + "message": "Det verkar som att det inte går att få tag på det om inte ChatGPT är klar. Klicka här för att tvinga fram slutförandet av jobbet." + }, + "warn_API_needed": { + "message": "För att använda den här funktionen behöver du en API-integration snarare än ChatGPT-webbintegrationen. Du kan definiera ett specifikt API på sidan med funktionsinställningar genom att först markera kryssrutan ovan och sedan klicka på knappen till vänster." } } From 02ea92938e316af0d571bfe2475193b6a33ecd37 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sun, 4 Jan 2026 23:44:48 +0100 Subject: [PATCH 133/146] Translated using Weblate (Swedish) Currently translated at 96.7% (418 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 40a4568b..0533d53a 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -1163,5 +1163,104 @@ }, "warn_API_needed": { "message": "För att använda den här funktionen behöver du en API-integration snarare än ChatGPT-webbintegrationen. Du kan definiera ett specifikt API på sidan med funktionsinställningar genom att först markera kryssrutan ovan och sedan klicka på knappen till vänster." + }, + "prompt_classify_full_text": { + "message": "Klassificera följande text i termer av artighet, värme, formalitet, självsäkerhet och anstötlighet. Ange en procentandel för varje kategori. Svara endast med kategorin och poängsätt utan extra kommentarer eller annan text." + }, + "prompt_get_calendar_event": { + "message": "Lägg till en ny kalenderhändelse" + }, + "prompt_get_task": { + "message": "Lägg till en ny uppgift" + }, + "prefs_OptionText_get_calendar_event_Info": { + "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att hämta information om kalenderhändelser från markerad text." + }, + "get_calendar_event_prompt_prefs_title": { + "message": "Alternativ för kalenderhändelser" + }, + "prefs_OptionText_get_task": { + "message": "Lägg till en ny uppgift från markerad text" + }, + "prefs_OptionText_get_task_Info": { + "message": "Om markerat kommer ett alternativ att inkluderas i menyn för att hämta uppgiftsinformation från markerad text." + }, + "get_task_prompt_prefs_title": { + "message": "Uppgiftsalternativ" + }, + "prefs_OptionText_composing_plain_text": { + "message": "Skriva i oformaterad text" + }, + "prefs_OptionText_composing_plain_text_Info": { + "message": "Markera det här alternativet om du skriver e-postmeddelandena i oformaterad text." + }, + "Replace_No_Selected_Text": { + "message": "Ingen text vald, vill du infoga AI:ns svar i början av e-postmeddelandet?" + }, + "prefs_ollama_num_ctx": { + "message": "Antal kontexttokens" + }, + "prefs_ollama_num_ctx_Info": { + "message": "Antalet kontexttokens som ska användas för Ollama API. Ställ in på 0 om du inte vill skicka den som en parameter till servern." + }, + "ask_chatgptweb_permission_1": { + "message": "För att använda ChatGPT-webbintegrationen måste du ge nödvändig behörighet." + }, + "ask_anthropic_api_permission_1": { + "message": "För att använda Claude API-integrationen måste du ge nödvändig behörighet." + }, + "ask_openai_api_permission_1": { + "message": "För att använda OpenAI API-integrationen måste du ge nödvändig behörighet." + }, + "ask_integration_permission_2_popup": { + "message": "Klicka här för att öppna en ny flik och följ instruktionerna." + }, + "ask_integration_permission_2": { + "message": "Klicka här för att fortsätta." + }, + "ask_integration_permission_ok": { + "message": "Tillstånd beviljat. Du kan klicka här för att stänga den här fliken och återgå till huvudfönstret." + }, + "AccountSelector_AutoTags": { + "message": "Välj de konton där automatisk taggning är aktiverad" + }, + "AccountSelector_AutoTags_infoline": { + "message": "Varje ändring sparas omedelbart." + }, + "AccountSelector_Spamfilter": { + "message": "Välj de konton där skräppostfiltret är aktiverat" + }, + "prefs_OptionText_chatgpt_web_project": { + "message": "ChatGPT webbprojekt" + }, + "prefs_OptionText_chatgpt_web_project_info": { + "message": "Detta är projektet som kommer att tillämpas för ChatGPT-webbgränssnittet." + }, + "prefs_OptionText_chatgpt_web_custom_gpt": { + "message": "ChatGPT webbanpassad GPT" + }, + "prefs_OptionText_chatgpt_web_custom_gpt_info": { + "message": "Detta är den anpassade GPT som kommer att tillämpas för ChatGPT-webbgränssnittet." + }, + "prefs_OptionText_chatgpt_web_custom_data_info": { + "message": "Detta måste vara i följande form:" + }, + "prefs_OptionText_chatgpt_web_custom_data_info2": { + "message": "Du hittar rätt värde i webbläsarens URL-fält när du öppnar den relaterade ChatGPT-sidan." + }, + "prefs_OptionText_add_tags_exclusions_exact_match_Info": { + "message": "Om markerat kommer orden i undantagslistan att matchas exakt med taggarna. Annars kommer de också att matcha om de ingår i taggen." + }, + "prefs_OptionText_add_tags_exclusions_exact_match": { + "message": "Exakt matchning för undantag" + }, + "customDataPH_manageDataPH": { + "message": "Hantera dataplatshållare" + }, + "customDataPH_manageDataPH_info_default_3": { + "message": "Du kan också använda standarddataplatshållarna med autokomplettering, precis som när du skriver anpassade promptar." + }, + "customDataPH_manageDataPH_info_default": { + "message": "På den här sidan är det möjligt att definiera anpassade dataplatshållare som ska användas i dina anpassade promptar." } } From d73dc3f07625798facb92cf4f3f285c56d28788c Mon Sep 17 00:00:00 2001 From: Mic Date: Sun, 4 Jan 2026 23:44:34 +0100 Subject: [PATCH 134/146] Translated using Weblate (German) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/de/ --- _locales/de/messages.json | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 11ae9c45..9930d5ac 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -1107,7 +1107,7 @@ "message": "Claude-API-Version" }, "prefs_OptionText_anthropic_max_tokens": { - "message": "Maximale Anzahl an Tokens für Claude" + "message": "Maximale Anzahl an Tokens" }, "anthropic_empty_apikey": { "message": "Sie haben keinen API-Schlüssel für die Claude-API hinzugefügt. Bitte fügen Sie einen auf der Optionsseite ein." @@ -1311,5 +1311,32 @@ }, "Optional_Permission_Denied_Model_Fetching": { "message": "Sie haben die optionale Berechtigung verweigert, die zum Abrufen der Modelle für diese Integration erforderlich ist." + }, + "prompt_string": { + "message": "Prompt" + }, + "placeholder_mail_headers": { + "message": "E-Mail-Kopfzeilen" + }, + "reset": { + "message": "Reset" + }, + "prefs_chatgpt_api_temperature_Info": { + "message": "Welche Sampling-Temperatur soll verwendet werden (zwischen 0 und 2)? Höhere Werte wie 0,8 machen die Ausgabe zufälliger, während niedrigere Werte wie 0,2 sie fokussierter und deterministischer machen." + }, + "prefs_ollama_temperature_Info": { + "message": "Die Temperatur des Modells. Eine Erhöhung der Temperatur führt dazu, dass das Modell kreativer antwortet. Der Standardwert ist 0,8. Es wird empfohlen, Werte zwischen 0 und 1 zu verwenden." + }, + "prefs_api_temperature": { + "message": "Temperatur" + }, + "prefs_openai_comp_temperature_Info": { + "message": "Welche Sampling-Temperatur verwendet werden soll (zwischen 0 und 2). Höhere Werte wie 0,8 machen die Ausgabe zufälliger, während niedrigere Werte wie 0,2 sie fokussierter und deterministischer machen." + }, + "prefs_google_gemini_temperature_Info": { + "message": "Dieser Parameter muss eine Zahl zwischen 0,0 und 2,0 sein. Er steuert den Zufallsgrad der Ausgabe. Der Standardwert variiert je nach Modell. Lassen Sie das Feld leer, um den Parameter im API-Aufruf nicht festzulegen." + }, + "prefs_anthropic_temperature_Info": { + "message": "Grad der Zufälligkeit in der Antwort. Der Standardwert ist 1,0. Der Bereich liegt zwischen 0,0 und 1,0. Verwenden Sie eine Temperatur näher an 0,0 für analytische Aufgaben oder Multiple-Choice-Fragen und näher an 1,0 für kreative und generative Aufgaben. Beachten Sie, dass die Ergebnisse selbst bei einer Temperatur von 0,0 nicht vollständig deterministisch sind." } } From d51d907e848216b5c00cfa1c9a95ed5c4501bb99 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sun, 4 Jan 2026 23:45:02 +0100 Subject: [PATCH 135/146] Translated using Weblate (Swedish) Currently translated at 96.9% (419 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 0533d53a..ab0fefdf 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -1262,5 +1262,8 @@ }, "customDataPH_manageDataPH_info_default": { "message": "På den här sidan är det möjligt att definiera anpassade dataplatshållare som ska användas i dina anpassade promptar." + }, + "customDataPH_manageDataPH_info_default_2": { + "message": "Befintliga dataplatshållare med samma ID kommer att skrivas över. Platshållare med nya ID:n kommer att läggas till." } } From 4c68ad0de22d5fc65dd8e2b96d4dd344657edfcc Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Sun, 4 Jan 2026 23:49:21 +0100 Subject: [PATCH 136/146] Translated using Weblate (Swedish) Currently translated at 98.1% (424 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index ab0fefdf..690b90bb 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -1265,5 +1265,20 @@ }, "customDataPH_manageDataPH_info_default_2": { "message": "Befintliga dataplatshållare med samma ID kommer att skrivas över. Platshållare med nya ID:n kommer att läggas till." + }, + "prefs_google_gemini_thinking_budget": { + "message": "Tänkande budget" + }, + "prefs_google_gemini_thinking_budget_Info": { + "message": "Definiera antalet tokens som ska användas för tänkande. Lämna det här fältet tomt om den valda modellen inte stöder tänkande eller om du vill använda standardmetoden. Ange 0 för att inaktivera tänkande eller -1 för att aktivera dynamiskt tänkande." + }, + "prefs_google_gemini_temperature_Info": { + "message": "Denna parameter måste vara ett tal mellan 0,0 och 2,0. Den styr utdatas slumpmässighet. Standardvärdet varierar beroende på modell. Lämna det tomt för att undvika att parametern anges i API-anropet." + }, + "prefs_anthropic_temperature_Info": { + "message": "Mängd slumpmässighet som injiceras i svaret. Standardvärdet är 1,0. Varierar från 0,0 till 1,0. Använd en temperatur närmare 0,0 för analytiska/flervalsfrågor och närmare 1,0 för kreativa och generativa uppgifter. Observera att även med en temperatur på 0,0 kommer resultaten inte att vara helt deterministiska." + }, + "prompt_add_tags_full_text": { + "message": "Analysera följande e-posttext och generera en JSON-matris med taggar som sammanfattar innehållet. Använd teman, nyckelämnen och relevanta beskrivningar som taggar. Se till att taggarna är koncisa och relevanta för e-postmeddelandets innehåll.\nE-posttext: {%mail_text_body%}\nTänk på följande detaljer för kontext:\n- Avsändare: {%author%}\n- Mottagare: {%recipients%}\n- CC-lista: {%cc_list%}\n- E-postämne: {%mail_subject%}\nBasera dina taggar på e-postmeddelandets text och kontext och ignorera onödig information eller triviala detaljer.\nGenerera ett svar endast i JSON-format. Utdata ska endast vara en JSON-matris med taggar utan ytterligare kommentarer eller text. Här är ett exempel på JSON-formatet som ska användas:\n{\n\"tags\": [\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]\n}" } } From d9bded0bb794b44a897f7b91cdda5343f9b10db6 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 5 Jan 2026 16:34:11 +0100 Subject: [PATCH 137/146] sv translation added --- LANG.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/LANG.md b/LANG.md index 4e7aa5e2..48e6e12d 100644 --- a/LANG.md +++ b/LANG.md @@ -9,5 +9,6 @@ it pl pt-br ru +sv zh_Hans zh_Hant \ No newline at end of file diff --git a/README.md b/README.md index 03252c22..0c2500ed 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Are you using this addon in your Thunderbird? - Português Brasileiro (pt-br): Bruno Pereira de Souza - Russian (ru): [Maksim](https://hosted.weblate.org/user/law820314/) - Spanish (es): [Gerardo Sobarzo](https://hosted.weblate.org/user/gerardo.sobarzo/), [Andrés Rendón Hernández](https://hosted.weblate.org/user/arendon/), [Erick Limon](https://hosted.weblate.org/user/ErickLimonG/) +- Swedish (sv): [Andreas Pettersson](https://hosted.weblate.org/user/Andy_tb/)
        Do you want to help translate this addon? [Find out how!](https://micz.it/thunderbird-addon-thunderai/translate/)
        From 4bf08b0d9b5e8bed1d267ee77b5c1efd50df53c9 Mon Sep 17 00:00:00 2001 From: mic Date: Mon, 5 Jan 2026 16:34:29 +0100 Subject: [PATCH 138/146] release notes updated --- CHANGELOG.md | 1 + options/mzta-release-notes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33b28cd4..dbad26b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@
      • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
      • [All APIs] The configuration information reported in the webchat API has been improved for all integrations.
      • 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.
      • ...
      diff --git a/options/mzta-release-notes.html b/options/mzta-release-notes.html index 2863c054..f45c1934 100644 --- a/options/mzta-release-notes.html +++ b/options/mzta-release-notes.html @@ -17,6 +17,7 @@
    • It is now possible to define a custom placeholder with dynamic data to retrieve any header present in the current email [#527].
    • [All APIs] The configuration information reported in the webchat API has been improved for all integrations.
    • 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.
    • ...
    From 927ef5af372359c4f5a153b02f2233bab06aefc3 Mon Sep 17 00:00:00 2001 From: Andreas Pettersson Date: Mon, 5 Jan 2026 16:58:24 +0100 Subject: [PATCH 139/146] Translated using Weblate (Swedish) Currently translated at 100.0% (432 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/sv/ --- _locales/sv/messages.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 690b90bb..c9e95c21 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -1280,5 +1280,29 @@ }, "prompt_add_tags_full_text": { "message": "Analysera följande e-posttext och generera en JSON-matris med taggar som sammanfattar innehållet. Använd teman, nyckelämnen och relevanta beskrivningar som taggar. Se till att taggarna är koncisa och relevanta för e-postmeddelandets innehåll.\nE-posttext: {%mail_text_body%}\nTänk på följande detaljer för kontext:\n- Avsändare: {%author%}\n- Mottagare: {%recipients%}\n- CC-lista: {%cc_list%}\n- E-postämne: {%mail_subject%}\nBasera dina taggar på e-postmeddelandets text och kontext och ignorera onödig information eller triviala detaljer.\nGenerera ett svar endast i JSON-format. Utdata ska endast vara en JSON-matris med taggar utan ytterligare kommentarer eller text. Här är ett exempel på JSON-formatet som ska användas:\n{\n\"tags\": [\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]\n}" + }, + "addtags_info_additional_statements": { + "message": "Detta uttryck kommer att läggas till i slutet av prompten:" + }, + "AddTags_prompt_prefs_title": { + "message": "Lägga till taggar alternativ" + }, + "placeholder_mail_typed_text": { + "message": "Skriven text före citatbrevets brödtext" + }, + "placeholder_mail_quoted_text": { + "message": "Citerad text i meddelandets brödtext" + }, + "prompt_get_calendar_event_full_text": { + "message": "Extrahera all relevant information som krävs för att generera en kalenderhändelse från följande text. Den extraherade informationen bör innehålla:\n- Händelsetitel\n- Startdatum och tid (inklusive tidszon, om angiven)\n- Slutdatum och tid (inklusive tidszon, om angiven)\n- Heldag (om angiven)\n- Deltagare\nSe till att informationen är tydligt och konsekvent formaterad så att den kan användas direkt för att skapa en kalenderhändelse.\nOm det finns relativa tidsreferenser, tänk på att datum och tid för e-postmeddelandet är \"{%mail_datetime%}\". Beräkna startdatum och tid baserat på denna referens. Om det beräknade startdatumet och tiden är tidigare än \"{%current_datetime%}\", beräkna om startdatumet och tiden med \"{%current_datetime%}\" som bas.\nOm varaktigheten inte anges, sätt den till en timme.\nDessa är deltagarna: {%author%}, {%recipients%}, {%cc_list%}. Om det finns, exkludera min adress: {%account_email_address%}.\nOm du inte kan få en eller flera av de obligatoriska uppgifterna, vänligen svara med en tom sträng.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaringar; ange endast JSON. Här är formatet som ska användas:\n{\n\"startDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"endDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"summary\": \"Sammanfattning av kalenderhändelse här\",\n\"forceAllDay\": false,\n\"attendees\": [attendee1@example.com,attendee2@example.com,attendee3@example.com]\n}\nHär är texten: \"{%selected_text%}\"" + }, + "prompt_get_task_full_text": { + "message": "Extrahera alla relevanta detaljer som krävs för att generera en uppgift från följande text. Den extraherade informationen bör innehålla:\n- Förfallodatum och tid (inklusive tidszon, om angiven)\n- Uppgiftssammanfattning\n- Initialt datum och tid (inklusive tidszon, om angiven)\nSe till att informationen är tydligt och konsekvent formaterad så att den kan användas direkt för att skapa en uppgift.\nOm det finns relativa tidsreferenser, tänk på att datum och tid för e-postmeddelandet är \"{%mail_datetime%}\". Beräkna startdatum och tid baserat på denna referens. Om det beräknade startdatumet och tiden är tidigare än \"{%current_datetime%}\", beräkna om startdatumet och tiden med \"{%current_datetime%}\" som bas.\nOm du inte kan få en eller flera av de obligatoriska uppgifterna, vänligen svara med en tom sträng.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaringar; ange endast JSON. Här är formatet som ska användas:\n{\n\"InitialDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"dueDate\": \"ÅÅÅÅMMDDTHHMMSS\",\n\"summary\": \"Uppgiftssammanfattning här\"\n}\nOm det inte finns någon information om datumen, ta bort dem.\nHär är texten: \"{%selected_text%}\"" + }, + "prompt_spamfilter_full_text": { + "message": "Analysera följande e-postmeddelande och avgör om det är skräppost eller inte. Tänk på faktorer som misstänkta sökord, överdrivet reklamspråk, vilseledande ämnesrader, förfrågningar om personlig information och ovanliga avsändaradresser.\nAnge ett värde från 0 (inte skräppost) till 100 (skräppost) och en förklaring på högst 10 ord.\nOm meddelandedata saknas, sätt värdet till 0 (inte skräppost) och ange orsaken.\nGenerera ett svar endast i JSON-format. Inkludera inte ytterligare text eller förklaring; ange endast JSON. Här är formatet som ska användas:\n{\n\"spamValue\": ,\n\"explanation\": \"Kort förklaring av ditt resonemang\"\n}\nHär är e-postinformationen:\nAvsändare: \"{%author%}\"\nÄmne: \"{%mail_subject%}\"\nHtml-text: \"{%mail_html_body%}\"" + }, + "CORS_give_allurls_perm": { + "message": "Ge behörighet för \"alla webbadresser\"" } } From 8c2ece55208bc54e8a087eec74b66f1ff185d34d Mon Sep 17 00:00:00 2001 From: Christos Kanotidis Date: Tue, 6 Jan 2026 13:23:31 +0100 Subject: [PATCH 140/146] Translated using Weblate (Greek) Currently translated at 97.9% (423 of 432 strings) Translation: ThunderAI for Thunderbird/main Translate-URL: https://hosted.weblate.org/projects/thunderai/main/el/ --- _locales/el/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_locales/el/messages.json b/_locales/el/messages.json index a4ed4972..16a60884 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -1277,5 +1277,8 @@ }, "Optional_Permission_Denied_Model_Fetching": { "message": "Έχετε αρνηθεί την προαιρετική άδεια που απαιτείται για την τοποθέτηση μοντέλων για αυτήν την ενσωμάτωση." + }, + "reset": { + "message": "Επαναφορά" } } From aa0fd9756397cdd9a0a962ea48cb83e2a30322ff Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 9 Jan 2026 22:52:41 +0100 Subject: [PATCH 141/146] 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 142/146] 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 143/146] 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 144/146] 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 bd1ea03f789fa3ca5653877f8d600d636abe3e31 Mon Sep 17 00:00:00 2001 From: Christos Kanotidis Date: Wed, 14 Jan 2026 19:24:24 +0100 Subject: [PATCH 145/146] 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 1d83c3a8c094f68c9da44447e1436fb29dd3a493 Mon Sep 17 00:00:00 2001 From: mic Date: Fri, 16 Jan 2026 22:29:34 +0100 Subject: [PATCH 146/146] 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