mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 19:47:22 +00:00
Added a Send to menu to every chat message and kept restrictions when sending content on (#1124)
This commit is contained in:
1 parent
d06688ca08
commit
bf54b8cd0d
73 files changed
+1923
-390
No files matched your search
@@ -1,6 +1,7 @@
|
||||
using System.Text;
|
||||
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.Agenda;
|
||||
@@ -266,16 +267,9 @@ public partial class AssistantAgenda : AssistantBaseCore<SettingsDialogAgenda>
|
||||
state.RestoreList(CONTENT_LINES_STATE_KEY, this.contentLines);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_AGENDA_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContent = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputContent = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@using AIStudio.Chat
|
||||
@using AIStudio.Settings.DataModel
|
||||
@inherits AssistantLowerBase
|
||||
@typeparam TSettings
|
||||
|
||||
@@ -128,7 +127,7 @@
|
||||
{
|
||||
@if (this.ShowSendTo && this.VisibleSendToAssistants.Count > 0)
|
||||
{
|
||||
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded">
|
||||
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded" MaxHeight="@MenuDefaults.MAX_HEIGHT">
|
||||
@foreach (var assistant in this.VisibleSendToAssistants)
|
||||
{
|
||||
<MudMenuItem OnClick="@(async () => await this.SendToAssistant(assistant, new()))">
|
||||
@@ -160,7 +159,7 @@
|
||||
case SendToButton sendToButton:
|
||||
@if (this.VisibleSendToAssistants.Count > 0)
|
||||
{
|
||||
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded">
|
||||
<MudMenu AnchorOrigin="Origin.TopLeft" TransformOrigin="Origin.BottomLeft" StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@TB("Send to ...")" Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded" MaxHeight="@MenuDefaults.MAX_HEIGHT">
|
||||
@foreach (var assistant in this.VisibleSendToAssistants)
|
||||
{
|
||||
<MudMenuItem OnClick="@(async () => await this.SendToAssistant(assistant, sendToButton))">
|
||||
@@ -200,7 +199,7 @@
|
||||
@* No selection where the assistant's own rules already name the tools: *@
|
||||
@if (this.SettingsManager.AreToolsEnabled() && this.AssistantManagedToolIds is null && this.SettingsManager.IsToolSelectionVisible(this.Component))
|
||||
{
|
||||
<ToolSelection Component="@this.Component" LLMProvider="@this.ProviderSettings" RequiredOutboundDataRestriction="@(this.ChatThread?.RequiredOutboundDataRestriction ?? OutboundDataRequirement.NONE)" SelectedToolIds="@this.SelectedToolIds" SelectedToolIdsChanged="@this.SelectedToolIdsChanged" Disabled="@this.IsProcessing" />
|
||||
<ToolSelection Component="@this.Component" LLMProvider="@this.ProviderSettings" RequiredOutboundDataRestriction="@this.CurrentRestrictions.OutboundData" SelectedToolIds="@this.SelectedToolIds" SelectedToolIdsChanged="@this.SelectedToolIdsChanged" Disabled="@this.IsProcessing" />
|
||||
}
|
||||
|
||||
<MudSpacer />
|
||||
|
||||
@@ -4,6 +4,7 @@ using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AIJobs;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
using AIStudio.Tools.Media;
|
||||
using AIStudio.Tools.Services;
|
||||
@@ -48,6 +49,9 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
[Inject]
|
||||
protected AssistantSessionService AssistantSessionService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private AssistantLaunchService AssistantLaunchService { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the job service used to run assistant-created chats independently from the assistant UI.
|
||||
/// </summary>
|
||||
@@ -162,6 +166,44 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
protected virtual ChatThread ConvertToChatThread => this.CreateSendToChatThread();
|
||||
|
||||
/// <summary>
|
||||
/// Takes over a text which another assistant or a chat sent to this assistant.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Every assistant which content may be sent to puts the text into its main field, see
|
||||
/// ComponentsExtensions.AllowSendTo. It comes before the preselected values, so a field which those only fill
|
||||
/// when empty keeps the text. An assistant which allows sending to it but takes nothing would leave the text
|
||||
/// lost without a word, which is why a test checks that each one overrides this.
|
||||
/// </remarks>
|
||||
/// <param name="payload">The text sent.</param>
|
||||
protected virtual void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.Logger.LogError("The assistant '{Component}' allows sending text to it, but it does not take the text.", this.Component);
|
||||
|
||||
/// <summary>
|
||||
/// What the text sent to this assistant demands, because of where it came from.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An answer written from mails demands here what it demanded in its chat. The thread of the
|
||||
/// assistant is created anew with every run, so the restrictions live here and go onto every thread
|
||||
/// this assistant runs, see AssignRuntimeIdentity, and onto every tool list, see GetRunnableToolIds.
|
||||
/// They stay until the form is reset, which removes the text as well.
|
||||
/// </remarks>
|
||||
private ChatRestrictions transferredRestrictions = ChatRestrictions.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// What everything this assistant holds demands: the text sent to it and what its current thread read.
|
||||
/// </summary>
|
||||
private ChatRestrictions CurrentRestrictions => this.ChatThread?.CaptureRestrictions().StricterOf(this.transferredRestrictions) ?? this.transferredRestrictions;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps what the current result demands, before the assistant puts that result into its own input.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Call this before clearing the thread: the result was written from what this thread read, and the
|
||||
/// web addresses in it were written by a model. Both stay with the input until the form is reset.
|
||||
/// </remarks>
|
||||
/// <param name="resultText">The result which becomes the new input.</param>
|
||||
protected void TakeOverRestrictionsOfResult(string resultText) => this.transferredRestrictions = this.CurrentRestrictions.WithWebAddressesWrittenByModelIn(resultText);
|
||||
|
||||
private protected virtual RenderFragment? HeaderActions => null;
|
||||
|
||||
private protected virtual RenderFragment? AfterResultContent => null;
|
||||
@@ -213,6 +255,13 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// A text sent here comes first, so that the preselected values below only fill what it left empty:
|
||||
if (AssistantLaunchService.TakeTextPayload(this.Component) is { } textLaunchPayload)
|
||||
{
|
||||
this.transferredRestrictions = textLaunchPayload.Restrictions;
|
||||
this.ApplyTextLaunchPayload(textLaunchPayload);
|
||||
}
|
||||
|
||||
this.MediaTranscriptionService.StateChanged += this.OnMediaImportStateChanged;
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
@@ -276,25 +325,30 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.Confidence.ShowProviderConfidence ? this.ProviderSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty;
|
||||
|
||||
private IReadOnlyList<Tools.Components> VisibleSendToAssistants => Enum.GetValues<AIStudio.Tools.Components>()
|
||||
.Where(this.CanSendToAssistant)
|
||||
.OrderBy(component => component.Name().Length)
|
||||
.ToArray();
|
||||
private IReadOnlyList<Tools.Components> VisibleSendToAssistants => this.AssistantLaunchService.GetDestinationsFor(this.Component);
|
||||
|
||||
protected string? ValidatingProvider(AIStudio.Settings.Provider provider)
|
||||
{
|
||||
if(provider.UsedLLMProvider == LLMProviders.NONE)
|
||||
return this.TB("Please select a provider.");
|
||||
|
||||
|
||||
// A provider which nothing else rules out may still be kept from the text sent here, because of where it came from:
|
||||
if (!this.transferredRestrictions.IsLLMProviderAllowed(provider) && ChatRestrictions.NONE.IsLLMProviderAllowed(provider))
|
||||
return this.TB("This provider may not see the text sent to this assistant, because of where the text came from. Please select another provider.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task Start()
|
||||
{
|
||||
//
|
||||
// A provider which may not see the text sent here would fail the run without a word, see
|
||||
// ContentText.CreateFromProviderAsync, so the user hears about it before the run starts:
|
||||
//
|
||||
await this.RefreshProviderSelectionFromConfigurationAsync();
|
||||
if (this.ProviderSettings == Settings.Provider.NONE)
|
||||
if (this.ProviderSettings == Settings.Provider.NONE || this.ValidatingProvider(this.ProviderSettings) is not null)
|
||||
{
|
||||
await this.ReportMissingProviderAsync();
|
||||
await this.ReportProviderIssueAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -367,16 +421,17 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the user that the assistant cannot start without a provider, together with whatever else is missing.
|
||||
/// Tells the user that the assistant cannot start with the selected provider, together with whatever else is missing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Most assistants validate their form only in their submit action, which never runs without a
|
||||
/// provider. Validating here marks the provider selection and lists the other issues as well.
|
||||
/// The form does not report the missing provider when it holds no provider selection, as with an
|
||||
/// assistant plugin without one, or when its selection still shows the provider which the refresh
|
||||
/// at the start has just dropped. Then the issue is added on its own.
|
||||
/// Either no provider is selected, or the selected one may not see the text sent to this assistant,
|
||||
/// see ValidatingProvider. Most assistants validate their form only in their submit action, which
|
||||
/// never runs without a usable provider. Validating here marks the provider selection and lists the
|
||||
/// other issues as well. The form does not report the issue when it holds no provider selection, as
|
||||
/// with an assistant plugin without one, or when its selection still shows the provider which the
|
||||
/// refresh at the start has just dropped. Then the issue is added on its own.
|
||||
/// </remarks>
|
||||
private async Task ReportMissingProviderAsync()
|
||||
private async Task ReportProviderIssueAsync()
|
||||
{
|
||||
if (this.Form is not null)
|
||||
await this.Form.Validate();
|
||||
@@ -466,16 +521,20 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
/// <summary>
|
||||
/// Sets who runs the given thread: this assistant's component and, for an assistant plugin, its name.
|
||||
/// It also puts the restrictions of a text sent to this assistant on the thread.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Both decide which tools the thread may use and what its requests to self-hosted servers name. Every
|
||||
/// way an assistant creates or sends a thread goes through here, so that none of them can forget one.
|
||||
/// That is why the restrictions of a text sent here go onto the thread here, too: every thread of this
|
||||
/// assistant may hold that text, its private threads for research included.
|
||||
/// </remarks>
|
||||
/// <param name="chatThread">The thread this assistant runs.</param>
|
||||
protected void AssignRuntimeIdentity(ChatThread chatThread)
|
||||
{
|
||||
chatThread.RuntimeComponent = this.Component;
|
||||
chatThread.RuntimeAssistantName = this.RuntimeAssistantName;
|
||||
chatThread.RequireRestrictions(this.transferredRestrictions);
|
||||
}
|
||||
|
||||
private Task RefreshProviderSelectionFromConfigurationAsync()
|
||||
@@ -515,9 +574,12 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
/// the user a tool for good. The same goes for a tool which a mailbox the thread read from
|
||||
/// keeps back.
|
||||
/// </remarks>
|
||||
/// <param name="outboundDataRestriction">Where the thread the tools run in may still send data, see ChatThread.RequiredOutboundDataRestriction.</param>
|
||||
/// <param name="outboundDataRestriction">Where the thread the tools run in may still send data, see ChatThread.RequiredOutboundDataRestriction. A text sent to this assistant may demand more, and then that counts.</param>
|
||||
protected HashSet<string> GetRunnableToolIds(OutboundDataRestriction outboundDataRestriction)
|
||||
{
|
||||
// Every thread of this assistant may hold the text sent to it, so what that text demands holds whoever asks:
|
||||
outboundDataRestriction = outboundDataRestriction.StricterOf(this.transferredRestrictions.OutboundData.Restriction);
|
||||
|
||||
if (this.AssistantManagedToolIds is not null)
|
||||
return this.ToolRegistry.FilterToolIdsForProvider(this.ProviderSettings, this.AssistantManagedToolIds, outboundDataRestriction);
|
||||
|
||||
@@ -834,7 +896,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
|
||||
protected async Task SendToAssistant(Tools.Components destination, SendToButton sendToButton)
|
||||
{
|
||||
if (!this.CanSendToAssistant(destination))
|
||||
if (!this.VisibleSendToAssistants.Contains(destination))
|
||||
return;
|
||||
|
||||
var contentToSend = sendToButton == default ? string.Empty : sendToButton.UseResultingContentBlockData switch
|
||||
@@ -847,57 +909,33 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
},
|
||||
};
|
||||
|
||||
var sendToData = destination.GetData();
|
||||
if (destination.HasSingleSessionSlot() && this.AssistantSessionService.GetSnapshots().Any(snapshot => snapshot.IsActive && snapshot.Key.Component == destination))
|
||||
// The chat starts from the conversation of this assistant, unless it only takes the text for the next message:
|
||||
if (destination is Tools.Components.CHAT && !sendToButton.SendToChatAsInput)
|
||||
{
|
||||
await this.MessageBus.SendWarning(new(Icons.Material.Filled.Apps, this.TB("This assistant is already running. AI Studio opens the running session instead.")));
|
||||
this.NavigationManager.NavigateTo(sendToData.Route);
|
||||
var convertedChatThread = this.ConvertToChatThread;
|
||||
convertedChatThread = convertedChatThread with { SelectedProvider = this.ProviderSettings.Id };
|
||||
|
||||
//
|
||||
// The chat holds what this assistant held, whichever thread the assistant builds it from: some
|
||||
// assistants start it from a new thread, which has read nothing, or from none at all. The copy
|
||||
// above is the chat's own, so tightening it leaves the thread of this assistant as it is:
|
||||
//
|
||||
convertedChatThread.RequireRestrictions(this.CurrentRestrictions);
|
||||
|
||||
// Some assistants start the chat under an id of its own, so what their answers received goes along. A chat without an id received nothing:
|
||||
if (this.ChatThread is { } assistantChat && convertedChatThread.ChatId != Guid.Empty && assistantChat.ChatId != convertedChatThread.ChatId)
|
||||
await ChatProvenance.CopyChatAsync(assistantChat.ChatId, convertedChatThread.ChatId);
|
||||
|
||||
MessageBus.INSTANCE.DeferMessage(this, Event.SEND_TO_CHAT, new ChatStartRequest(convertedChatThread));
|
||||
this.NavigationManager.NavigateTo(Routes.CHAT);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only components with a single session slot may be cleared as a group. The visual briefing
|
||||
// assistant keys its sessions per briefing, so clearing by component would discard the
|
||||
// status of every stored briefing instead of the one we are about to open.
|
||||
if (destination.HasSingleSessionSlot())
|
||||
await this.AssistantSessionService.ClearInactiveSessionsForComponentAsync(destination);
|
||||
|
||||
switch (destination)
|
||||
{
|
||||
case Tools.Components.CHAT:
|
||||
if (sendToButton.SendToChatAsInput)
|
||||
MessageBus.INSTANCE.DeferMessage(this, Event.SEND_TO_CHAT_INPUT, contentToSend);
|
||||
else
|
||||
{
|
||||
var convertedChatThread = this.ConvertToChatThread;
|
||||
convertedChatThread = convertedChatThread with { SelectedProvider = this.ProviderSettings.Id };
|
||||
|
||||
// Some assistants start the chat under an id of its own, so what their answers received goes along. A chat without an id received nothing:
|
||||
if (this.ChatThread is { } assistantChat && convertedChatThread.ChatId != Guid.Empty && assistantChat.ChatId != convertedChatThread.ChatId)
|
||||
await ChatProvenance.CopyChatAsync(assistantChat.ChatId, convertedChatThread.ChatId);
|
||||
|
||||
MessageBus.INSTANCE.DeferMessage(this, sendToData.Event, new ChatStartRequest(convertedChatThread));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MessageBus.INSTANCE.DeferMessage(this, sendToData.Event, contentToSend);
|
||||
break;
|
||||
}
|
||||
|
||||
this.NavigationManager.NavigateTo(sendToData.Route);
|
||||
// A model wrote what an assistant sends, even when it falls back to the input, so it gets filtered, and none of its addresses counts as given:
|
||||
var payload = await this.AssistantLaunchService.CreateTextPayloadAsync(contentToSend, writtenByModel: true, this.CurrentRestrictions, this.Title);
|
||||
await this.AssistantLaunchService.LaunchAsync(destination, payload);
|
||||
}
|
||||
|
||||
private bool CanSendToAssistant(Tools.Components component)
|
||||
{
|
||||
if (!component.AllowSendTo())
|
||||
return false;
|
||||
|
||||
return this.SettingsManager.IsAssistantVisible(
|
||||
component,
|
||||
withLogging: false,
|
||||
requiredPreviewFeature: component.RequiredPreviewFeature());
|
||||
}
|
||||
|
||||
private async Task InnerResetForm()
|
||||
{
|
||||
if ((this.AssistantSessionService.TryGetSnapshot(this.assistantSessionKey)?.IsActive ?? false)
|
||||
@@ -908,6 +946,9 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
this.MediaTranscriptionService.ClearOwnerState(this.CurrentMediaImportOwner);
|
||||
this.assistantSessionId = null;
|
||||
this.ClearConversationState();
|
||||
|
||||
// The text sent here is gone with the form, and what it demanded goes with it:
|
||||
this.transferredRestrictions = ChatRestrictions.NONE;
|
||||
this.ProviderSettings = Settings.Provider.NONE;
|
||||
|
||||
await this.JsRuntime.ClearDiv(BEFORE_RESULT_DIV_ID);
|
||||
@@ -1149,6 +1190,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
state.Set(INPUT_ISSUES_STATE_KEY, this.InputIssues);
|
||||
state.Set(IS_PROCESSING_STATE_KEY, this.IsProcessing);
|
||||
state.Set(SELECTED_TOOL_IDS_STATE_KEY, this.SelectedToolIds);
|
||||
state.Set(TRANSFERRED_RESTRICTIONS_STATE_KEY, this.transferredRestrictions);
|
||||
this.CaptureCustomAssistantSessionState(state);
|
||||
|
||||
return state.ToDictionary();
|
||||
@@ -1177,6 +1219,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
reader.Restore(INPUT_ISSUES_STATE_KEY, value => this.InputIssues = value);
|
||||
reader.Restore(IS_PROCESSING_STATE_KEY, value => this.IsProcessing = value);
|
||||
reader.Restore(SELECTED_TOOL_IDS_STATE_KEY, value => this.SelectedToolIds = this.ToolRegistry.NormalizeSelection(value));
|
||||
reader.Restore(TRANSFERRED_RESTRICTIONS_STATE_KEY, value => this.transferredRestrictions = value);
|
||||
this.RestoreCustomAssistantSessionState(reader);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ public abstract class AssistantLowerBase : MSGComponentBase
|
||||
protected static readonly AssistantSessionStateKey<string[]> INPUT_ISSUES_STATE_KEY = new(nameof(InputIssues));
|
||||
protected static readonly AssistantSessionStateKey<bool> IS_PROCESSING_STATE_KEY = new(nameof(IsProcessing));
|
||||
protected static readonly AssistantSessionStateKey<HashSet<string>> SELECTED_TOOL_IDS_STATE_KEY = new("SelectedToolIds");
|
||||
protected static readonly AssistantSessionStateKey<ChatRestrictions> TRANSFERRED_RESTRICTIONS_STATE_KEY = new("TransferredRestrictions");
|
||||
|
||||
protected AIStudio.Settings.Provider ProviderSettings = Settings.Provider.NONE;
|
||||
protected bool InputIsValid;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.Coding;
|
||||
@@ -139,16 +140,9 @@ public partial class AssistantCoding : AssistantBaseCore<SettingsDialogCoding>
|
||||
state.Restore(QUESTIONS_STATE_KEY, value => this.questions = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_CODING_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.questions = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.questions = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text;
|
||||
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.EMail;
|
||||
@@ -120,16 +121,9 @@ public partial class AssistantEMail : AssistantBaseCore<SettingsDialogWritingEMa
|
||||
state.Restore(INPUT_HISTORY_STATE_KEY, value => this.inputHistory = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_EMAIL_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputBulletPoints = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputBulletPoints = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
+3
-10
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.GrammarSpelling;
|
||||
@@ -31,7 +32,6 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore<SettingsDialog
|
||||
[
|
||||
new SendToButton
|
||||
{
|
||||
Self = Tools.Components.GRAMMAR_SPELLING_ASSISTANT,
|
||||
UseResultingContentBlockData = false,
|
||||
GetText = () => string.IsNullOrWhiteSpace(this.correctedText) ? this.inputText : this.correctedText
|
||||
},
|
||||
@@ -68,16 +68,9 @@ public partial class AssistantGrammarSpelling : AssistantBaseCore<SettingsDialog
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_GRAMMAR_SPELLING_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -331,8 +331,8 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T1840311560"] = "Export re
|
||||
-- The media transcription was canceled.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T241403726"] = "The media transcription was canceled."
|
||||
|
||||
-- This assistant is already running. AI Studio opens the running session instead.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T2575715765"] = "This assistant is already running. AI Studio opens the running session instead."
|
||||
-- This provider may not see the text sent to this assistant, because of where the text came from. Please select another provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T268581738"] = "This provider may not see the text sent to this assistant, because of where the text came from. Please select another provider."
|
||||
|
||||
-- Assistant - {0}
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::ASSISTANTBASE::T3043922"] = "Assistant - {0}"
|
||||
@@ -3454,6 +3454,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGASSISTANT::
|
||||
-- Please provide a custom protection level.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGASSISTANT::T799692129"] = "Please provide a custom protection level."
|
||||
|
||||
-- This provider may not see the text sent to this briefing, because of where the text came from. Please select another provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGASSISTANT::T869841458"] = "This provider may not see the text sent to this briefing, because of where the text came from. Please select another provider."
|
||||
|
||||
-- Please provide a briefing name.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGASSISTANT::T902674552"] = "Please provide a briefing name."
|
||||
|
||||
@@ -3601,6 +3604,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGFAILUREEXTE
|
||||
-- The assembled briefing did not pass the security validation.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGFAILUREEXTENSIONS::T295498807"] = "The assembled briefing did not pass the security validation."
|
||||
|
||||
-- The selected provider may not see the content of this briefing. Please select another provider.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGFAILUREEXTENSIONS::T300791290"] = "The selected provider may not see the content of this briefing. Please select another provider."
|
||||
|
||||
-- The charts of the model response did not match the planned briefing elements. Please try again or select another model.
|
||||
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::VISUALBRIEFING::VISUALBRIEFINGFAILUREEXTENSIONS::T3326200304"] = "The charts of the model response did not match the planned briefing elements. Please try again or select another model."
|
||||
|
||||
@@ -3772,6 +3778,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4188329028"] = "No, kee
|
||||
-- No tool calls
|
||||
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4224149521"] = "No tool calls"
|
||||
|
||||
-- Send to ...
|
||||
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4242312602"] = "Send to ..."
|
||||
|
||||
-- No arguments
|
||||
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T931993614"] = "No arguments"
|
||||
|
||||
@@ -12694,26 +12703,26 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::MAILBOXTRANSPORTSECURITYEXTENSIO
|
||||
-- Unknown encryption
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::MAILBOXTRANSPORTSECURITYEXTENSIONS::T685301366"] = "Unknown encryption"
|
||||
|
||||
-- This chat found content in a data source which has been removed since, while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T1103975982"] = "This chat found content in a data source which has been removed since, while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from your Confluence wiki, found while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T1689639786"] = "This chat holds content from your Confluence wiki, found while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat read an internal web page on '{0}' while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T1307134700"] = "This chat read an internal web page on '{0}' while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from the mailbox '{0}', read while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T1878172266"] = "This chat holds content from the mailbox '{0}', read while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat searched your Confluence wiki while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T1719013859"] = "This chat searched your Confluence wiki while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from a data source which has been removed since, found while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T2154420164"] = "This chat holds content from a data source which has been removed since, found while its setting 'Where a chat may send data after reading this data source' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat found content in the data source '{0}' while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T2391737974"] = "This chat found content in the data source '{0}' while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from a mailbox which has been removed since, read while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T2474328188"] = "This chat holds content from a mailbox which has been removed since, read while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat read mails from the mailbox '{0}' while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T3290545516"] = "This chat read mails from the mailbox '{0}' while its setting 'Where a chat may send data after reading mails' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from an internal web page on '{0}', read while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T3062480014"] = "This chat holds content from an internal web page on '{0}', read while the setting 'Where a chat may send data after reading internal pages' of the tool 'Read Web Page' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat read internal content while the chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T3482648272"] = "This chat read internal content while the chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds content from the data source '{0}', found while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T3148548820"] = "This chat holds content from the data source '{0}', found while its setting 'Where a chat may send data after reading this data source' was '{1}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- This chat read mails from a mailbox which has been removed since, while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T996427866"] = "This chat read mails from a mailbox which has been removed since, while its setting 'Where a chat may send data after reading mails' was '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat can use it again."
|
||||
-- This chat holds internal content, read while a chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again.
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATAREQUIREMENTEXTENSIONS::T348053469"] = "This chat holds internal content, read while a chat was restricted to '{0}'. This tool would send data beyond that, so it is not available in this chat. A new chat without this content can use it again."
|
||||
|
||||
-- Unknown restriction
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::OUTBOUNDDATARESTRICTIONEXTENSIONS::T1376332431"] = "Unknown restriction"
|
||||
@@ -12859,6 +12868,12 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T4193824894"] = "
|
||||
-- Learning
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T755590027"] = "Learning"
|
||||
|
||||
-- This assistant is already running. AI Studio opens the running session instead.
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTLAUNCH::ASSISTANTLAUNCHSERVICE::T2575715765"] = "This assistant is already running. AI Studio opens the running session instead."
|
||||
|
||||
-- Unnamed chat
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTLAUNCH::ASSISTANTLAUNCHSERVICE::T3310482275"] = "Unnamed chat"
|
||||
|
||||
-- SSO (Kerberos)
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::AUTHMETHODSV1EXTENSIONS::T268552140"] = "SSO (Kerberos)"
|
||||
|
||||
@@ -15610,6 +15625,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::SECURITY::PROMPTINJECTIONSOURCEKINDEXTENSIONS:
|
||||
-- Data source description
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SECURITY::PROMPTINJECTIONSOURCEKINDEXTENSIONS::T1553588912"] = "Data source description"
|
||||
|
||||
-- AI answer
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SECURITY::PROMPTINJECTIONSOURCEKINDEXTENSIONS::T2066071095"] = "AI answer"
|
||||
|
||||
-- Web content
|
||||
UI_TEXT_CONTENT["AISTUDIO::TOOLS::SECURITY::PROMPTINJECTIONSOURCEKINDEXTENSIONS::T2626468388"] = "Web content"
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.IconFinder;
|
||||
@@ -74,16 +75,9 @@ public partial class AssistantIconFinder : AssistantBaseCore<SettingsDialogIconF
|
||||
state.Restore(SELECTED_ICON_SOURCE_STATE_KEY, value => this.selectedIconSource = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_ICON_FINDER_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContext = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputContext = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.JobPosting;
|
||||
@@ -173,16 +174,9 @@ public partial class AssistantJobPostings : AssistantBaseCore<SettingsDialogJobP
|
||||
state.Restore(CUSTOM_TARGET_LANGUAGE_STATE_KEY, value => this.customTargetLanguage = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_JOB_POSTING_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputJobDescription = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputJobDescription = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.LegalCheck;
|
||||
@@ -91,16 +92,9 @@ public partial class AssistantLegalCheck : AssistantBaseCore<SettingsDialogLegal
|
||||
state.Restore(INPUT_QUESTIONS_STATE_KEY, value => this.inputQuestions = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_LEGAL_CHECK_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputQuestions = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputQuestions = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.MyTasks;
|
||||
@@ -135,16 +136,9 @@ public partial class AssistantMyTasks : AssistantBaseCore<SettingsDialogMyTasks>
|
||||
state.Restore(CUSTOM_TARGET_LANGUAGE_STATE_KEY, value => this.customTargetLanguage = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_MY_TASKS_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Text.Json;
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
using AIStudio.Tools.Services;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
@@ -110,7 +111,6 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
|
||||
},
|
||||
new SendToButton
|
||||
{
|
||||
Self = Tools.Components.PROMPT_OPTIMIZER_ASSISTANT,
|
||||
UseResultingContentBlockData = false,
|
||||
SendToChatAsInput = true,
|
||||
GetText = () => string.IsNullOrWhiteSpace(this.optimizedPrompt) ? this.inputPrompt : this.optimizedPrompt,
|
||||
@@ -163,13 +163,11 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
|
||||
this.ResetGuidelineSummaryToDefault();
|
||||
this.hasUpdatedDefaultRecommendations = false;
|
||||
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_PROMPT_OPTIMIZER_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputPrompt = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputPrompt = payload.Text;
|
||||
|
||||
private string inputPrompt = string.Empty;
|
||||
private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS;
|
||||
private string customTargetLanguage = string.Empty;
|
||||
@@ -460,6 +458,7 @@ public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialog
|
||||
if (!this.CanImproveFurther)
|
||||
return Task.CompletedTask;
|
||||
|
||||
this.TakeOverRestrictionsOfResult(this.optimizedPrompt);
|
||||
this.inputPrompt = this.optimizedPrompt;
|
||||
this.ResetOutput();
|
||||
this.ClearConversationState();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.RewriteImprove;
|
||||
@@ -32,7 +33,6 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
|
||||
[
|
||||
new SendToButton
|
||||
{
|
||||
Self = Tools.Components.REWRITE_ASSISTANT,
|
||||
UseResultingContentBlockData = false,
|
||||
GetText = () => string.IsNullOrWhiteSpace(this.rewrittenText) ? this.inputText : this.rewrittenText,
|
||||
},
|
||||
@@ -73,16 +73,9 @@ public partial class AssistantRewriteImprove : AssistantBaseCore<SettingsDialogR
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_REWRITE_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ public partial class AssistantSWOTAnalysis
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
// The research runs in a thread of its own, which has read nothing yet:
|
||||
// The research runs in a thread of its own, which has read nothing yet. A text sent to this
|
||||
// assistant may still demand more, and GetRunnableToolIds holds the research to that:
|
||||
var runnableToolIds = this.GetRunnableToolIds(OutboundDataRestriction.UNRESTRICTED);
|
||||
if (runnableToolIds.Count > 0)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
using AIStudio.Tools.Security;
|
||||
using AIStudio.Tools.Services;
|
||||
@@ -160,16 +161,9 @@ public partial class AssistantSWOTAnalysis : AssistantBaseCore<SettingsDialogSWO
|
||||
state.Restore(SHARED_RESEARCH_CONTEXT_STATE_KEY, value => this.sharedResearchContext = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_SWOT_ANALYSIS_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
using AIStudio.Tools.PowerPoint;
|
||||
using AIStudio.Tools.Security;
|
||||
@@ -399,16 +400,9 @@ public partial class SlideAssistant : AssistantBaseCore<SettingsDialogSlideBuild
|
||||
this.StartCountingPictureLibrary();
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_SLIDE_BUILDER_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContent = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputContent = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.Synonym;
|
||||
@@ -127,16 +128,9 @@ public partial class AssistantSynonyms : AssistantBaseCore<SettingsDialogSynonym
|
||||
state.Restore(CUSTOM_TARGET_LANGUAGE_STATE_KEY, value => this.customTargetLanguage = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_SYNONYMS_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputContext = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputContext = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.TextSummarizer;
|
||||
@@ -116,16 +117,9 @@ public partial class AssistantTextSummarizer : AssistantBaseCore<SettingsDialogT
|
||||
state.Restore(IMPORTANT_ASPECTS_STATE_KEY, value => this.importantAspects = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_TEXT_SUMMARIZER_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
|
||||
namespace AIStudio.Assistants.Translation;
|
||||
@@ -120,16 +121,9 @@ public partial class AssistantTranslation : AssistantBaseCore<SettingsDialogTran
|
||||
state.Restore(CUSTOM_TARGET_LANGUAGE_STATE_KEY, value => this.customTargetLanguage = value);
|
||||
}
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
#region Overrides of AssistantBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var deferredContent = MessageBus.INSTANCE.TakeDeferredMessages<string>(Event.SEND_TO_TRANSLATION_ASSISTANT).LastOrDefault();
|
||||
if (deferredContent is not null)
|
||||
this.inputText = deferredContent;
|
||||
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
protected override void ApplyTextLaunchPayload(TextLaunchPayload payload) => this.inputText = payload.Text;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ internal sealed class StructuredLlmStageRunner(
|
||||
/// <typeparam name="T">The strict response type.</typeparam>
|
||||
/// <param name="provider">The selected provider configuration.</param>
|
||||
/// <param name="profile">The selected user profile.</param>
|
||||
/// <param name="restrictions">What the content of the briefing demands, see VisualBriefingManifest.Restrictions.</param>
|
||||
/// <param name="systemContract">The stage-specific system contract.</param>
|
||||
/// <param name="prompt">The user prompt containing stage inputs.</param>
|
||||
/// <param name="attachments">The first-turn attachments.</param>
|
||||
@@ -31,6 +32,7 @@ internal sealed class StructuredLlmStageRunner(
|
||||
public async Task<StructuredLlmStageResult<T>> RunAsync<T>(
|
||||
ProviderSettings provider,
|
||||
Profile profile,
|
||||
ChatRestrictions restrictions,
|
||||
string systemContract,
|
||||
string prompt,
|
||||
IReadOnlyList<FileAttachment> attachments,
|
||||
@@ -79,6 +81,10 @@ internal sealed class StructuredLlmStageRunner(
|
||||
],
|
||||
};
|
||||
|
||||
// The thread of the stage holds what the briefing holds. The orchestrator checked the provider before the
|
||||
// build started; the provider call checks it against the thread once more:
|
||||
thread.RequireRestrictions(restrictions);
|
||||
|
||||
VisualBriefingContractIssue? repairIssue = null;
|
||||
for (var attempt = 1; attempt <= 2; attempt++)
|
||||
{
|
||||
|
||||
+9
-2
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Tools.Media;
|
||||
@@ -58,7 +59,13 @@ public partial class VisualBriefingAssistant
|
||||
/// <summary>
|
||||
/// Defines <c>CreateBriefingAsync</c> for the visual briefing feature.
|
||||
/// </summary>
|
||||
private async Task CreateBriefingAsync()
|
||||
private Task CreateBriefingAsync() => this.CreateBriefingAsync(ChatRestrictions.NONE);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a briefing which holds content with the given restrictions, see VisualBriefingManifest.Restrictions.
|
||||
/// </summary>
|
||||
/// <param name="restrictions">What the content of the briefing demands.</param>
|
||||
private async Task CreateBriefingAsync(ChatRestrictions restrictions)
|
||||
{
|
||||
var defaults = this.SettingsManager.ConfigurationData.VisualBriefing;
|
||||
var defaultProvider = this.SettingsManager.GetPreselectedProvider(ComponentKind.VISUAL_BRIEFING_ASSISTANT);
|
||||
@@ -79,7 +86,7 @@ public partial class VisualBriefingAssistant
|
||||
OptimizeImages = defaults.OptimizeImages,
|
||||
};
|
||||
|
||||
var briefing = await this.Store.CreateAsync(suggestedName, string.Empty, settings);
|
||||
var briefing = await this.Store.CreateAsync(suggestedName, string.Empty, settings, restrictions);
|
||||
await this.ReloadListAsync(briefing.BriefingId);
|
||||
}
|
||||
|
||||
|
||||
+16
-4
@@ -1,3 +1,4 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Rust;
|
||||
@@ -109,10 +110,21 @@ public partial class VisualBriefingAssistant
|
||||
private string? ValidateProjectName(string name) => string.IsNullOrWhiteSpace(name) ? T("Please provide a briefing name.") : null;
|
||||
|
||||
/// <summary>Validates the selected generation provider.</summary>
|
||||
private string? ValidateProvider(ProviderSettings value) =>
|
||||
value == ProviderSettings.NONE || value.UsedLLMProvider is LLMProviders.NONE
|
||||
? T("Please select a provider.")
|
||||
: null;
|
||||
/// <remarks>
|
||||
/// A provider which may not see a text sent to this briefing is reported here, before the build starts. A provider the
|
||||
/// organization prohibited is not: it fails for every briefing alike, and the build reports it.
|
||||
/// </remarks>
|
||||
private string? ValidateProvider(ProviderSettings value)
|
||||
{
|
||||
if (value == ProviderSettings.NONE || value.UsedLLMProvider is LLMProviders.NONE)
|
||||
return T("Please select a provider.");
|
||||
|
||||
var restrictions = this.selectedBriefing?.Restrictions ?? ChatRestrictions.NONE;
|
||||
if (!restrictions.IsLLMProviderAllowed(value) && ChatRestrictions.NONE.IsLLMProviderAllowed(value))
|
||||
return T("This provider may not see the text sent to this briefing, because of where the text came from. Please select another provider.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Validates the free-form target language when Other is selected.</summary>
|
||||
private string? ValidateCustomTargetLanguage(string language) =>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Dialogs;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Tools.AssistantLaunch;
|
||||
using AIStudio.Tools.AssistantSessions;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
@@ -152,20 +154,18 @@ public partial class VisualBriefingAssistant : MSGComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
this.ApplyFilters([], [Event.SEND_TO_VISUAL_BRIEFING_ASSISTANT, Event.CONFIGURATION_CHANGED]);
|
||||
this.ApplyFilters([], [Event.CONFIGURATION_CHANGED]);
|
||||
this.MediaTranscriptionService.StateChanged += this.MediaStateChanged;
|
||||
this.BuildProgressService.Changed += this.BuildProgressChanged;
|
||||
await this.ReloadListAsync();
|
||||
await this.ConsumePendingMediaOutcomesAsync();
|
||||
this.MonitorSourceStatusAsync(this.sourceMonitorCancellation.Token).Observe($"{nameof(VisualBriefingAssistant)}: monitoring the source status");
|
||||
var deferredInstruction = this.MessageBus.TakeDeferredMessages<string>(Event.SEND_TO_VISUAL_BRIEFING_ASSISTANT).LastOrDefault();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(deferredInstruction))
|
||||
if (AssistantLaunchService.TakeTextPayload(ComponentKind.VISUAL_BRIEFING_ASSISTANT) is { } textLaunchPayload && !string.IsNullOrWhiteSpace(textLaunchPayload.Text))
|
||||
{
|
||||
if (this.selectedBriefing is null)
|
||||
await this.CreateBriefingAsync();
|
||||
|
||||
this.editor.Instruction = deferredInstruction;
|
||||
// A text sent here starts a briefing of its own, which holds what the text demands. The briefing
|
||||
// open last belongs to other work, and its instruction would be gone:
|
||||
await this.CreateBriefingAsync(textLaunchPayload.Restrictions);
|
||||
this.editor.Instruction = textLaunchPayload.Text;
|
||||
await this.SaveCurrentAsync();
|
||||
}
|
||||
|
||||
@@ -235,17 +235,6 @@ public partial class VisualBriefingAssistant : MSGComponentBase
|
||||
/// </summary>
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
if (triggeredEvent is Event.SEND_TO_VISUAL_BRIEFING_ASSISTANT && data is string text)
|
||||
{
|
||||
if (this.selectedBriefing is null)
|
||||
await this.CreateBriefingAsync();
|
||||
|
||||
this.editor.Instruction = text;
|
||||
await this.SaveCurrentAsync();
|
||||
this.StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (triggeredEvent is Event.CONFIGURATION_CHANGED)
|
||||
{
|
||||
// The spellchecking setting might have changed. Since this page is not re-parameterized
|
||||
|
||||
+23
@@ -1,3 +1,4 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Rust;
|
||||
@@ -233,6 +234,28 @@ internal sealed partial class VisualBriefingBuildOrchestrator
|
||||
"No provider is selected.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the selected provider may see what the briefing holds.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A text sent to the briefing demands what it demanded where it came from, see VisualBriefingManifest.Restrictions,
|
||||
/// and a provider the organization prohibited may see nothing at all. The provider call of each stage would refuse
|
||||
/// such a provider as well, but only once the build runs, and the stage would fail without telling why.
|
||||
/// </remarks>
|
||||
/// <param name="manifest">The briefing manifest.</param>
|
||||
/// <param name="provider">The provider.</param>
|
||||
internal static void ValidateProviderMaySeeContent(VisualBriefingManifest manifest, ProviderSettings provider)
|
||||
{
|
||||
if (manifest.Restrictions.IsLLMProviderAllowed(provider))
|
||||
return;
|
||||
|
||||
throw new VisualBriefingBuildException(
|
||||
VisualBriefingFailureCode.PROVIDER_NOT_ALLOWED,
|
||||
VisualBriefingBuildStage.SOURCE_PREPARATION,
|
||||
"The selected provider may not see the content of this briefing.",
|
||||
$"ProviderFamily={provider.UsedLLMProvider}; RequiredConfidence={manifest.Restrictions.ProviderConfidence}; DataSecurity={manifest.Restrictions.DataSecurity}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures content-generating builds have at least one source-material file.
|
||||
/// </summary>
|
||||
|
||||
@@ -114,6 +114,7 @@ internal sealed partial class VisualBriefingBuildOrchestrator
|
||||
try
|
||||
{
|
||||
ValidateProvider(provider);
|
||||
ValidateProviderMaySeeContent(manifest, provider);
|
||||
ValidateSourceMaterial(manifest, mode);
|
||||
var parentContext = await this.LoadParentContextAsync(manifest, mode, parentRevisionId, token);
|
||||
VisualBriefingEvidenceArtifact? reusableEvidence = null;
|
||||
|
||||
@@ -37,7 +37,7 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
|
||||
await store.SaveBuildAsync(build, token);
|
||||
progressService.Publish(build);
|
||||
|
||||
var run = await stageRunner.RunAsync<VisualBriefingContentResponse>(provider, profile, BuildSystemContract(),
|
||||
var run = await stageRunner.RunAsync<VisualBriefingContentResponse>(provider, profile, manifest.Restrictions, BuildSystemContract(),
|
||||
BuildPrompt(manifest, evidence, plan), [], VisualBriefingBuildStage.CONTENT, build.OperationId, build.BuildId,
|
||||
response => this.ValidateResponseAndProject(manifest, plan, evidence, response), token);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ internal sealed class VisualBriefingEvidenceStage(StructuredLlmStageRunner stage
|
||||
progressService.Publish(build);
|
||||
|
||||
var run = await stageRunner.RunAsync<VisualBriefingEvidenceResponse>(
|
||||
provider, profile, BuildSystemContract(), BuildPrompt(manifest, preparedSources), preparedSources.Attachments, VisualBriefingBuildStage.EVIDENCE,
|
||||
provider, profile, manifest.Restrictions, BuildSystemContract(), BuildPrompt(manifest, preparedSources), preparedSources.Attachments, VisualBriefingBuildStage.EVIDENCE,
|
||||
build.OperationId, build.BuildId, response => VisualBriefingValidation.ValidateEvidence(manifest, response), token);
|
||||
|
||||
stage.Attempts = run.Attempts;
|
||||
|
||||
@@ -18,6 +18,11 @@ public enum VisualBriefingFailureCode
|
||||
/// </summary>
|
||||
PROVIDER_NOT_SELECTED,
|
||||
|
||||
/// <summary>
|
||||
/// The selected provider may not see the content of the briefing.
|
||||
/// </summary>
|
||||
PROVIDER_NOT_ALLOWED,
|
||||
|
||||
/// <summary>
|
||||
/// The selected model lacks a required capability.
|
||||
/// </summary>
|
||||
|
||||
@@ -83,6 +83,7 @@ internal static class VisualBriefingFailureExtensions
|
||||
private static string ToUserMessage(this VisualBriefingFailureCode code) => code switch
|
||||
{
|
||||
VisualBriefingFailureCode.PROVIDER_NOT_SELECTED => TB("This briefing has no provider selected. Please select a provider before you generate a briefing."),
|
||||
VisualBriefingFailureCode.PROVIDER_NOT_ALLOWED => TB("The selected provider may not see the content of this briefing. Please select another provider."),
|
||||
VisualBriefingFailureCode.MODEL_CAPABILITY_MISSING => TB("The selected model lacks a capability this briefing needs. Please select another model."),
|
||||
VisualBriefingFailureCode.SOURCE_UNREACHABLE => TB("A source of this briefing can no longer be reached. Please relink or remove the affected source."),
|
||||
VisualBriefingFailureCode.TRANSCRIPT_UNAVAILABLE => TB("A media transcript of this briefing is missing or outdated. Please transcribe the affected media again."),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
/// <summary>
|
||||
@@ -40,6 +42,18 @@ public sealed class VisualBriefingManifest
|
||||
/// </summary>
|
||||
public VisualBriefingLocalSettings Settings { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// What the text sent to this briefing demands, because of where it came from.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An answer written from mails demands here what it demanded in its chat, and every stage of every build
|
||||
/// holds to it. The restrictions are set when the briefing is created for the text, and they never loosen:
|
||||
/// the text may still be part of the instruction, and of the versions built from it. They live here rather
|
||||
/// than in the settings, which the editor replaces with every save. A briefing nothing was sent to, or one
|
||||
/// written before this property existed, demands nothing.
|
||||
/// </remarks>
|
||||
public ChatRestrictions Restrictions { get; init; } = ChatRestrictions.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Defines <c>Sources</c> for the visual briefing feature.
|
||||
/// </summary>
|
||||
|
||||
@@ -42,7 +42,7 @@ internal sealed class VisualBriefingPlanStage(StructuredLlmStageRunner stageRunn
|
||||
await store.SaveBuildAsync(build, token);
|
||||
progressService.Publish(build);
|
||||
|
||||
var run = await stageRunner.RunAsync<VisualBriefingPlanResponse>(provider, profile, BuildSystemContract(), BuildPrompt(manifest, evidence),
|
||||
var run = await stageRunner.RunAsync<VisualBriefingPlanResponse>(provider, profile, manifest.Restrictions, BuildSystemContract(), BuildPrompt(manifest, evidence),
|
||||
[], VisualBriefingBuildStage.PLAN, build.OperationId, build.BuildId, response => VisualBriefingValidation.ValidatePlan(evidence, response), token);
|
||||
|
||||
stage.Attempts = run.Attempts;
|
||||
|
||||
@@ -42,7 +42,7 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
|
||||
await store.SaveBuildAsync(build, token);
|
||||
progressService.Publish(build);
|
||||
|
||||
var run = await stageRunner.RunAsync<VisualBriefingDesignResponse>(provider, profile, BuildSystemContract(),
|
||||
var run = await stageRunner.RunAsync<VisualBriefingDesignResponse>(provider, profile, manifest.Restrictions, BuildSystemContract(),
|
||||
BuildPrompt(manifest, plan, parentPresentation), [], VisualBriefingBuildStage.DESIGN, build.OperationId, build.BuildId,
|
||||
response => ValidateDesign(manifest, plan, content, response), token);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
public sealed partial class VisualBriefingStore
|
||||
@@ -294,10 +296,14 @@ public sealed partial class VisualBriefingStore
|
||||
/// <summary>
|
||||
/// Defines <c>CreateAsync</c> for the visual briefing feature.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The restrictions are set here only, see VisualBriefingManifest.Restrictions: nothing later on loosens them.
|
||||
/// </remarks>
|
||||
public async Task<VisualBriefingManifest> CreateAsync(
|
||||
string name,
|
||||
string author,
|
||||
VisualBriefingLocalSettings settings,
|
||||
ChatRestrictions restrictions,
|
||||
Guid? briefingId = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
@@ -330,6 +336,7 @@ public sealed partial class VisualBriefingStore
|
||||
CreatedAtUtc = now,
|
||||
ModifiedAtUtc = now,
|
||||
Settings = settings,
|
||||
Restrictions = restrictions,
|
||||
};
|
||||
|
||||
await this.StoreManifestAtomicAsync(manifest, token);
|
||||
@@ -455,6 +462,8 @@ public sealed partial class VisualBriefingStore
|
||||
/// </summary>
|
||||
private async Task StoreManifestAtomicAsync(VisualBriefingManifest manifest, CancellationToken token)
|
||||
{
|
||||
// What is written now holds everything of the current version, the restrictions among them, which an older AI Studio cannot read:
|
||||
manifest.ManifestVersion = VisualBriefingVersions.MANIFEST;
|
||||
var json = JsonSerializer.Serialize(manifest, JSON_OPTIONS);
|
||||
await WriteTextAtomicAsync(this.ManifestPath(manifest.BriefingId), json, overwrite: true, token);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Chat;
|
||||
|
||||
namespace AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
public sealed partial class VisualBriefingStore
|
||||
@@ -339,6 +341,10 @@ public sealed partial class VisualBriefingStore
|
||||
export.Name,
|
||||
export.Author,
|
||||
SettingsFromExport(export),
|
||||
|
||||
// An export is a file outside AI Studio, which carries neither the instruction nor any restrictions.
|
||||
// A briefing which exists here already keeps its own:
|
||||
ChatRestrictions.NONE,
|
||||
export.BriefingId,
|
||||
token);
|
||||
}
|
||||
@@ -440,6 +446,9 @@ public sealed partial class VisualBriefingStore
|
||||
parts.ExportManifest.Name,
|
||||
parts.ExportManifest.Author,
|
||||
SettingsFromExport(parts.ExportManifest),
|
||||
|
||||
// An export is a file outside AI Studio, which carries neither the instruction nor any restrictions:
|
||||
ChatRestrictions.NONE,
|
||||
copyId,
|
||||
token);
|
||||
|
||||
|
||||
@@ -9,7 +9,11 @@ public static class VisualBriefingVersions
|
||||
public const int ARTIFACT = 1;
|
||||
|
||||
/// <summary>Gets the project manifest contract version.</summary>
|
||||
public const int MANIFEST = 1;
|
||||
/// <remarks>
|
||||
/// Version 2 added the restrictions of a text sent to the briefing. An older version of AI Studio cannot
|
||||
/// read them, so it tells the user that the briefing needs a newer version instead of ignoring them.
|
||||
/// </remarks>
|
||||
public const int MANIFEST = 2;
|
||||
|
||||
/// <summary>Gets the canonical data schema version.</summary>
|
||||
public const int SCHEMA = 2;
|
||||
|
||||
Reference in new issue
Block a user