From c4823df975ce4e5102db4211eb36a97ad637fa95 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 12:37:50 +0200 Subject: [PATCH 1/9] Added Enterprise IT documentation --- README.md | 3 ++ documentation/Enterprise IT.md | 93 ++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 documentation/Enterprise IT.md diff --git a/README.md b/README.md index dec66068..4f293322 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,9 @@ Stay tuned for more updates and enhancements to make MindWork AI Studio even mor ## Building You want to know how to build MindWork AI Studio from source? [Check out the instructions here](documentation/Build.md). +## Enterprise IT +Do you want to manage AI Studio centrally from your IT department? Yes, that’s possible. [Here’s how it works.](documentation/Enterprise IT.md) + ## License MindWork AI Studio is licensed under the `FSL-1.1-MIT` license (functional source license). Here’s a simple rundown of what that means for you: - **Permitted Use**: Feel free to use, copy, modify, and share the software for your own projects, educational purposes, research, or even in professional services. The key is to use it in a way that doesn't compete with our offerings. diff --git a/documentation/Enterprise IT.md b/documentation/Enterprise IT.md new file mode 100644 index 00000000..e1c6c9f1 --- /dev/null +++ b/documentation/Enterprise IT.md @@ -0,0 +1,93 @@ +# Enterprise IT + +## Overview +Do you want to manage MindWork AI Studio in a corporate environment or within an organization? This documentation explains what you need to do and how it works. First, here's an overview of the entire process: + +- You can distribute MindWork AI Studio to employees' devices using tools like Microsoft System Center Configuration Manager (SCCM). +- Employees can get updates through the built-in update feature. If you want, you can disable automatic updates and control which version gets distributed. +- AI Studio checks about every 16 minutes to see where and which configuration it should load. This information is loaded from the local system. On Windows, you might use the registry, for example. +- If it finds the necessary metadata, AI Studio downloads the configuration as a ZIP file from the specified server. +- The configuration is an AI Studio plugin written in Lua. +- Any changes to the configuration apply live while the software is running, so employees don’t need to restart it. + +AI Studio checks about every 16 minutes to see if the configuration ID, the server for the configuration, or the configuration itself has changed. If it finds any changes, it loads the updated configuration from the server and applies it right away. + +## Configure the devices +So that MindWork AI Studio knows where to load which configuration, this information must be provided as metadata on employees’ devices. Currently, the following options are available: + +- **Registry** (only available for Microsoft Windows): On Windows devices, AI Studio first tries to read the information from the registry. The registry information can be managed and distributed centrally as a so-called Group Policy Object (GPO). + +- **Environment variables**: On all operating systems (on Windows as a fallback after the registry), AI Studio tries to read the configuration metadata from environment variables. + +The following keys and values (registry) and variables are checked and read: + +- Key `HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT`, value `config_id` or variable `MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID`: This must be a valid [GUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Globally_unique_identifier). It uniquely identifies the configuration. You can use an ID per department, institute, or even per person. + +- Key `HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT`, value `delete_config_id` or variable `MINDWORK_AI_STUDIO_ENTERPRISE_DELETE_CONFIG_ID`: This is a configuration ID that should be removed. This is helpful if an employee moves to a different department or leaves the organization. + +- Key `HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT`, value `config_server_url` or variable `MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL`: An HTTP or HTTPS address using an IP address or DNS name. This is the web server from which AI Studio attempts to load the specified configuration as a ZIP file. + +Let's assume as example that `https://intranet.my-company.com:30100/ai-studio/configuration` is the server address and `9072b77d-ca81-40da-be6a-861da525ef7b` is the configuration ID. AI Studio will derive the following address from this information: `https://intranet.my-company.com:30100/ai-studio/configuration/9072b77d-ca81-40da-be6a-861da525ef7b.zip`. Important: The configuration ID will always be written in lowercase, even if it is configured in uppercase. If `9072B77D-CA81-40DA-BE6A-861DA525EF7B` is configured, the same address will be derived. Your web server must be configured accordingly. + +Finally, AI Studio will send a GET request and download the ZIP file. The ZIP file only contains the files necessary for the configuration. It's normal to include a file for an icon along with the actual configuration plugin. + +Approximately every 16 minutes, AI Studio checks the metadata of the ZIP file by reading the [ETag](https://en.wikipedia.org/wiki/HTTP_ETag). When the ETag was not changed, no download will be performed. Make sure that your web server supports this. + +## Configure the configuration web server + +In principle, you can use any web server that can serve ZIP files from a folder. However, keep in mind that AI Studio queries the file's metadata using [ETag](https://en.wikipedia.org/wiki/HTTP_ETag). Your web server must support this feature. For security reasons, you should also make sure that users cannot list the contents of the directory. This is important because the different configurations may contain confidential information such as API keys. Each user should only know their own configuration ID. Otherwise, a user might try to use someone else’s ID to gain access to exclusive resources. + +The ZIP file names for the configurations must be in lowercase on the server, or your web server needs to ignore the spelling in requests. Also, make sure the web server is only accessible within your organization’s intranet. You don’t want the server open to everyone worldwide. + +You can use the open source web server [Caddy](https://caddyserver.com/). The project is openly developed on [GitHub](https://github.com/caddyserver/caddy). Below you’ll find an example configuration, a so-called `Caddyfile`, for serving configurations from the folder `/localdata1/ai-studio/config` to AI Studio. The TLS certificates are loaded from the folder `/localdata1/tls-certificate`. + +``` +{ + # Disable logging: + log { + output discard + } + + # Disable automatic HTTPS redirection: + auto_https off +} + +intranet.my-company.com:30100 { + # Load TLS certificates: + tls /localdata1/tls-certificate/cert_webserver.pem /localdata1/tls-certificate/key_webserver.pem + + # Serve the configuration files: + handle_path /ai-studio/configuration/* { + file_server { + root /localdata1/ai-studio/config + + # Disable directory browsing: + browse false + } + } + + # All other requests will receive a 404 Not Found response: + handle { + respond "Not Found" 404 + } +} +``` + +## Example AI Studio configuration +The latest example of an AI Studio configuration via configuration plugin can always be found in the repository in the `app/MindWork AI Studio/Plugins/configuration` folder. Here are the links to the files: + +- [The icon](app/MindWork AI Studio/Plugins/configuration/icon.lua) +- [The configuration with explanations](app/MindWork AI Studio/Plugins/configuration/plugin.lua) + +Currently, you can configure the following things: +- Any number of self-hosted LLM providers (a combination of server and model), but currently only without API keys +- The update behavior of AI Studio + +All other settings can be made by the user themselves. If you need additional settings, feel free to create an issue in our planning repository: https://github.com/MindWorkAI/Planning/issues + +In the coming months, we will allow more settings, such as: +- Using API keys for providers +- Configuration of embedding providers for RAG +- Configuration of data sources for RAG +- Configuration of chat templates +- Configuration of assistant plugins (for example, your own assistants for your company or specific departments) \ No newline at end of file From ef515c4758b0ac106181acaadf06aa2cf8298387 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 12:42:26 +0200 Subject: [PATCH 2/9] Fix broken links with spaces in documentation --- README.md | 2 +- documentation/Enterprise IT.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4f293322..39bb3d4f 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Stay tuned for more updates and enhancements to make MindWork AI Studio even mor You want to know how to build MindWork AI Studio from source? [Check out the instructions here](documentation/Build.md). ## Enterprise IT -Do you want to manage AI Studio centrally from your IT department? Yes, that’s possible. [Here’s how it works.](documentation/Enterprise IT.md) +Do you want to manage AI Studio centrally from your IT department? Yes, that’s possible. [Here’s how it works.](documentation/Enterprise%20IT.md) ## License MindWork AI Studio is licensed under the `FSL-1.1-MIT` license (functional source license). Here’s a simple rundown of what that means for you: diff --git a/documentation/Enterprise IT.md b/documentation/Enterprise IT.md index e1c6c9f1..5d41c41b 100644 --- a/documentation/Enterprise IT.md +++ b/documentation/Enterprise IT.md @@ -76,8 +76,8 @@ intranet.my-company.com:30100 { ## Example AI Studio configuration The latest example of an AI Studio configuration via configuration plugin can always be found in the repository in the `app/MindWork AI Studio/Plugins/configuration` folder. Here are the links to the files: -- [The icon](app/MindWork AI Studio/Plugins/configuration/icon.lua) -- [The configuration with explanations](app/MindWork AI Studio/Plugins/configuration/plugin.lua) +- [The icon](app/MindWork%20AI%20Studio/Plugins/configuration/icon.lua) +- [The configuration with explanations](app/MindWork%20AI%20Studio/Plugins/configuration/plugin.lua) Currently, you can configure the following things: - Any number of self-hosted LLM providers (a combination of server and model), but currently only without API keys From b8e002c10093d4180f8278f127c8f2ab4df7c4b6 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 12:43:11 +0200 Subject: [PATCH 3/9] Fix relative links in Enterprise IT documentation --- documentation/Enterprise IT.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/Enterprise IT.md b/documentation/Enterprise IT.md index 5d41c41b..85a61f2a 100644 --- a/documentation/Enterprise IT.md +++ b/documentation/Enterprise IT.md @@ -76,8 +76,8 @@ intranet.my-company.com:30100 { ## Example AI Studio configuration The latest example of an AI Studio configuration via configuration plugin can always be found in the repository in the `app/MindWork AI Studio/Plugins/configuration` folder. Here are the links to the files: -- [The icon](app/MindWork%20AI%20Studio/Plugins/configuration/icon.lua) -- [The configuration with explanations](app/MindWork%20AI%20Studio/Plugins/configuration/plugin.lua) +- [The icon](../app/MindWork%20AI%20Studio/Plugins/configuration/icon.lua) +- [The configuration with explanations](../app/MindWork%20AI%20Studio/Plugins/configuration/plugin.lua) Currently, you can configure the following things: - Any number of self-hosted LLM providers (a combination of server and model), but currently only without API keys From ed102dde0495b7f1249d3459516eba02815e67fb Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 12:47:04 +0200 Subject: [PATCH 4/9] Clarify SVG requirement for plugin icons in documentation --- documentation/Enterprise IT.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/documentation/Enterprise IT.md b/documentation/Enterprise IT.md index 85a61f2a..396308b8 100644 --- a/documentation/Enterprise IT.md +++ b/documentation/Enterprise IT.md @@ -79,6 +79,8 @@ The latest example of an AI Studio configuration via configuration plugin can al - [The icon](../app/MindWork%20AI%20Studio/Plugins/configuration/icon.lua) - [The configuration with explanations](../app/MindWork%20AI%20Studio/Plugins/configuration/plugin.lua) +Please note that the icon must be an SVG vector graphic. Raster graphics like PNGs, GIFs, and others aren’t supported. You can use the sample icon, which looks like a gear. + Currently, you can configure the following things: - Any number of self-hosted LLM providers (a combination of server and model), but currently only without API keys - The update behavior of AI Studio From d2c75ea7bf55bd50f3c9b01bcdf30010e650d2d5 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 13:03:25 +0200 Subject: [PATCH 5/9] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39bb3d4f..a5548adf 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Things we are currently working on: - [x] ~~Add support for other languages (I18N) to AI Studio ([PR #381](https://github.com/MindWorkAI/AI-Studio/pull/381), [PR #400](https://github.com/MindWorkAI/AI-Studio/pull/400), [PR #404](https://github.com/MindWorkAI/AI-Studio/pull/404), [PR #429](https://github.com/MindWorkAI/AI-Studio/pull/429), [PR #446](https://github.com/MindWorkAI/AI-Studio/pull/446), [PR #451](https://github.com/MindWorkAI/AI-Studio/pull/451), [PR #455](https://github.com/MindWorkAI/AI-Studio/pull/455), [PR #458](https://github.com/MindWorkAI/AI-Studio/pull/458), [PR #462](https://github.com/MindWorkAI/AI-Studio/pull/462), [PR #469](https://github.com/MindWorkAI/AI-Studio/pull/469), [PR #486](https://github.com/MindWorkAI/AI-Studio/pull/486))~~ - [x] ~~Add an I18N assistant to translate all AI Studio texts to a certain language & culture ([PR #422](https://github.com/MindWorkAI/AI-Studio/pull/422))~~ - [x] ~~Provide MindWork AI Studio in German ([PR #430](https://github.com/MindWorkAI/AI-Studio/pull/430), [PR #446](https://github.com/MindWorkAI/AI-Studio/pull/446), [PR #451](https://github.com/MindWorkAI/AI-Studio/pull/451), [PR #455](https://github.com/MindWorkAI/AI-Studio/pull/455), [PR #458](https://github.com/MindWorkAI/AI-Studio/pull/458), [PR #462](https://github.com/MindWorkAI/AI-Studio/pull/462), [PR #469](https://github.com/MindWorkAI/AI-Studio/pull/469), [PR #486](https://github.com/MindWorkAI/AI-Studio/pull/486))~~ - - [x] ~~Add configuration plugins, which allow pre-defining some LLM providers in organizations ([PR #491](https://github.com/MindWorkAI/AI-Studio/pull/491), [PR #493](https://github.com/MindWorkAI/AI-Studio/pull/493), [PR #494](https://github.com/MindWorkAI/AI-Studio/pull/494))~~ + - [x] ~~Add configuration plugins, which allow pre-defining some LLM providers in organizations ([PR #491](https://github.com/MindWorkAI/AI-Studio/pull/491), [PR #493](https://github.com/MindWorkAI/AI-Studio/pull/493), [PR #494](https://github.com/MindWorkAI/AI-Studio/pull/494), [PR #497](https://github.com/MindWorkAI/AI-Studio/pull/497))~~ - [ ] Add an app store for plugins, showcasing community-contributed plugins from public GitHub and GitLab repositories. This will enable AI Studio users to discover, install, and update plugins directly within the platform. - [ ] Add assistant plugins From bc88746c611e7392efcc5e6550487777144260ea Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 13:09:59 +0200 Subject: [PATCH 6/9] Replace `info` logs with `debug` and `warn` levels --- runtime/src/environment.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/runtime/src/environment.rs b/runtime/src/environment.rs index b62980a9..8c484ab8 100644 --- a/runtime/src/environment.rs +++ b/runtime/src/environment.rs @@ -1,6 +1,6 @@ use std::env; use std::sync::OnceLock; -use log::info; +use log::{debug, warn}; use rocket::{delete, get}; use sys_locale::get_locale; use crate::api_token::APIToken; @@ -42,7 +42,7 @@ pub fn is_prod() -> bool { #[get("/system/language")] pub fn read_user_language(_token: APIToken) -> String { get_locale().unwrap_or_else(|| { - log::warn!("Could not determine the system language. Use default 'en-US'."); + warn!("Could not determine the system language. Use default 'en-US'."); String::from("en-US") }) } @@ -64,7 +64,7 @@ pub fn read_enterprise_env_config_id(_token: APIToken) -> String { // The environment variable is: // MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID // - info!("Trying to read the enterprise environment for some config ID."); + debug!("Trying to read the enterprise environment for some config ID."); get_enterprise_configuration( "config_id", "MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID", @@ -88,7 +88,7 @@ pub fn delete_enterprise_env_config_id(_token: APIToken) -> String { // The environment variable is: // MINDWORK_AI_STUDIO_ENTERPRISE_DELETE_CONFIG_ID // - info!("Trying to read the enterprise environment for some config ID, which should be deleted."); + debug!("Trying to read the enterprise environment for some config ID, which should be deleted."); get_enterprise_configuration( "delete_config_id", "MINDWORK_AI_STUDIO_ENTERPRISE_DELETE_CONFIG_ID", @@ -112,7 +112,7 @@ pub fn read_enterprise_env_config_server_url(_token: APIToken) -> String { // The environment variable is: // MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL // - info!("Trying to read the enterprise environment for the config server URL."); + debug!("Trying to read the enterprise environment for the config server URL."); get_enterprise_configuration( "config_server_url", "MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL", @@ -122,20 +122,20 @@ pub fn read_enterprise_env_config_server_url(_token: APIToken) -> String { fn get_enterprise_configuration(_reg_value: &str, env_name: &str) -> String { cfg_if::cfg_if! { if #[cfg(target_os = "windows")] { - info!(r"Detected a Windows machine, trying to read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT' or environment variables."); + debug!(r"Detected a Windows machine, trying to read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT' or environment variables."); use windows_registry::*; let key_path = r"Software\github\MindWork AI Studio\Enterprise IT"; let key = match CURRENT_USER.open(key_path) { Ok(key) => key, Err(_) => { - info!(r"Could not read the registry key HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT. Falling back to environment variables."); + debug!(r"Could not read the registry key HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT. Falling back to environment variables."); return match env::var(env_name) { Ok(val) => { - info!("Falling back to the environment variable '{}' was successful.", env_name); + debug!("Falling back to the environment variable '{}' was successful.", env_name); val }, Err(_) => { - info!("Falling back to the environment variable '{}' was not successful.", env_name); + debug!("Falling back to the environment variable '{}' was not successful.", env_name); "".to_string() }, } @@ -145,14 +145,14 @@ fn get_enterprise_configuration(_reg_value: &str, env_name: &str) -> String { match key.get_string(_reg_value) { Ok(val) => val, Err(_) => { - info!(r"We could read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT', but the value '{}' could not be read. Falling back to environment variables.", _reg_value); + debug!(r"We could read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT', but the value '{}' could not be read. Falling back to environment variables.", _reg_value); match env::var(env_name) { Ok(val) => { - info!("Falling back to the environment variable '{}' was successful.", env_name); + debug!("Falling back to the environment variable '{}' was successful.", env_name); val }, Err(_) => { - info!("Falling back to the environment variable '{}' was not successful.", env_name); + debug!("Falling back to the environment variable '{}' was not successful.", env_name); "".to_string() } } @@ -160,11 +160,11 @@ fn get_enterprise_configuration(_reg_value: &str, env_name: &str) -> String { } } else { // In the case of macOS or Linux, we just read the environment variable: - info!(r"Detected a Unix machine, trying to read the environment variable '{}'.", env_name); + debug!(r"Detected a Unix machine, trying to read the environment variable '{}'.", env_name); match env::var(env_name) { Ok(val) => val, Err(_) => { - info!("The environment variable '{}' was not found.", env_name); + debug!("The environment variable '{}' was not found.", env_name); "".to_string() } } From c6d61a3de0194e42a131828036dff0516fa9f397 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 13:53:00 +0200 Subject: [PATCH 7/9] Implemented another hot reload locking mechanism --- .../PluginSystem/PluginFactory.Download.cs | 3 ++ .../PluginSystem/PluginFactory.HotReload.cs | 35 ++++++++++++-- .../Tools/PluginSystem/PluginFactory.cs | 47 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Download.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Download.cs index 7bad7ec4..e3923b65 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Download.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Download.cs @@ -42,6 +42,7 @@ public static async Task TryDownloadingConfigPluginAsync(Guid configPlugId var tempDownloadFile = Path.GetTempFileName(); try { + await LockHotReloadAsync(); using var httpClient = new HttpClient(); var response = await httpClient.GetAsync(downloadUrl, cancellationToken); if (response.IsSuccessStatusCode) @@ -80,6 +81,8 @@ public static async Task TryDownloadingConfigPluginAsync(Guid configPlugId LOG.LogError(e, "Failed to delete the temporary download file."); } } + + UnlockHotReload(); } return true; diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs index 7bed742e..b7cb0c18 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs @@ -46,12 +46,41 @@ private static async void HotReloadEventHandler(object _, FileSystemEventArgs ar try { LOG.LogInformation($"File changed ({changeType}): {args.FullPath}. Reloading plugins..."); - - // Wait for parallel writes to finish: - await Task.Delay(TimeSpan.FromSeconds(3)); + if (File.Exists(HOT_RELOAD_LOCK_FILE)) + { + LOG.LogInformation("Hot reload lock file exists. Waiting for it to be released before proceeding with the reload."); + + var lockFileCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + var token = lockFileCancellationTokenSource.Token; + var waitTime = TimeSpan.FromSeconds(1); + while (File.Exists(HOT_RELOAD_LOCK_FILE) && !token.IsCancellationRequested) + { + try + { + LOG.LogDebug("Waiting for hot reload lock to be released..."); + await Task.Delay(waitTime, token); + waitTime = TimeSpan.FromSeconds(Math.Min(waitTime.TotalSeconds * 2, 120)); // Exponential backoff with a cap + } + catch (TaskCanceledException) + { + // Case: The cancellation token was triggered, meaning the lock file is still present. + // We expect that something goes wrong. So, we try to delete the lock file: + LOG.LogWarning("Hot reload lock file still exists after 30 seconds. Attempting to delete it..."); + UnlockHotReload(); + break; + } + } + + LOG.LogInformation("Hot reload lock file released. Proceeding with plugin reload."); + } + await LoadAll(); await MessageBus.INSTANCE.SendMessage(null, Event.PLUGINS_RELOADED); } + catch(Exception e) + { + LOG.LogError(e, $"Error while reloading plugins after change in file '{args.FullPath}' with change type '{changeType}'."); + } finally { HOT_RELOAD_SEMAPHORE.Release(); diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs index 352c9bb3..2d7b38b0 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs @@ -13,6 +13,7 @@ public static partial class PluginFactory private static string PLUGINS_ROOT = string.Empty; private static string INTERNAL_PLUGINS_ROOT = string.Empty; private static string CONFIGURATION_PLUGINS_ROOT = string.Empty; + private static string HOT_RELOAD_LOCK_FILE = string.Empty; private static FileSystemWatcher HOT_RELOAD_WATCHER = null!; private static ILanguagePlugin BASE_LANGUAGE_PLUGIN = NoPluginLanguage.INSTANCE; @@ -30,6 +31,7 @@ public static bool Setup() LOG.LogInformation("Initializing plugin factory..."); DATA_DIR = SettingsManager.DataDirectory!; PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins"); + HOT_RELOAD_LOCK_FILE = Path.Join(PLUGINS_ROOT, ".lock"); INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal"); CONFIGURATION_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".config"); @@ -41,6 +43,51 @@ public static bool Setup() LOG.LogInformation("Plugin factory initialized successfully."); return true; } + + private static async Task LockHotReloadAsync() + { + if (!IS_INITIALIZED) + { + LOG.LogError("PluginFactory is not initialized."); + return; + } + + try + { + if (File.Exists(HOT_RELOAD_LOCK_FILE)) + { + LOG.LogWarning("Hot reload lock file already exists."); + return; + } + + await File.WriteAllTextAsync(HOT_RELOAD_LOCK_FILE, DateTime.UtcNow.ToString("o")); + } + catch (Exception e) + { + LOG.LogError(e, "An error occurred while trying to lock hot reloading."); + } + } + + private static void UnlockHotReload() + { + if (!IS_INITIALIZED) + { + LOG.LogError("PluginFactory is not initialized."); + return; + } + + try + { + if(File.Exists(HOT_RELOAD_LOCK_FILE)) + File.Delete(HOT_RELOAD_LOCK_FILE); + else + LOG.LogWarning("Hot reload lock file does not exist. Nothing to unlock."); + } + catch (Exception e) + { + LOG.LogError(e, "An error occurred while trying to unlock hot reloading."); + } + } public static void Dispose() { From df898b1c4d223234ce12ac6327b322d09f121daa Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 14:02:48 +0200 Subject: [PATCH 8/9] Improved I18N --- .../de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua | 4 ++-- .../en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 905283cb..183f19e6 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 @@ -1129,7 +1129,7 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::REWRITEIMPROVE::ASSISTANTREWRITEIMPROVE:: UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::REWRITEIMPROVE::ASSISTANTREWRITEIMPROVE::T3032662264"] = "Benutzerdefinierte Sprache" -- Your input to improve -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::REWRITEIMPROVE::ASSISTANTREWRITEIMPROVE::T3037449423"] = "Ihr Vorschlag zur Verbesserung" +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::REWRITEIMPROVE::ASSISTANTREWRITEIMPROVE::T3037449423"] = "Ihr Text, der verbessert werden soll" -- Writing style UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::REWRITEIMPROVE::ASSISTANTREWRITEIMPROVE::T3754048862"] = "Schreibstil" @@ -4213,7 +4213,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2173617769"] = "Diese Bibliothek wird UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2174764529"] = "Für die sichere Kommunikation zwischen der Benutzeroberfläche und der Laufzeit müssen wir Zertifikate erstellen. Diese Rust-Bibliothek eignet sich hervorragend dafür." -- AI Studio runs without an enterprise configuration. -UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2244723851"] = "AI Studio läuft ohne eine Konfiguration ihrer Organisation." +UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2244723851"] = "Dies ist eine private AI Studio-Installation. Es wird keine Konfiguration einer Organisation verwendet." -- OK UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2246359087"] = "OK" diff --git a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua index 065c7e0e..1b43762c 100644 --- a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua @@ -4213,7 +4213,7 @@ UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2173617769"] = "This library is used t UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2174764529"] = "For the secure communication between the user interface and the runtime, we need to create certificates. This Rust library is great for this purpose." -- AI Studio runs without an enterprise configuration. -UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2244723851"] = "AI Studio runs without an enterprise configuration." +UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2244723851"] = "This is a private AI Studio installation. It runs without an enterprise configuration." -- OK UI_TEXT_CONTENT["AISTUDIO::PAGES::ABOUT::T2246359087"] = "OK" From 89f9fe81e05fb54ce2e95e62e0be130440c55b6a Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 9 Jun 2025 14:06:07 +0200 Subject: [PATCH 9/9] Updated changelog --- app/MindWork AI Studio/wwwroot/changelog/v0.9.48.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.48.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.48.md index 11526d08..33a3c90c 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.48.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.48.md @@ -1 +1,3 @@ # v0.9.48, build 223 (2025-06-xx xx:xx UTC) +- Improved German translation. +- Improved how configurations are applied in organizations and made the process more robust. \ No newline at end of file