Added a way to read what the AI received from your sources (#1100)

Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
Paul KoudelkaandThorsten Sommer authored and GitHub committed 2026-10-26 10:00:01 +01:00
1 parent e0d8e18f34
commit cbc4ce5413
229 files changed
+12739 -1269

No files matched your search

@@ -36,6 +36,36 @@ public static partial class SourceExtensions
public static bool IsMailSource(this ISource source) =>
Uri.TryCreate(source.URL.Trim(), UriKind.Absolute, out var address) && address.Scheme.Equals(MAIL_SOURCE_SCHEME, StringComparison.OrdinalIgnoreCase);
/// <summary>
/// The scheme of the address a passage of a data source leaves as a source, when its path is nothing a program can open.
/// </summary>
private const string RETRIEVAL_SOURCE_SCHEME = "retrieval";
/// <summary>
/// The address of the source a passage of a data source leaves in a chat, when its path is
/// nothing a program can open, e.g., a path which only the ERI server knows.
/// </summary>
/// <remarks>
/// Made from the name and the path the data source gave, so that the passages of one document
/// gather under one source, see MergeSources. The host is the same for all of them, since the
/// identity of an address writes its host in lower case. Like the address of a mail, nothing can
/// open it, see HasNoLink.
/// </remarks>
/// <param name="name">The name of the content, e.g., the document.</param>
/// <param name="path">The path the data source gave, which may be empty.</param>
/// <returns>The address.</returns>
public static string CreateRetrievalSourceUrl(string name, string path) => $"{RETRIEVAL_SOURCE_SCHEME}://context/{Uri.EscapeDataString(name)}/{Uri.EscapeDataString(path)}";
/// <summary>
/// Whether nothing can open a source by its address: a mail, or the passage of a data source
/// whose path names nothing to open, see CreateRetrievalSourceUrl.
/// </summary>
/// <param name="source">The source.</param>
/// <returns>True for a source which is named as text, without a link.</returns>
public static bool HasNoLink(this ISource source) =>
Uri.TryCreate(source.URL.Trim(), UriKind.Absolute, out var address)
&& (address.Scheme.Equals(MAIL_SOURCE_SCHEME, StringComparison.OrdinalIgnoreCase) || address.Scheme.Equals(RETRIEVAL_SOURCE_SCHEME, StringComparison.OrdinalIgnoreCase));
private static void AppendMarkdownLink(StringBuilder sb, string title, string url)
{
sb.Append('[');
@@ -181,8 +211,8 @@ public static partial class SourceExtensions
{
sb.Append($"- [{numberedSource.Number}] ");
// A link to a mail would lead nowhere in a document or in the clipboard, so a mail is named only:
if (numberedSource.Source.IsMailSource())
// A link to a mail, or to what only a data source knows, would lead nowhere in a document or in the clipboard, so it is named only:
if (numberedSource.Source.HasNoLink())
sb.Append(EscapeMarkdownLinkText(numberedSource.Source.Title));
else
AppendMarkdownLink(sb, numberedSource.Source.Title, keepPageAnchors ? numberedSource.Source.URL : WithoutPageAnchor(numberedSource.Source.URL));
@@ -305,7 +335,16 @@ public static partial class SourceExtensions
}
}
private static string GetSourceIdentity(string url)
/// <summary>
/// What tells two sources apart: the address without its fragment.
/// </summary>
/// <remarks>
/// The passages of an answer are matched to their sources by the same identity, see
/// SourcePassageExtensions.GetPassagesOf, so a source and its passages always agree.
/// </remarks>
/// <param name="url">The address of a source.</param>
/// <returns>The identity of the source.</returns>
internal static string GetSourceIdentity(string url)
{
var cleanedUrl = url.Trim().Replace("\r", string.Empty).Replace("\n", string.Empty);
if (!Uri.TryCreate(cleanedUrl, UriKind.Absolute, out var absoluteUri))