mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 16:32:10 +00:00
Fixed settings keeping their plugin value after a configuration was withdrawn (#903)
Some checks failed
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Some checks failed
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Sync Flatpak repo (push) Has been cancelled
Build and Release / Collect Flatpak artifacts (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
This commit is contained in:
parent
a3cccb7c7d
commit
b9ec13edcf
@ -143,7 +143,7 @@ Plugins can configure:
|
||||
- etc.
|
||||
|
||||
Configuration plugins provide three kinds of values:
|
||||
- **Managed settings:** simple values such as booleans, numbers, strings, enums, lists, or sets handled through `ManagedConfiguration`. These values may be locked or used as organization defaults. Which configuration plugin owns a locked setting is persisted in `Data.ManagedLockedConfigurations`, and organization defaults are tracked in `Data.ManagedEditableDefaults`. Both are cleaned up generically by `ManagedConfiguration.CleanupLeftOverManagedConfigurations(...)` when the owning plugin is gone.
|
||||
- **Managed settings:** simple values such as booleans, numbers, strings, enums, lists, or sets handled through `ManagedConfiguration`. These values may be locked or used as organization defaults. Which configuration plugin owns a locked setting is persisted in `Data.ManagedLockedConfigurations`, and organization defaults are tracked in `Data.ManagedEditableDefaults`. Both are cleaned up generically by `ManagedConfiguration.CleanupLeftOverManagedConfigurations(...)` when the owning plugin is gone. The value a setting had before a configuration plugin took it over is kept in `Data.ManagedUserValueSnapshots` and restored by that same clean-up, so removing a plugin hands the user's own value back instead of the app default.
|
||||
- **Managed configuration objects:** complex Lua tables that are persisted into `SettingsManager.ConfigurationData`, implement `IConfigurationObject`, and are cleaned up through `PluginConfigurationObject.CleanLeftOverConfigurationObjects(...)`. Examples include providers, profiles, chat templates, data sources, and document analysis policies.
|
||||
- **Live plugin content:** complex Lua tables that implement `ILivePluginContent` and are read live from running plugins instead of being persisted to `ConfigurationData`. Examples include `MANDATORY_INFOS` and `INTRODUCTIONS`. If live plugin content creates persistent side data, add a dedicated cleanup path for that side data, like mandatory-info acceptances.
|
||||
|
||||
|
||||
@ -238,6 +238,21 @@ CONFIG["SETTINGS"] = {}
|
||||
-- DataAssistantPluginAudit.EnterpriseApprovedPlugins.
|
||||
-- ------
|
||||
|
||||
-- ------
|
||||
-- What happens to a setting when your configuration is removed
|
||||
-- ------
|
||||
--
|
||||
-- AI Studio remembers the value a setting had before a configuration took it over.
|
||||
-- Once no configuration manages that setting anymore -- because your IT department
|
||||
-- stopped deploying this configuration, because the user deleted it, or because a test
|
||||
-- configuration ended -- the user gets that value back. When there is nothing to
|
||||
-- restore, e.g. for a setting the user had never changed, AI Studio falls back to its
|
||||
-- own default value.
|
||||
--
|
||||
-- One case differs: when you allow users to override a setting and somebody makes use
|
||||
-- of that, their choice outlives your configuration and stays as it is.
|
||||
-- ------
|
||||
|
||||
-- Configure the update check interval:
|
||||
-- Allowed values are: NO_CHECK, DISABLE_UPDATES, ONCE_STARTUP, HOURLY, DAILY, WEEKLY
|
||||
-- NO_CHECK disables automatic checks, but users can still check and install updates manually.
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
@ -57,6 +58,31 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
||||
/// <inheritdoc/>
|
||||
public override bool RemovePluginContribution(Guid configPluginId) => this.pluginContributions.Remove(configPluginId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string SerializeCurrentValue() => ManagedConfiguration.SerializeManagedScalarValue(this.GetValue());
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string SerializeCurrentValueAsJson() => JsonSerializer.Serialize(this.GetValue(), SettingsManager.JSON_OPTIONS);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override bool TrySetValueFromJson(string json)
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = JsonSerializer.Deserialize<TValue>(json, SettingsManager.JSON_OPTIONS);
|
||||
if (value is null)
|
||||
return false;
|
||||
|
||||
this.SetValue(value);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.LogWarning(e, $"Was not able to restore the value of the setting '{this.SettingName}' from its snapshot '{json}'. Using the default value instead.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Reset()
|
||||
{
|
||||
|
||||
@ -12,6 +12,8 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
{
|
||||
protected static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
|
||||
protected static ILogger Log => Program.LOGGER_FACTORY.CreateLogger(nameof(ConfigMetaBase));
|
||||
|
||||
/// <summary>
|
||||
/// The persisted name of the configuration setting.
|
||||
/// </summary>
|
||||
@ -89,14 +91,14 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
public void ResetLockedConfiguration()
|
||||
{
|
||||
SettingsManagerAccess.ConfigurationData.ManagedLockedConfigurations.Remove(this.SettingName);
|
||||
|
||||
|
||||
this.IsLocked = false;
|
||||
this.LockedByConfigPluginId = Guid.Empty;
|
||||
|
||||
|
||||
if (this.ManagedMode is ManagedConfigurationMode.LOCKED)
|
||||
this.ManagedMode = null;
|
||||
|
||||
this.Reset();
|
||||
this.RestoreUserValueOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -137,6 +139,29 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
this.EditableDefaultByConfigPluginId = Guid.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the editable-default state and hands the setting back to the user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Without a snapshot of the user's value, the current value stays as it is. That is the
|
||||
/// difference to a locked setting: the user was allowed to change an editable default all
|
||||
/// along, so its value is a plausible choice of theirs. Resetting it to the app's default would
|
||||
/// take away something nobody asked us to remove.
|
||||
/// </remarks>
|
||||
/// <param name="keepCurrentValue">
|
||||
/// True when the user has changed the value in the meantime. Their decision outlives the
|
||||
/// configuration plugin, so the snapshot is dropped instead of applied.
|
||||
/// </param>
|
||||
public void ResetEditableDefaultConfiguration(bool keepCurrentValue)
|
||||
{
|
||||
this.ClearEditableDefaultConfiguration();
|
||||
|
||||
if (keepCurrentValue)
|
||||
this.ClearUserValueSnapshot();
|
||||
else
|
||||
this.TryRestoreUserValueSnapshot();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the contribution of one configuration plugin without changing the current value.
|
||||
/// </summary>
|
||||
@ -144,6 +169,96 @@ public abstract record ConfigMetaBase(string SettingName) : IConfig
|
||||
/// <returns>True when that plugin had a contribution, otherwise false.</returns>
|
||||
public abstract bool RemovePluginContribution(Guid configPluginId);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the value the user had chosen before a configuration plugin took over
|
||||
/// this setting is still available.
|
||||
/// </summary>
|
||||
public bool HasUserValueSnapshot => SettingsManagerAccess.ConfigurationData.ManagedUserValueSnapshots.ContainsKey(this.SettingName);
|
||||
|
||||
/// <summary>
|
||||
/// Remembers the current value as the user's value, so that it can be restored once no
|
||||
/// configuration plugin manages this setting anymore.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only an unmanaged setting holds a value which belongs to the user. When one configuration
|
||||
/// plugin takes a setting over from another, the current value belongs to the previous plugin,
|
||||
/// so the snapshot of the user's value must survive that handover untouched.<br/><br/>
|
||||
/// The persisted editable default counts as managed as well: unlike a locked setting, it is not
|
||||
/// restored into the in-memory state when the settings are loaded, so right after a start it is
|
||||
/// the only evidence that a configuration plugin is already in charge.
|
||||
/// </remarks>
|
||||
public void CaptureUserValueSnapshot()
|
||||
{
|
||||
if (this.ManagedMode is not null || SettingsManagerAccess.ConfigurationData.ManagedEditableDefaults.ContainsKey(this.SettingName))
|
||||
return;
|
||||
|
||||
var snapshots = SettingsManagerAccess.ConfigurationData.ManagedUserValueSnapshots;
|
||||
if (snapshots.ContainsKey(this.SettingName))
|
||||
return;
|
||||
|
||||
snapshots[this.SettingName] = this.SerializeCurrentValueAsJson();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the value the user had chosen before a configuration plugin took over this setting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The snapshot is consumed either way: when it cannot be applied, keeping it would mean trying
|
||||
/// the same broken value again on every start.
|
||||
/// </remarks>
|
||||
/// <returns>True when a snapshot was available and could be applied, otherwise false.</returns>
|
||||
private bool TryRestoreUserValueSnapshot()
|
||||
{
|
||||
var snapshots = SettingsManagerAccess.ConfigurationData.ManagedUserValueSnapshots;
|
||||
if (!snapshots.Remove(this.SettingName, out var snapshot))
|
||||
return false;
|
||||
|
||||
return this.TrySetValueFromJson(snapshot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the snapshot of the user's value without changing the current value.
|
||||
/// </summary>
|
||||
/// <returns>True when a snapshot was dropped, otherwise false.</returns>
|
||||
public bool ClearUserValueSnapshot() => SettingsManagerAccess.ConfigurationData.ManagedUserValueSnapshots.Remove(this.SettingName);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the current value the same way the managed states record it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is meant for comparisons, e.g. to tell whether the user has changed an editable default
|
||||
/// in the meantime. It is not meant for restoring a value: the representation is lossy.
|
||||
/// </remarks>
|
||||
public abstract string SerializeCurrentValue();
|
||||
|
||||
/// <summary>
|
||||
/// Restores the user's value, or falls back to the default value when no snapshot is available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Settings which a configuration plugin managed before this app version has no snapshot, and
|
||||
/// neither has a setting whose value the user never changed. The default value is the best
|
||||
/// answer in both cases.
|
||||
/// </remarks>
|
||||
private void RestoreUserValueOrDefault()
|
||||
{
|
||||
if (this.TryRestoreUserValueSnapshot())
|
||||
return;
|
||||
|
||||
this.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the current value as JSON, so that it can be restored without losing information.
|
||||
/// </summary>
|
||||
protected abstract string SerializeCurrentValueAsJson();
|
||||
|
||||
/// <summary>
|
||||
/// Applies a value which was serialized by SerializeCurrentValueAsJson.
|
||||
/// </summary>
|
||||
/// <param name="json">The serialized value.</param>
|
||||
/// <returns>True when the value could be applied, otherwise false.</returns>
|
||||
protected abstract bool TrySetValueFromJson(string json);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the configuration property to its default value.
|
||||
/// </summary>
|
||||
|
||||
@ -68,6 +68,18 @@ public sealed class Data
|
||||
/// </summary>
|
||||
public Dictionary<string, Guid> ManagedLockedConfigurations { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// The value each managed setting had before a configuration plugin took it over, as JSON.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A configuration plugin might be removed later, e.g. when a test configuration ends or when an
|
||||
/// organization withdraws its configuration. The value the user had chosen before belongs to the
|
||||
/// user, so we keep it here and restore it instead of falling back to the app's default value.
|
||||
/// The snapshot is taken once, when a setting becomes managed, and is consumed when no
|
||||
/// configuration plugin manages that setting anymore.
|
||||
/// </remarks>
|
||||
public Dictionary<string, string> ManagedUserValueSnapshots { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Cached audit results for assistant plugins.
|
||||
/// </summary>
|
||||
|
||||
@ -913,6 +913,13 @@ public static partial class ManagedConfiguration
|
||||
if (!MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
//
|
||||
// Remember the value the user had chosen before any configuration plugin took this setting
|
||||
// over. Once no plugin manages it anymore, we hand that value back to the user:
|
||||
//
|
||||
if (successful)
|
||||
configMeta.CaptureUserValueSnapshot();
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true:
|
||||
@ -967,6 +974,15 @@ public static partial class ManagedConfiguration
|
||||
if (!MayManageSetting(configPluginId, configMeta))
|
||||
return false;
|
||||
|
||||
//
|
||||
// Remember the value the user had chosen before any configuration plugin took this setting
|
||||
// over. Once no plugin manages it anymore, we hand that value back to the user. This has to
|
||||
// happen before the managed state below changes, because only an unmanaged setting holds a
|
||||
// value which belongs to the user:
|
||||
//
|
||||
if (successful)
|
||||
configMeta.CaptureUserValueSnapshot();
|
||||
|
||||
switch (successful)
|
||||
{
|
||||
case true when managedMode is ManagedConfigurationMode.LOCKED:
|
||||
@ -1008,7 +1024,7 @@ public static partial class ManagedConfiguration
|
||||
case false when configMeta.ManagedMode is ManagedConfigurationMode.EDITABLE_DEFAULT
|
||||
&& TryGetEditableDefaultState(settingName, out var editableDefaultStateToRemove)
|
||||
&& editableDefaultStateToRemove.ConfigPluginId == configPluginId:
|
||||
configMeta.ClearEditableDefaultConfiguration();
|
||||
configMeta.ResetEditableDefaultConfiguration(HasUserChangedEditableDefault(configMeta, editableDefaultStateToRemove));
|
||||
ClearEditableDefaultState(settingName);
|
||||
break;
|
||||
}
|
||||
@ -1033,7 +1049,7 @@ public static partial class ManagedConfiguration
|
||||
return ManagedConfigurationMode.LOCKED;
|
||||
}
|
||||
|
||||
private static string SerializeManagedScalarValue<TValue>(TValue value) => value switch
|
||||
internal static string SerializeManagedScalarValue<TValue>(TValue value) => value switch
|
||||
{
|
||||
null => string.Empty,
|
||||
string text => text,
|
||||
|
||||
@ -361,6 +361,19 @@ public static partial class ManagedConfiguration
|
||||
configMeta.RemovePluginContribution(contributingConfigPluginId);
|
||||
wasChanged = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Finally, drop any snapshot of the user's value which nobody claims anymore. Without
|
||||
// this, a setting which stopped being managed outside of the paths above would keep its
|
||||
// snapshot in the settings file forever. The persisted editable default counts as a
|
||||
// claim as well: it survives a configuration plugin which is deployed but could not be
|
||||
// loaded, and that plugin is still in charge:
|
||||
//
|
||||
if (configMeta.ManagedMode is null && !TryGetEditableDefaultState(configMeta.SettingName, out _) && configMeta.ClearUserValueSnapshot())
|
||||
{
|
||||
Log.LogInformation($"Dropping the snapshot of the user's value for the setting '{configMeta.SettingName}': no configuration plugin manages it anymore.");
|
||||
wasChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove persisted states which belong to settings that do not exist anymore:
|
||||
@ -405,6 +418,13 @@ public static partial class ManagedConfiguration
|
||||
wasChanged = true;
|
||||
}
|
||||
|
||||
foreach (var settingName in configurationData.ManagedUserValueSnapshots.Keys.Where(x => !registeredSettingNames.Contains(x)).ToList())
|
||||
{
|
||||
Log.LogInformation($"Removing the snapshot of the user's value for the setting '{settingName}': this setting does not exist anymore.");
|
||||
configurationData.ManagedUserValueSnapshots.Remove(settingName);
|
||||
wasChanged = true;
|
||||
}
|
||||
|
||||
return wasChanged;
|
||||
}
|
||||
|
||||
@ -447,7 +467,7 @@ public static partial class ManagedConfiguration
|
||||
if (configMeta.ManagedMode is not ManagedConfigurationMode.EDITABLE_DEFAULT)
|
||||
return false;
|
||||
|
||||
configMeta.ClearEditableDefaultConfiguration();
|
||||
configMeta.ResetEditableDefaultConfiguration(keepCurrentValue: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -455,7 +475,17 @@ public static partial class ManagedConfiguration
|
||||
return false;
|
||||
|
||||
Log.LogInformation($"Clearing the editable default of the setting '{configMeta.SettingName}': the configuration plugin '{editableDefaultState.ConfigPluginId}' is not available anymore.");
|
||||
configMeta.ClearEditableDefaultConfiguration();
|
||||
configMeta.ResetEditableDefaultConfiguration(HasUserChangedEditableDefault(configMeta, editableDefaultState));
|
||||
return ClearEditableDefaultState(configMeta.SettingName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the user has changed an editable default themselves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The user may change an editable default at any time. When the current value is not the one
|
||||
/// the configuration plugin applied last, the user decided against that value, and their
|
||||
/// decision outlives the plugin.
|
||||
/// </remarks>
|
||||
private static bool HasUserChangedEditableDefault(ConfigMetaBase configMeta, ManagedEditableDefaultState editableDefaultState) => !string.Equals(configMeta.SerializeCurrentValue(), editableDefaultState.LastAppliedValue, StringComparison.Ordinal);
|
||||
}
|
||||
@ -23,7 +23,7 @@ public sealed class SettingsManager
|
||||
|
||||
private readonly record struct CurrentSettingsReadResult(Data? SettingsData, SettingsWriteBlockReason FailureReason);
|
||||
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Converters = { new TolerantEnumConverter() },
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
- Fixed reset buttons in assistants. As you may have noticed in the Document Analysis Assistant, resetting it could leave content from the previous analysis visible. Reset buttons now clear previous results completely.
|
||||
- Fixed dropping files after you closed a dialog that accepts files itself. Such a dialog takes over dropped files while it is open, but never handed that role back when you closed it. Afterwards, the chat and the assistants silently ignored dropped files until you switched to another page. Each time you opened such a dialog again, the problem got worse.
|
||||
- Fixed configuration-managed settings remaining active after their configuration plugin was removed.
|
||||
- Fixed settings not returning to your own value after a configuration was removed. When a configuration takes control of a setting, AI Studio now remembers the value you had chosen before and hands it back once no configuration manages that setting anymore. This covers an IT department withdrawing a configuration, deleting one yourself, and an administrator ending a test configuration. When a configuration only suggested a value and you changed it afterwards, your choice stays as it is.
|
||||
- Fixed the integrated code editor to keep errors and other issues in plugin code visible in the footer while scrolling.
|
||||
- Fixed the trusted badge so you can now see at a glance which models are trusted. It is shown consistently for self-hosted models and models from trusted providers.
|
||||
- Fixed approvals for assistant plugins being accepted from any configuration plugin. An approval marks an assistant as safe without a security check, and the app states that your organization approved it. Only configurations your IT department deploys, or that an administrator stages for a test, can do that now; approvals from any other locally placed configuration plugin are ignored and reported in the log.
|
||||
|
||||
@ -304,7 +304,7 @@ A typical layered setup:
|
||||
| Department | `100` | Refines the base, e.g. a different default model |
|
||||
| Project or lab | `200` | Refines the department configuration |
|
||||
|
||||
A configuration only overrides what it actually defines. Everything it does not mention keeps the value of the configuration below it. The same applies when you remove a configuration later: its settings fall back to the configuration below, not to the AI Studio defaults.
|
||||
A configuration only overrides what it actually defines. Everything it does not mention keeps the value of the configuration below it. The same applies when you remove a configuration later: its settings fall back to the configuration below, not to the AI Studio defaults. Once no configuration manages a setting anymore, see [Withdrawing a configuration](#withdrawing-a-configuration).
|
||||
|
||||
Give two configurations that must override each other different priorities. With an equal priority, the order is stable across restarts but arbitrary, so the outcome is not the one you designed.
|
||||
|
||||
@ -342,6 +342,19 @@ In both cases each configuration keeps its own contribution, so removing one of
|
||||
|
||||
One clarification for `DataChat.PreselectedDataSourceIds`: the IDs are not limited to the data sources of the same configuration. They are resolved against every known data source, including those of your other configurations and the ones a user configured. IDs that resolve to nothing are ignored.
|
||||
|
||||
## Withdrawing a configuration
|
||||
|
||||
A configuration does not have to stay forever: you stop deploying it, a user deletes a configuration they installed themselves, or a test configuration ends with the next restart. AI Studio then removes what that configuration brought along, such as its providers, data sources, profiles, chat templates, and its approvals for assistant plugins.
|
||||
|
||||
Settings go one step further. AI Studio remembers the value each setting had before a configuration took it over and hands it back once no configuration manages that setting anymore. Somebody who had chosen a start page before your configuration set one therefore gets their own start page back, not the AI Studio default.
|
||||
|
||||
Two cases differ:
|
||||
|
||||
- **There is nothing to hand back.** When a setting still had its AI Studio default at the moment your configuration took it over, that default returns. The same applies to settings which a configuration already managed before AI Studio v26.8.1, because nothing was remembered back then.
|
||||
- **Somebody used `AllowUserOverride`.** A setting you offered as an organization default, and which the user changed afterwards, keeps the user's value. Their decision outlives your configuration.
|
||||
|
||||
A configuration that is deployed but cannot be loaded, e.g. because of an error in its Lua code, is not withdrawn. It still manages the device, so everything it brought along stays untouched until you actually stop deploying it.
|
||||
|
||||
## 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:
|
||||
|
||||
@ -460,7 +473,7 @@ Keep in mind that everybody in the group loses the test configuration the next t
|
||||
|
||||
### Cleaning up
|
||||
|
||||
Restart AI Studio: the test directory is emptied, the approvals are gone, and the assistant requires a security audit again. To end a test without restarting, delete the configuration on the plugin page.
|
||||
Restart AI Studio: the test directory is emptied, the approvals are gone, and the assistant requires a security audit again. Every setting your test configuration had taken over returns to the value it had before the test, as described in [Withdrawing a configuration](#withdrawing-a-configuration). To end a test without restarting, delete the configuration on the plugin page.
|
||||
|
||||
### Security note
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user