mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 00:07:21 +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,3 +1,4 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
@@ -144,15 +145,11 @@ public sealed record ChatThread
|
||||
/// any provider marks the chat as one which holds data of a data source, while a restriction set
|
||||
/// earlier stays. NOT_SPECIFIED demands nothing and changes nothing.<br/><br/>
|
||||
/// Shared by the RAG process and by tools which search the data sources, so both tighten a chat
|
||||
/// the same way.
|
||||
/// the same way. The rule itself is DataSourceSecurityExtensions.TightenedBy, which
|
||||
/// ChatRestrictions uses as well for content which leaves the chat.
|
||||
/// </remarks>
|
||||
/// <param name="dataSecurity">What the data brought in demands.</param>
|
||||
public void RequireDataSecurity(DataSourceSecurity dataSecurity) => this.DataSecurity = (this.DataSecurity, dataSecurity) switch
|
||||
{
|
||||
(DataSourceSecurity.SELF_HOSTED, _) or (_, DataSourceSecurity.SELF_HOSTED) => DataSourceSecurity.SELF_HOSTED,
|
||||
(_, DataSourceSecurity.ALLOW_ANY) => DataSourceSecurity.ALLOW_ANY,
|
||||
_ => this.DataSecurity,
|
||||
};
|
||||
public void RequireDataSecurity(DataSourceSecurity dataSecurity) => this.DataSecurity = this.DataSecurity.TightenedBy(dataSecurity);
|
||||
|
||||
/// <summary>
|
||||
/// Where this chat may still send data, because of the internal content it holds: mails, a
|
||||
@@ -184,16 +181,56 @@ public sealed record ChatThread
|
||||
/// For an assistant which lets tools work in a thread of its own and carries the result over into
|
||||
/// the thread it shows: without this, the result would arrive without the restrictions its data
|
||||
/// demands, and a chat started from it could hand that data to any provider or tool. All three
|
||||
/// ratchets go along, and each one only tightens.
|
||||
/// ratchets go along, and so do the web addresses its models wrote; each part only tightens.
|
||||
/// </remarks>
|
||||
/// <param name="otherThread">The thread whose result this chat takes over.</param>
|
||||
public void RequireRestrictionsOf(ChatThread otherThread)
|
||||
public void RequireRestrictionsOf(ChatThread otherThread) => this.RequireRestrictions(otherThread.CaptureRestrictions());
|
||||
|
||||
/// <summary>
|
||||
/// What this chat demands of everybody who continues with its content, as it stands right now.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A snapshot for content which leaves this chat, such as a message sent to an assistant: the chat
|
||||
/// may tighten later on, while an answer is still being written, but the content which left does
|
||||
/// not hold what arrives afterward. A method rather than a property, so that the snapshot is not
|
||||
/// stored along with the chat.
|
||||
/// </remarks>
|
||||
/// <returns>The restrictions of this chat.</returns>
|
||||
public ChatRestrictions CaptureRestrictions() => new(this.RequiredProviderConfidence, this.DataSecurity, this.RequiredOutboundDataRestriction, this.WebAddressesWrittenByModels);
|
||||
|
||||
/// <summary>
|
||||
/// Tightens this chat to everything the given restrictions demand, and never loosens it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For content which arrives with the restrictions of where it was written, see CaptureRestrictions.
|
||||
/// Each part tightens on its own, by the same rules as when this chat reads something itself.
|
||||
/// </remarks>
|
||||
/// <param name="restrictions">What the content arriving demands.</param>
|
||||
public void RequireRestrictions(ChatRestrictions restrictions)
|
||||
{
|
||||
this.RequireProviderConfidence(otherThread.RequiredProviderConfidence);
|
||||
this.RequireDataSecurity(otherThread.DataSecurity);
|
||||
this.RequireOutboundDataRestriction(otherThread.RequiredOutboundDataRestriction);
|
||||
this.RequireProviderConfidence(restrictions.ProviderConfidence);
|
||||
this.RequireDataSecurity(restrictions.DataSecurity);
|
||||
this.RequireOutboundDataRestriction(restrictions.OutboundData);
|
||||
this.WebAddressesWrittenByModels = this.WebAddressesWrittenByModels.Union(restrictions.WebAddressesWrittenByModels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The web addresses a model wrote which reached this chat inside a message of the user, as request
|
||||
/// keys, see WebAddresses.CreateRequestKey.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An answer of a model which is sent on, to an assistant or into a new chat, becomes a message of the
|
||||
/// user there. Its addresses would then pass for ones the user gave, see IsWebAddressGivenToTheModel,
|
||||
/// although a model chose them and could have put anything of the chat it came from into them. This
|
||||
/// set keeps them apart, see ChatRestrictions.WithWebAddressesWrittenByModelIn.<br/><br/>
|
||||
///
|
||||
/// Stored with the chat, unlike the other sets of addresses: forgetting it after a restart would let
|
||||
/// the chat know more addresses, not fewer. It only ever grows, like the other restrictions, and it is
|
||||
/// immutable, so that a copy of the thread never shares a set which grows later.
|
||||
/// </remarks>
|
||||
[JsonInclude]
|
||||
public ImmutableHashSet<string> WebAddressesWrittenByModels { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// The name of the chat thread. Usually generated by an AI model or manually edited by the user.
|
||||
/// </summary>
|
||||
@@ -259,8 +296,10 @@ public sealed record ChatThread
|
||||
/// message of the user or a document attached to one, see ContentText.RuntimeAttachmentWebAddresses,
|
||||
/// or a tool returned it, see RuntimeWebAddressesFromTools. What the model wrote itself never
|
||||
/// counts, its answers included, because the model could have put anything of the chat into it.
|
||||
/// The comparison is the one of WebAddresses.CreateRequestKey, so an address counts when it
|
||||
/// asks the server for the same.<br/><br/>
|
||||
/// Neither does what any model wrote and what reached this chat as a message of the user, such
|
||||
/// as an answer sent here from another chat, see WebAddressesWrittenByModels. The comparison is
|
||||
/// the one of WebAddresses.CreateRequestKey, so an address counts when it asks the server for
|
||||
/// the same.<br/><br/>
|
||||
/// Shared by both rules of Read Web Page which depend on it: a free address choice switched
|
||||
/// off, and a mailbox which allows the addresses from the chat only.
|
||||
/// </remarks>
|
||||
@@ -281,6 +320,10 @@ public sealed record ChatThread
|
||||
if (messagesOfTheUser.Any(content => content.RuntimeAttachmentWebAddresses.Contains(requestKey)))
|
||||
return true;
|
||||
|
||||
// A model wrote it, even though it stands in a message of the user:
|
||||
if (this.WebAddressesWrittenByModels.Contains(requestKey))
|
||||
return false;
|
||||
|
||||
return messagesOfTheUser
|
||||
.SelectMany(content => WebAddresses.Find(content.Text))
|
||||
.Any(address => WebAddresses.TryCreateRequestKey(address, out var key) && string.Equals(key, requestKey, StringComparison.Ordinal));
|
||||
|
||||
Reference in new issue
Block a user