diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 99257cc7..f4cd7c9b 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -1912,21 +1912,42 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CHATROLEEXTENSIONS::T601166687"] = "AI" -- Edit Message UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1183581066"] = "Edit Message" +-- Result +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1347088452"] = "Result" + -- Do you really want to remove this message? UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1347427447"] = "Do you really want to remove this message?" -- Yes, remove the AI response and edit it UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1350385882"] = "Yes, remove the AI response and edit it" +-- Failed +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1434043348"] = "Failed" + +-- Tool Calls ({0}) +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1493057571"] = "Tool Calls ({0})" + +-- Executed +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1564757972"] = "Executed" + -- Yes, regenerate it UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1603883875"] = "Yes, regenerate it" +-- No result +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1684269223"] = "No result" + -- Yes, remove it UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1820166585"] = "Yes, remove it" -- Number of sources UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1848978959"] = "Number of sources" +-- Show {0} tool calls +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1981771421"] = "Show {0} tool calls" + +-- Show tool call for {0} +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2004842583"] = "Show tool call for {0}" + -- Do you really want to edit this message? In order to edit this message, the AI response will be deleted. UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2018431076"] = "Do you really want to edit this message? In order to edit this message, the AI response will be deleted." @@ -1936,6 +1957,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2093355991"] = "Removes -- Regenerate Message UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2308444540"] = "Regenerate Message" +-- Arguments +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2738624831"] = "Arguments" + -- Number of attachments UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3018847255"] = "Number of attachments" @@ -1945,9 +1969,15 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3175548294"] = "Cannot -- Edit UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3267849393"] = "Edit" +-- Unknown +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3424652889"] = "Unknown" + -- Regenerate UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3587744975"] = "Regenerate" +-- Blocked +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3816336467"] = "Blocked" + -- Do you really want to regenerate this message? UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3878878761"] = "Do you really want to regenerate this message?" @@ -1957,9 +1987,15 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4070211974"] = "Remove -- No, keep it UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4188329028"] = "No, keep it" +-- No tool calls +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4224149521"] = "No tool calls" + -- Export Chat to Microsoft Word UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T861873672"] = "Export Chat to Microsoft Word" +-- No arguments +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T931993614"] = "No arguments" + -- The selected model '{0}' is no longer available from '{1}' (provider={2}). Please adapt your provider settings. UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T3267850764"] = "The selected model '{0}' is no longer available from '{1}' (provider={2}). Please adapt your provider settings." @@ -2176,15 +2212,6 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T252 -- Select a minimum confidence level UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMINCONFIDENCESELECTION::T2579793544"] = "Select a minimum confidence level" --- You have selected 1 preview feature. -UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T1384241824"] = "You have selected 1 preview feature." - --- No preview features selected. -UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T2809641588"] = "No preview features selected." - --- You have selected {0} preview features. -UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONMULTISELECT::T3513450626"] = "You have selected {0} preview features." - -- Preselected provider UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::CONFIGURATIONPROVIDERSELECTION::T1469984996"] = "Preselected provider" @@ -2995,6 +3022,39 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T900237 -- Export configuration UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T975426229"] = "Export configuration" +-- Settings +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T1258653480"] = "Settings" + +-- Description +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T1725856265"] = "Description" + +-- Icon +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T1759955728"] = "Icon" + +-- Configure global settings for each tool. Tool defaults for chat and assistants are configured in the corresponding feature settings. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T176751696"] = "Configure global settings for each tool. Tool defaults for chat and assistants are configured in the corresponding feature settings." + +-- This tool still needs to be configured. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T1958939818"] = "This tool still needs to be configured." + +-- Missing required settings: {0} +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T2588115579"] = "Missing required settings: {0}" + +-- Name +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T266367750"] = "Name" + +-- No minimum confidence level chosen +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T2828607242"] = "No minimum confidence level chosen" + +-- Minimum provider confidence +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3461070436"] = "Minimum provider confidence" + +-- Tool Settings +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3730473128"] = "Tool Settings" + +-- State +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T502047894"] = "State" + -- No transcription provider configured yet. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1079350363"] = "No transcription provider configured yet." @@ -3064,6 +3124,66 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::THIRDPARTYCOMPONENT::T1392042694"] = "Ope -- License: UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::THIRDPARTYCOMPONENT::T1908172666"] = "License:" +-- Tool selection is hidden +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T2096103917"] = "Tool selection is hidden" + +-- You have selected 1 tool. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T2493128368"] = "You have selected 1 tool." + +-- Choose which tools should be preselected for new runs of this assistant. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T2696618758"] = "Choose which tools should be preselected for new runs of this assistant." + +-- Default tools for this assistant +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3253667950"] = "Default tools for this assistant" + +-- Tool selection is visible +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3384582069"] = "Tool selection is visible" + +-- Show tool selection in this assistant? +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3494508870"] = "Show tool selection in this assistant?" + +-- You have selected {0} tools. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3729156356"] = "You have selected {0} tools." + +-- No tools selected. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3934845540"] = "No tools selected." + +-- Default tools for chat +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T907403808"] = "Default tools for chat" + +-- Choose which tools should be preselected for new chats. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T948842182"] = "Choose which tools should be preselected for new chats." + +-- This tool is currently required because Web Search is enabled. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T1351725609"] = "This tool is currently required because Web Search is enabled." + +-- Tool changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T1688023907"] = "Tool changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished." + +-- Enabling this tool also enables Read Web Page. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3023833839"] = "Enabling this tool also enables Read Web Page." + +-- Required settings are missing. Configure this tool before enabling it. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3119156561"] = "Required settings are missing. Configure this tool before enabling it." + +-- The selected provider or model does not support tool calling. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3364063757"] = "The selected provider or model does not support tool calling." + +-- Close +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3448155331"] = "Close" + +-- No tools are available in this context. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3904490680"] = "No tools are available in this context." + +-- This tool requires provider confidence {0}. The selected provider has {1}. +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T4097602620"] = "This tool requires provider confidence {0}. The selected provider has {1}." + +-- Tool Selection +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T749664565"] = "Tool Selection" + +-- Select tools +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T998515990"] = "Select tools" + -- You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T1015366320"] = "You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation." @@ -5665,6 +5785,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3547 -- Preselect e-mail options? UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3832719342"] = "Preselect e-mail options?" +-- Save +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T1294818664"] = "Save" + +-- Tool Settings +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3730473128"] = "Tool Settings" + +-- The selected tool could not be loaded. +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3907843187"] = "The selected tool could not be loaded." + +-- Cancel +UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T900713019"] = "Cancel" + -- Save UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SHORTCUTDIALOG::T1294818664"] = "Save" @@ -6625,6 +6757,9 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::BASEPROVIDER::T3014737766"] = "We tried to -- We tried to communicate with the LLM provider '{0}' (type={1}). Even after {2} retries, there were some problems with the request. The provider message is: '{3}'. UI_TEXT_CONTENT["AISTUDIO::PROVIDER::BASEPROVIDER::T3049689432"] = "We tried to communicate with the LLM provider '{0}' (type={1}). Even after {2} retries, there were some problems with the request. The provider message is: '{3}'." +-- The tool calling request failed with status code {0}. See the logs for details. +UI_TEXT_CONTENT["AISTUDIO::PROVIDER::BASEPROVIDER::T3117779001"] = "The tool calling request failed with status code {0}. See the logs for details." + -- Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}' UI_TEXT_CONTENT["AISTUDIO::PROVIDER::BASEPROVIDER::T3573577433"] = "Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}'" @@ -6715,6 +6850,9 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::MODELLOADFAILUREREASONEXTENSIONS::T37333904 -- We could not load models from '{0}' due to an unknown error. UI_TEXT_CONTENT["AISTUDIO::PROVIDER::MODELLOADFAILUREREASONEXTENSIONS::T3907712809"] = "We could not load models from '{0}' due to an unknown error." +-- The tool calling request failed with status code {0}. See the logs for details. +UI_TEXT_CONTENT["AISTUDIO::PROVIDER::OPENAI::PROVIDEROPENAI::T3117779001"] = "The tool calling request failed with status code {0}. See the logs for details." + -- It looks like you do not have any API credits left with OpenAI. Please add credits to your account and try again. UI_TEXT_CONTENT["AISTUDIO::PROVIDER::OPENAI::PROVIDEROPENAI::T757371511"] = "It looks like you do not have any API credits left with OpenAI. Please add credits to your account and try again." @@ -7855,6 +7993,108 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SOURCEEXTENSIONS::T4174900468"] = "Sources pro -- Sources provided by the AI UI_TEXT_CONTENT["AISTUDIO::TOOLS::SOURCEEXTENSIONS::T4261248356"] = "Sources provided by the AI" +-- Tool +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T3517012711"] = "Tool" + +-- Tool description +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T4056470505"] = "Tool description" + +-- Load a single web page, extract its main HTML content, and return structured working material for the model. Use the result to synthesize a natural-language answer instead of exposing the raw payload to the user. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T1823236891"] = "Load a single web page, extract its main HTML content, and return structured working material for the model. Use the result to synthesize a natural-language answer instead of exposing the raw payload to the user." + +-- Optional global truncation limit for extracted Markdown returned to the model. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2066580916"] = "Optional global truncation limit for extracted Markdown returned to the model." + +-- Allowed private hosts must be host names only, without scheme or path. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2196457612"] = "Allowed private hosts must be host names only, without scheme or path." + +-- Optional host allowlist for private or VPN web pages. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a High-confidence provider. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T237631450"] = "Optional host allowlist for private or VPN web pages. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a High-confidence provider." + +-- Maximum Content Characters +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2801581200"] = "Maximum Content Characters" + +-- Optional HTTP timeout for loading a web page in seconds. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2941521561"] = "Optional HTTP timeout for loading a web page in seconds." + +-- Allowed private host '{0}' is not valid. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T3089707139"] = "Allowed private host '{0}' is not valid." + +-- Allowed Private Hosts +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T3415515539"] = "Allowed Private Hosts" + +-- Timeout Seconds +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T3567699845"] = "Timeout Seconds" + +-- Read Web Page +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T3612587998"] = "Read Web Page" + +-- The web page was not loaded because private or VPN web pages require a High-confidence provider. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T3856267430"] = "The web page was not loaded because private or VPN web pages require a High-confidence provider." + +-- Maximum Results +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1273024715"] = "Maximum Results" + +-- Optional comma-separated default categories. Do not set this together with default engines. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1342681591"] = "Optional comma-separated default categories. Do not set this together with default engines." + +-- Default Safe Search +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1343180281"] = "Default Safe Search" + +-- Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1739312423"] = "Base URL of the SearXNG instance. You can enter either the instance root URL or the /search endpoint." + +-- A SearXNG URL is required. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1746583720"] = "A SearXNG URL is required." + +-- Default Engines +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1865580137"] = "Default Engines" + +-- Optional fallback language code when the model does not provide a language. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T1868101906"] = "Optional fallback language code when the model does not provide a language." + +-- Default Categories +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T2053347010"] = "Default Categories" + +-- Default Language +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T2526826120"] = "Default Language" + +-- The configured SearXNG URL is not a valid absolute URL. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3038368943"] = "The configured SearXNG URL is not a valid absolute URL." + +-- Optional HTTP timeout for the search request in seconds. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3078115445"] = "Optional HTTP timeout for the search request in seconds." + +-- Timeout Seconds +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3567699845"] = "Timeout Seconds" + +-- Optional default maximum number of results returned to the model when the model does not provide a limit. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3603838271"] = "Optional default maximum number of results returned to the model when the model does not provide a limit." + +-- Web Search +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3815068443"] = "Web Search" + +-- Optional safe search policy sent to SearXNG when configured. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3967748757"] = "Optional safe search policy sent to SearXNG when configured." + +-- Default categories and default engines cannot both be set for the web search tool. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T4009446158"] = "Default categories and default engines cannot both be set for the web search tool." + +-- Optional comma-separated default engines. Do not set this together with default categories. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T4108908537"] = "Optional comma-separated default engines. Do not set this together with default categories." + +-- The setting '{0}' must be a positive integer. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T4199432074"] = "The setting '{0}' must be a positive integer." + +-- Search the web with a configured SearXNG instance and return candidate URLs for the model. Use Read Web Page on relevant result URLs before answering factual or detailed web questions. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T764865565"] = "Search the web with a configured SearXNG instance and return candidate URLs for the model. Use Read Web Page on relevant result URLs before answering factual or detailed web questions." + +-- The configured SearXNG URL must start with http:// or https://. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T944878454"] = "The configured SearXNG URL must start with http:// or https://." + +-- SearXNG URL +UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T993547568"] = "SearXNG URL" + -- Pandoc Installation UI_TEXT_CONTENT["AISTUDIO::TOOLS::USERFILE::T185447014"] = "Pandoc Installation" diff --git a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua index 23523e26..39de99f8 100644 --- a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua @@ -7998,9 +7998,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T35170 -- Tool description UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::ITOOLIMPLEMENTATION::T4056470505"] = "Werkzeugbeschreibung" --- Load a single web page, extract its main HTML content, and return structured working material for the model. Use the result to synthesize a natural-language answer instead of exposing the raw payload to the user. -UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T1823236891"] = "Klar — ich kann eine einzelne Webseite laden, ihren Hauptinhalt extrahieren und daraus eine nutzbare, strukturierte Grundlage erstellen. Dem Nutzer gebe ich dann **eine natürlich formulierte Antwort**, nicht den rohen Extraktions-Output. Bitte sende mir einfach **die URL** der Seite, die ich verarbeiten soll. Wenn du möchtest, kannst du auch kurz dazuschreiben, **was genau ich daraus beantworten oder zusammenfassen soll**." - -- Optional global truncation limit for extracted Markdown returned to the model. UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::READWEBPAGETOOL::T2066580916"] = "Optionales globales Kürzungslimit für extrahiertes Markdown, das an das Modell zurückgegeben wird." diff --git a/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolModels.cs b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolModels.cs new file mode 100644 index 00000000..5510aec0 --- /dev/null +++ b/app/MindWork AI Studio/Provider/Anthropic/AnthropicToolModels.cs @@ -0,0 +1,74 @@ +using System.Text.Json; + +namespace AIStudio.Provider.Anthropic; + +public sealed record AnthropicTool +{ + public string Name { get; init; } = string.Empty; + + public string Description { get; init; } = string.Empty; + + public bool Strict { get; init; } + + public JsonElement InputSchema { get; init; } +} + +public sealed record AnthropicMessage(IList Content, string Role) : IMessage>; + +public sealed record AnthropicToolResultMessage(IList Content, string Role = "user") : IMessage>; + +public sealed record AnthropicToolResultContent +{ + public string Type { get; init; } = "tool_result"; + + public string ToolUseId { get; init; } = string.Empty; + + public string Content { get; init; } = string.Empty; +} + +public sealed record AnthropicResponse +{ + public string StopReason { get; init; } = string.Empty; + + public IList Content { get; init; } = []; + + public IReadOnlyList GetToolUses() => this.Content + .Where(x => ReadString(x, "type").Equals("tool_use", StringComparison.Ordinal)) + .Select(x => new AnthropicToolUse + { + Id = ReadString(x, "id"), + Name = ReadString(x, "name"), + Input = x.TryGetProperty("input", out var input) ? input : default, + }) + .Where(x => !string.IsNullOrWhiteSpace(x.Id) && !string.IsNullOrWhiteSpace(x.Name)) + .ToList(); + + public string GetTextOutput() => string.Concat(this.Content + .Where(x => ReadString(x, "type").Equals("text", StringComparison.Ordinal)) + .Select(x => ReadString(x, "text"))); + + public bool HasFinalStopReason() => this.StopReason is "" or "end_turn" or "stop_sequence"; + + private static string ReadString(JsonElement item, string propertyName) + { + if (item.ValueKind is not JsonValueKind.Object || + !item.TryGetProperty(propertyName, out var property) || + property.ValueKind is not JsonValueKind.String) + return string.Empty; + + return property.GetString() ?? string.Empty; + } +} + +public sealed record AnthropicToolUse +{ + public string Id { get; init; } = string.Empty; + + public string Name { get; init; } = string.Empty; + + public JsonElement Input { get; init; } + + public string Arguments => this.Input.ValueKind is JsonValueKind.Undefined + ? "{}" + : this.Input.GetRawText(); +} diff --git a/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs b/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs index d6df3990..5e45fcee 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ChatRequest.cs @@ -18,7 +18,10 @@ public readonly record struct ChatRequest( string System ) { + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IList? Tools { get; init; } + // Attention: The "required" modifier is not supported for [JsonExtensionData]. [JsonExtensionData] public IDictionary AdditionalApiParameters { get; init; } = new Dictionary(); -} \ No newline at end of file +} diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs index 1f322788..49f12ad5 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs @@ -5,12 +5,17 @@ using System.Text.Json; using AIStudio.Chat; using AIStudio.Provider.OpenAI; using AIStudio.Settings; +using AIStudio.Tools.Rust; +using AIStudio.Tools.ToolCallingSystem; + +using Microsoft.Extensions.DependencyInjection; namespace AIStudio.Provider.Anthropic; public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, new Uri("https://api.anthropic.com/v1/"), ExternalHttpTrustPolicy.SYSTEM_TRUST_ONLY, LOGGER) { private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); + private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ProviderAnthropic).Namespace, nameof(ProviderAnthropic)); #region Implementation of IProvider @@ -32,7 +37,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n yield break; // Parse the API parameters: - var apiParameters = this.ParseAdditionalApiParameters("system"); + var apiParameters = this.ParseAdditionalApiParameters("system", "tools"); var maxTokens = 4_096; if (TryPopIntParameter(apiParameters, "max_tokens", out var parsedMaxTokens)) maxTokens = parsedMaxTokens; @@ -71,6 +76,39 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n } ); + var toolRegistry = Program.SERVICE_PROVIDER.GetService(); + var toolExecutor = Program.SERVICE_PROVIDER.GetService(); + var currentAssistantContent = chatThread.Blocks.LastOrDefault(x => x.Role is ChatRole.AI)?.Content as ContentText; + currentAssistantContent?.ToolInvocations.Clear(); + var providerConfidence = this.Provider.GetConfidence(settingsManager).Level; + IReadOnlyList<(ToolDefinition Definition, IToolImplementation Implementation)> runnableTools = toolRegistry is null + ? [] + : await toolRegistry.GetRunnableToolsAsync( + chatThread.RuntimeComponent, + chatThread.RuntimeSelectedToolIds, + this.Provider.GetModelCapabilities(chatModel), + providerConfidence, + settingsManager.IsToolSelectionVisible(chatThread.RuntimeComponent)); + + if (toolExecutor is not null && runnableTools.Count > 0) + { + await foreach (var content in this.StreamWithLocalTools( + chatModel, + messages, + chatThread.PrepareSystemPrompt(settingsManager), + maxTokens, + apiParameters, + runnableTools, + toolExecutor, + currentAssistantContent, + requestedSecret, + providerConfidence, + token)) + yield return content; + + yield break; + } + // Prepare the Anthropic HTTP chat request: var chatRequest = JsonSerializer.Serialize(new ChatRequest { @@ -107,6 +145,170 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n yield return content; } + private async IAsyncEnumerable StreamWithLocalTools( + Model chatModel, + IList baseMessages, + string systemPrompt, + int maxTokens, + IDictionary apiParameters, + IReadOnlyList<(ToolDefinition Definition, IToolImplementation Implementation)> runnableTools, + ToolExecutor toolExecutor, + ContentText? currentAssistantContent, + RequestedSecret requestedSecret, + ConfidenceLevel providerConfidence, + [EnumeratorCancellation] CancellationToken token) + { + var providerTools = runnableTools + .Select(x => (object)new AnthropicTool + { + Name = x.Definition.Function.Name, + Description = x.Definition.Function.Description, + Strict = x.Definition.Function.Strict, + InputSchema = x.Definition.Function.Parameters, + }) + .ToList(); + var internalMessages = new List(); + var toolCallCount = 0; + const int MAX_TOOL_CALLS = 30; + + while (true) + { + var requestDto = new ChatRequest + { + Model = chatModel.Id, + Messages = [..baseMessages, ..internalMessages], + MaxTokens = maxTokens, + Stream = false, + System = systemPrompt, + Tools = providerTools, + AdditionalApiParameters = apiParameters, + }; + var response = await this.ExecuteMessagesRequest(requestDto, requestedSecret, token); + if (response is null) + { + if (currentAssistantContent is not null) + { + currentAssistantContent.ToolRuntimeStatus = new(); + await currentAssistantContent.StreamingEvent(); + } + + yield break; + } + + var textOutput = response.GetTextOutput(); + var toolUses = response.GetToolUses(); + if (toolUses.Count > 0 && !string.IsNullOrWhiteSpace(textOutput)) + yield return new ContentStreamChunk(textOutput, []); + + if (toolUses.Count == 0) + { + if (currentAssistantContent is not null) + { + currentAssistantContent.ToolRuntimeStatus = new(); + await currentAssistantContent.StreamingEvent(); + } + + if (!string.IsNullOrWhiteSpace(textOutput)) + yield return new ContentStreamChunk(textOutput, []); + + if (!response.HasFinalStopReason()) + { + yield return new ContentStreamChunk($"The model stopped with reason '{response.StopReason}' before returning a final answer.", []); + yield break; + } + + else if (toolCallCount > 0) + yield return new ContentStreamChunk("The model completed the tool call but did not return a final answer.", []); + + yield break; + } + + if (currentAssistantContent is not null) + { + currentAssistantContent.ToolRuntimeStatus = new ToolRuntimeStatus + { + IsRunning = true, + ToolNames = toolUses + .Select(x => runnableTools.FirstOrDefault(tool => tool.Definition.Function.Name.Equals(x.Name, StringComparison.Ordinal)).Implementation?.GetDisplayName() ?? x.Name) + .ToList(), + }; + await currentAssistantContent.StreamingEvent(); + } + + internalMessages.Add(new AnthropicMessage(response.Content, "assistant")); + var toolResults = new List(); + foreach (var toolUse in toolUses) + { + toolCallCount++; + if (toolCallCount > MAX_TOOL_CALLS) + { + var limitMessage = $"Tool calling stopped because the maximum of {MAX_TOOL_CALLS} tool calls was reached."; + currentAssistantContent?.ToolInvocations.Add(new ToolInvocationTrace + { + Order = toolCallCount, + ToolId = toolUse.Name, + ToolName = toolUse.Name, + ToolCallId = toolUse.Id, + Status = ToolInvocationTraceStatus.BLOCKED, + StatusMessage = limitMessage, + Result = limitMessage, + }); + + if (currentAssistantContent is not null) + { + currentAssistantContent.ToolRuntimeStatus = new(); + await currentAssistantContent.StreamingEvent(); + } + + yield return new ContentStreamChunk(limitMessage, []); + yield break; + } + + var (toolContent, trace) = await toolExecutor.ExecuteAsync( + toolUse.Id, + toolUse.Name, + toolUse.Arguments, + runnableTools, + providerConfidence, + toolCallCount, + token); + + currentAssistantContent?.ToolInvocations.Add(trace); + toolResults.Add(new AnthropicToolResultContent + { + ToolUseId = toolUse.Id, + Content = toolContent, + }); + } + + internalMessages.Add(new AnthropicToolResultMessage(toolResults)); + + if (currentAssistantContent is not null) + await currentAssistantContent.StreamingEvent(); + } + } + + private async Task ExecuteMessagesRequest(ChatRequest requestDto, RequestedSecret requestedSecret, CancellationToken token) + { + using var request = new HttpRequestMessage(HttpMethod.Post, "messages"); + request.Headers.Add("x-api-key", await requestedSecret.Secret.Decrypt(ENCRYPTION)); + request.Headers.Add("anthropic-version", "2023-06-01"); + request.Content = new StringContent(JsonSerializer.Serialize(requestDto, JSON_SERIALIZER_OPTIONS), Encoding.UTF8, "application/json"); + + using var response = await this.HttpClient.SendAsync(request, token); + if (!response.IsSuccessStatusCode) + { + var responseBody = await response.Content.ReadAsStringAsync(token); + LOGGER.LogError("Tool calling Anthropic Messages API request failed with status code {ResponseStatusCode} and body: '{ResponseBody}'.", response.StatusCode, responseBody); + await MessageBus.INSTANCE.SendError(new( + Icons.Material.Filled.Build, + string.Format(TB("The tool calling request failed with status code {0}. See the logs for details."), (int)response.StatusCode))); + return null; + } + + return await response.Content.ReadFromJsonAsync(JSON_SERIALIZER_OPTIONS, token); + } + #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously /// public override async IAsyncEnumerable StreamImageCompletion(Model imageModel, string promptPositive, string promptNegative = FilterOperator.String.Empty, ImageURL referenceImageURL = default, [EnumeratorCancellation] CancellationToken token = default) @@ -189,4 +391,4 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n }, jsonSerializerOptions: JSON_SERIALIZER_OPTIONS); } -} \ No newline at end of file +}