Renamed the extension classes of interfaces to drop the I prefix (#1190)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-11 16:17:45 +01:00
1 parent d8ef328e6e
commit 6f187f1bd8
30 files changed
+59 -59

No files matched your search

@@ -16,7 +16,7 @@ namespace AIStudio.Assistants.BeyondFactsLab;
/// <para>
/// A shortened material is the beginning of the text which passed the prompt injection filter when the person added
/// it. It does not pass the filter again: cutting off the end of a text adds nothing which the filter did not see,
/// unlike IRetrievalContextExtensions.ShortenToFitAsync, which cuts the unfiltered text of a data source.
/// unlike RetrievalContextExtensions.ShortenToFitAsync, which cuts the unfiltered text of a data source.
/// </para>
/// <para>
/// An image takes no characters: as many images as the model takes at once go along with the first message of the
@@ -313,7 +313,7 @@ public sealed class BflMaterialService(BeyondFactsLabStore store, RustService ru
/// <returns>True when the preparation has the image now, also as a material it had already.</returns>
private async Task<bool> AddImageAsync(Guid projectId, string path, string name, long size, string hash)
{
var prepared = await rustService.PrepareImageForModelAsync(path, IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES);
var prepared = await rustService.PrepareImageForModelAsync(path, ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES);
if (!prepared.IsPrepared)
{
logger.LogWarning("The BeyondFacts Lab could not prepare the image '{Path}': {ErrorCode}.", path, prepared.ErrorCode);
@@ -5375,16 +5375,16 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T373499115"] = "Your data sources
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T713722424"] = "AI Studio could not store what the AI received separately from your chat. It remains in the chat itself, so you can still read it."
-- The local image file does not exist. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image."
-- Failed to download the image from the URL. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T2996654916"] = "Failed to download the image from the URL. Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T2996654916"] = "Failed to download the image from the URL. Skipping the image."
-- The local image file is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T3219823625"] = "The local image file is too large (>10 MB). Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T3219823625"] = "The local image file is too large (>10 MB). Skipping the image."
-- The image at the URL is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T349928509"] = "The image at the URL is too large (>10 MB). Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T349928509"] = "The image at the URL is too large (>10 MB). Skipping the image."
-- Export configuration
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ADMINEXPORTBUTTON::T975426229"] = "Export configuration"
@@ -1,6 +1,6 @@
namespace AIStudio.Chat;
public static class IContentExtensions
public static class ContentExtensions
{
/// <param name="content">The content of a message in the chat.</param>
extension(IContent content)
@@ -4,9 +4,9 @@ using AIStudio.Tools.PluginSystem;
namespace AIStudio.Chat;
public static class IImageSourceExtensions
public static class ImageSourceExtensions
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(IImageSourceExtensions).Namespace, nameof(IImageSourceExtensions));
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(ImageSourceExtensions).Namespace, nameof(ImageSourceExtensions));
/// <summary>
/// The largest image, in bytes, we send anywhere: no image prepared for a model is larger, and
@@ -5377,16 +5377,16 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T373499115"] = "Ihre Datenquellen
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T713722424"] = "AI Studio konnte die Inhalte, die die KI erhalten hat, nicht getrennt von Ihrem Chat speichern. Diese bleiben im Chat selbst, sodass Sie sie weiterhin lesen können."
-- The local image file does not exist. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "Die lokale Bilddatei existiert nicht. Das Bild wird übersprungen."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T255679918"] = "Die lokale Bilddatei existiert nicht. Das Bild wird übersprungen."
-- Failed to download the image from the URL. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T2996654916"] = "Das Bild konnte nicht von der URL heruntergeladen werden. Das Bild wird übersprungen."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T2996654916"] = "Das Bild konnte nicht von der URL heruntergeladen werden. Das Bild wird übersprungen."
-- The local image file is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T3219823625"] = "Die lokale Bilddatei ist zu groß (>10 MB). Das Bild wird übersprungen."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T3219823625"] = "Die lokale Bilddatei ist zu groß (>10 MB). Das Bild wird übersprungen."
-- The image at the URL is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T349928509"] = "Das Bild unter der URL ist zu groß (>10 MB). Das Bild wird übersprungen."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T349928509"] = "Das Bild unter der URL ist zu groß (>10 MB). Das Bild wird übersprungen."
-- Export configuration
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ADMINEXPORTBUTTON::T975426229"] = "Konfiguration exportieren"
@@ -5377,16 +5377,16 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T373499115"] = "Your data sources
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T713722424"] = "AI Studio could not store what the AI received separately from your chat. It remains in the chat itself, so you can still read it."
-- The local image file does not exist. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image."
-- Failed to download the image from the URL. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T2996654916"] = "Failed to download the image from the URL. Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T2996654916"] = "Failed to download the image from the URL. Skipping the image."
-- The local image file is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T3219823625"] = "The local image file is too large (>10 MB). Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T3219823625"] = "The local image file is too large (>10 MB). Skipping the image."
-- The image at the URL is too large (>10 MB). Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T349928509"] = "The image at the URL is too large (>10 MB). Skipping the image."
UI_TEXT_CONTENT["AISTUDIO::CHAT::IMAGESOURCEEXTENSIONS::T349928509"] = "The image at the URL is too large (>10 MB). Skipping the image."
-- Export configuration
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::ADMINEXPORTBUTTON::T975426229"] = "Export configuration"
@@ -292,7 +292,7 @@ public static class LLMProvidersExtensions
/// <remarks>
/// The limit belongs to the API of the provider, not to the model: the same model may accept
/// larger images through another provider. What we actually send is asked through
/// IImageSourceExtensions.MaxImageSizeBytesFor, which also applies our own limit.
/// ImageSourceExtensions.MaxImageSizeBytesFor, which also applies our own limit.
/// </remarks>
/// <value>The size limit of one image file, or null when the provider states none we know of.</value>
public long? MaxImageSizeBytes => provider switch
@@ -45,7 +45,7 @@ public static class HostExtensions
/// <remarks>
/// Like the limit of a cloud provider, see LLMProvidersExtensions.MaxImageSizeBytes, this
/// belongs to the API of the engine, not to the model. What we actually send is asked through
/// IImageSourceExtensions.MaxImageSizeBytesFor.
/// ImageSourceExtensions.MaxImageSizeBytesFor.
/// </remarks>
/// <value>The size limit of one image file, or null when the engine states none we know of.</value>
public long? MaxImageSizeBytes => host switch
@@ -1,6 +1,6 @@
namespace AIStudio.Tools;
public static class IConfidenceExtensions
public static class ConfidenceExtensions
{
private static readonly ILogger<IConfidence> LOGGER = Program.LOGGER_FACTORY.CreateLogger<IConfidence>();
@@ -256,7 +256,7 @@ public static class PlainFileExport
/// <param name="dialogTitle">The title of the save dialog.</param>
/// <param name="file">The file, as ExtractFiles read it out of the message. Its format must be a
/// plain text format, see FileExportFormatExtensions.IsPlainText.</param>
/// <param name="fileContent">The finished file, see IContentExtensions.ToExportContent.</param>
/// <param name="fileContent">The finished file, see ContentExtensions.ToExportContent.</param>
/// <param name="fileName">What the file is about, used to suggest a name in the save dialog.
/// Null falls back to a generic name.</param>
/// <returns>True, when the file was written.</returns>
@@ -4,7 +4,7 @@ using SharedTools;
namespace AIStudio.Tools.PluginSystem;
public static class ILangExtensions
public static class LangExtensions
{
private static readonly ILogger<ILang> LOGGER = Program.LOGGER_FACTORY.CreateLogger<ILang>();
@@ -2,7 +2,7 @@ using SharedTools;
namespace AIStudio.Tools.PluginSystem;
public static class ILanguagePluginExtensions
public static class LanguagePluginExtensions
{
/// <param name="plugin">The language plugin.</param>
extension(ILanguagePlugin plugin)
@@ -84,7 +84,7 @@ public sealed class PassageBudget(int limit, Func<string, CancellationToken, Tas
/// </para>
/// <para>
/// A passage longer than the whole budget is shortened until it fits, and filtered again, see
/// IRetrievalContextExtensions.ShortenToFitAsync. It then has to fit into what is left like any
/// RetrievalContextExtensions.ShortenToFitAsync. It then has to fit into what is left like any
/// other passage.
/// </para>
/// </remarks>
@@ -7,7 +7,7 @@ namespace AIStudio.Tools.RAG;
/// ready to be numbered.
/// </summary>
/// <remarks>
/// Made by IRetrievalContextExtensions.PrepareForModelAsync. Which number a context gets depends on
/// Made by RetrievalContextExtensions.PrepareForModelAsync. Which number a context gets depends on
/// which contexts the caller hands on in the end, so the header is written only then, see
/// ToMarkdown. The app writes it itself, which is why it needs no filter.
/// </remarks>
@@ -4,7 +4,7 @@ using AIStudio.Tools.Security;
namespace AIStudio.Tools.RAG;
public static class IRetrievalContextExtensions
public static class RetrievalContextExtensions
{
private static readonly ILogger<IRetrievalContext> LOGGER = Program.LOGGER_FACTORY.CreateLogger<IRetrievalContext>();
@@ -12,7 +12,7 @@ namespace AIStudio.Tools.RAG;
/// so it is not shown as if it had.<br/><br/>
/// A passage belongs to the source it is listed under, which is why it is only made for a context
/// with a source, see SourceUrl. A context which names nothing to open, e.g., by a path which only
/// its ERI server knows, gets a source named as text, see IRetrievalContextExtensions.ToSources.<br/><br/>
/// its ERI server knows, gets a source named as text, see RetrievalContextExtensions.ToSources.<br/><br/>
/// Plain stored values only: a computed property would be written into every chat file as well.
/// </remarks>
public sealed record SourcePassage
@@ -55,7 +55,7 @@ public sealed class ModelImageService(RustService rustService, ILogger<ModelImag
return PreparedModelImage.Failed(ModelImageErrorCode.FILE_NOT_FOUND);
}
var maxBytes = IImageSourceExtensions.MaxImageSizeBytesFor(provider);
var maxBytes = ImageSourceExtensions.MaxImageSizeBytesFor(provider);
var key = new CacheKey(file.FullName, file.LastWriteTimeUtc, file.Length, maxBytes);
if (this.cache.TryGetValue(key, out PreparedModelImage? cached) && cached is not null)
{
@@ -208,7 +208,7 @@ internal sealed record PendingMail(DataSourceMailbox Mailbox, MailSummary Summar
/// <remarks>
/// The attachments are numbered the way the index numbers them, cf. MailSummary.AttachmentNames.
/// Where in an attachment is worded like the location of any other passage, cf.
/// IRetrievalContextExtensions.DescribeLocation. A passage of the text of the mail names
/// RetrievalContextExtensions.DescribeLocation. A passage of the text of the mail names
/// no attachment, and neither does one of a mail indexed before attachments were told apart.
/// </remarks>
/// <param name="texts">The filtered texts of the result.</param>
@@ -220,6 +220,6 @@ internal sealed record PendingMail(DataSourceMailbox Mailbox, MailSummary Summar
var type = DataSourceLocalRetrievalService.GetRetrievalContentType(Path.GetExtension(this.Summary.AttachmentNames[position]));
var located = DataSourceLocalRetrievalService.LocatePassage(location, type, chunkNumber: 1);
return new(texts[attachment], IRetrievalContextExtensions.DescribeLocation(located.PageNumber, located.EndPageNumber, located.SheetName, located.StartRow, located.EndRow, located.StartLine, located.EndLine));
return new(texts[attachment], RetrievalContextExtensions.DescribeLocation(located.PageNumber, located.EndPageNumber, located.SheetName, located.StartRow, located.EndRow, located.StartLine, located.EndLine));
}
}
@@ -70,7 +70,7 @@ public sealed class SemanticSearchTool(SettingsManager settingsManager, DataSour
/// A chunk is as long as the embedding model takes at once, by default 8,192 tokens, so a
/// single passage may already fill tens of thousands of characters. A passage which does not
/// fit starts the next page, see SearchAsync. Only a passage longer than a whole page is
/// shortened, and filtered again, see IRetrievalContextExtensions.ShortenToFitAsync. The limit
/// shortened, and filtered again, see RetrievalContextExtensions.ShortenToFitAsync. The limit
/// is the one a web search has by default, and it leaves room for about three searches within
/// the budget of all tool results of an answer, see ToolSelectionRules.MAX_TOOL_RESULT_CHARACTERS:
/// a question with several aspects gets one search per aspect.
@@ -422,7 +422,7 @@ public sealed class SemanticSearchTool(SettingsManager settingsManager, DataSour
/// </para>
/// <para>
/// A passage longer than a whole page would hold up every passage after it, so it is shortened
/// to fill a page of its own, see IRetrievalContextExtensions.ShortenToFitAsync.
/// to fill a page of its own, see RetrievalContextExtensions.ShortenToFitAsync.
/// </para>
/// </remarks>
/// <param name="request">The search to run.</param>
@@ -62,7 +62,7 @@ public sealed class DirectI18NGetTextAnalyzer : DiagnosticAnalyzer
private static bool IsLangExtensions(INamedTypeSymbol? type)
{
var staticClass = type is { IsExtension: true } ? type.ContainingType : type;
return staticClass?.Name == "ILangExtensions" && staticClass.ContainingNamespace.ToDisplayString() == "AIStudio.Tools.PluginSystem";
return staticClass?.Name == "LangExtensions" &&staticClass.ContainingNamespace.ToDisplayString() == "AIStudio.Tools.PluginSystem";
}
private static bool IsCollectorCompatibleWrapper(IMethodSymbol? containingMethod, IInvocationOperation invocation)
@@ -21,7 +21,7 @@ public sealed class DirectI18NGetTextAnalyzerTests
{
private const string CLASSIC_FORM =
"""
public static class ILangExtensions
public static class LangExtensions
{
public static string GetText(this ILang lang, string fallbackEN) => fallbackEN;
}
@@ -29,7 +29,7 @@ public sealed class DirectI18NGetTextAnalyzerTests
private const string EXTENSION_BLOCK_FORM =
"""
public static class ILangExtensions
public static class LangExtensions
{
extension(ILang lang)
{
@@ -52,11 +52,11 @@ public sealed class DirectI18NGetTextAnalyzerTests
[TestCase(CLASSIC_FORM, """public string Describe() => this.GetText("Hello");""", TestName = "A classic extension method called from another method")]
[TestCase(CLASSIC_FORM, """public string T(string fallbackEN) => this.GetText("Hello");""", TestName = "A classic extension method called by a wrapper with a text of its own")]
[TestCase(CLASSIC_FORM, """public string Describe() => ILangExtensions.GetText(this, "Hello");""", TestName = "A classic extension method called as a static method")]
[TestCase(CLASSIC_FORM, """public string Describe() => LangExtensions.GetText(this, "Hello");""", TestName = "A classic extension method called as a static method")]
[TestCase(EXTENSION_BLOCK_FORM, """public string Describe() => this.GetText("Hello");""", TestName = "The member of an extension block called from another method")]
[TestCase(EXTENSION_BLOCK_FORM, """public string T(string fallbackEN) => this.GetText("Hello");""", TestName = "The member of an extension block called by a wrapper with a text of its own")]
[TestCase(EXTENSION_BLOCK_FORM, """public string TA(string fallbackEN) => this.GetText("Hello");""", TestName = "The member of an extension block called by a TA wrapper with a text of its own")]
[TestCase(EXTENSION_BLOCK_FORM, """public string Describe() => ILangExtensions.GetText(this, "Hello");""", TestName = "The member of an extension block called as a static method")]
[TestCase(EXTENSION_BLOCK_FORM, """public string Describe() => LangExtensions.GetText(this, "Hello");""", TestName = "The member of an extension block called as a static method")]
public async Task ADirectLookupIsRefused(string form, string member)
{
var reported = await AnalyzeAsync(form, member);
@@ -99,7 +99,7 @@ public sealed class DirectI18NGetTextAnalyzerTests
private static async Task<IReadOnlyList<Diagnostic>> AnalyzeAsync(string form, string member)
{
//
// The snippet declares its own ILang and ILangExtensions where the analyzer looks for them. They take
// The snippet declares its own ILang and LangExtensions where the analyzer looks for them. They take
// the place of those of the app, which the compilation references as well.
//
var source =
@@ -75,7 +75,7 @@ public sealed class BflImageMaterialTests
Assert.That(await File.ReadAllBytesAsync(copy), Is.EqualTo(Convert.FromBase64String(FakeImageRuntime.IMAGE_BASE64)));
Assert.That(copy, Does.StartWith(Path.Combine(this.dataDirectory, BeyondFactsLabStore.ROOT_DIRECTORY_NAME)), "The material must not depend on the file of the person.");
Assert.That(this.runtime.RequestedPaths, Is.EqualTo(new[] { poster }));
Assert.That(this.runtime.RequestedBudgets, Is.EqualTo(new[] { IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES }), "The copy must be as large as any provider takes.");
Assert.That(this.runtime.RequestedBudgets, Is.EqualTo(new[] { ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES }), "The copy must be as large as any provider takes.");
}
}
@@ -16,7 +16,7 @@ namespace AIStudio.Tests.Chat;
/// way the one can run into the other -- an open code fence above all. A document has no such seam.
/// </remarks>
[TestFixture]
public sealed class IContentExtensionsTests
public sealed class ContentExtensionsTests
{
private static readonly Source TOOL_SOURCE = new("Search result", "https://example.org/search", SourceOrigin.TOOL);
+6 -6
View File
@@ -20,7 +20,7 @@ public sealed class ImageSizeLimitTests
using (Assert.EnterMultipleScope())
{
Assert.That(LLMProviders.ANTHROPIC.MaxImageSizeBytes, Is.EqualTo(3_932_160));
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.ANTHROPIC)), Is.EqualTo(3_932_160));
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.ANTHROPIC)), Is.EqualTo(3_932_160));
}
}
@@ -30,7 +30,7 @@ public sealed class ImageSizeLimitTests
using (Assert.EnterMultipleScope())
{
Assert.That(LLMProviders.OPEN_AI.MaxImageSizeBytes, Is.Null, "Nobody stated a limit, and no number stands in for that.");
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.OPEN_AI)), Is.EqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES));
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.OPEN_AI)), Is.EqualTo(ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES));
}
}
@@ -40,8 +40,8 @@ public sealed class ImageSizeLimitTests
using (Assert.EnterMultipleScope())
{
Assert.That(Host.LLMMAN.MaxImageSizeBytes, Is.EqualTo(1_048_576));
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.LLMMAN)), Is.EqualTo(1_048_576));
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.OLLAMA)), Is.EqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES), "Ollama states no limit we know of.");
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.LLMMAN)), Is.EqualTo(1_048_576));
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(LLMProviders.SELF_HOSTED, Host.OLLAMA)), Is.EqualTo(ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES), "Ollama states no limit we know of.");
}
}
@@ -52,7 +52,7 @@ public sealed class ImageSizeLimitTests
// to a cloud provider in the dialog:
var cloudProviderWithAnOldHost = ProviderOf(LLMProviders.OPEN_AI, Host.LLMMAN);
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(cloudProviderWithAnOldHost), Is.EqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES));
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(cloudProviderWithAnOldHost), Is.EqualTo(ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES));
}
[Test]
@@ -62,7 +62,7 @@ public sealed class ImageSizeLimitTests
{
foreach (var llmProvider in Enum.GetValues<LLMProviders>())
foreach (var host in Enum.GetValues<Host>())
Assert.That(IImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(llmProvider, host)), Is.LessThanOrEqualTo(IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES), $"{llmProvider} with {host}");
Assert.That(ImageSourceExtensions.MaxImageSizeBytesFor(ProviderOf(llmProvider, host)), Is.LessThanOrEqualTo(ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES), $"{llmProvider} with {host}");
}
}
+1 -1
View File
@@ -77,7 +77,7 @@ public sealed class ModelImageServiceTests
using (Assert.EnterMultipleScope())
{
Assert.That(this.runtime.RequestedBudgets, Is.EqualTo(new[] { 3_932_160, IImageSourceExtensions.MAX_IMAGE_SIZE_BYTES }));
Assert.That(this.runtime.RequestedBudgets, Is.EqualTo(new[] { 3_932_160, ImageSourceExtensions.MAX_IMAGE_SIZE_BYTES }));
Assert.That(this.runtime.RequestedPaths, Is.All.EqualTo(new FileInfo(this.imagePath).FullName));
}
}
@@ -144,8 +144,8 @@ public sealed class RetrievalContextDescriptionTests
};
var builder = new StringBuilder();
IRetrievalContextExtensions.AppendContextDescription(builder, image);
IRetrievalContextExtensions.AppendImageMatch(builder);
RetrievalContextExtensions.AppendContextDescription(builder, image);
RetrievalContextExtensions.AppendImageMatch(builder);
var description = builder.ToString();
using (Assert.EnterMultipleScope())
@@ -161,7 +161,7 @@ public sealed class RetrievalContextDescriptionTests
private static string Describe(IRetrievalContext retrievalContext)
{
var builder = new StringBuilder();
IRetrievalContextExtensions.AppendContextDescription(builder, retrievalContext);
RetrievalContextExtensions.AppendContextDescription(builder, retrievalContext);
return builder.ToString();
}
@@ -120,8 +120,8 @@ public sealed class RetrievalContextPreparationTests
var expected = new StringBuilder();
expected.AppendLine("# Retrieval context");
IRetrievalContextExtensions.AppendContextDescription(expected, image);
IRetrievalContextExtensions.AppendImageMatch(expected);
RetrievalContextExtensions.AppendContextDescription(expected, image);
RetrievalContextExtensions.AppendImageMatch(expected);
expected.AppendLine();
using (Assert.EnterMultipleScope())
@@ -22,37 +22,37 @@ public sealed class RetrievalContextShorteningTests
{
const string TEXT = "first line\nsecond line";
Assert.That(IRetrievalContextExtensions.CutAtLineEnd(TEXT, TEXT.Length), Is.SameAs(TEXT));
Assert.That(RetrievalContextExtensions.CutAtLineEnd(TEXT, TEXT.Length), Is.SameAs(TEXT));
}
[Test]
public void ACutEndsAtTheLastLineEndWhichFits()
{
Assert.That(IRetrievalContextExtensions.CutAtLineEnd("first\nsecond\nthird", 15), Is.EqualTo("first\nsecond"));
Assert.That(RetrievalContextExtensions.CutAtLineEnd("first\nsecond\nthird", 15), Is.EqualTo("first\nsecond"));
}
[Test]
public void ACutKeepsNoHalfOfAWindowsLineEnd()
{
Assert.That(IRetrievalContextExtensions.CutAtLineEnd("first\r\nsecond\r\nthird", 17), Is.EqualTo("first\r\nsecond"));
Assert.That(RetrievalContextExtensions.CutAtLineEnd("first\r\nsecond\r\nthird", 17), Is.EqualTo("first\r\nsecond"));
}
[Test]
public void ACutGivesUpAtMostHalfOfWhatFitsForALineEnd()
{
Assert.That(IRetrievalContextExtensions.CutAtLineEnd("a\nbcdefghijkl", 10), Is.EqualTo("a\nbcdefghi"), "With its only line end right at the start, the text would lose nearly everything.");
Assert.That(RetrievalContextExtensions.CutAtLineEnd("a\nbcdefghijkl", 10), Is.EqualTo("a\nbcdefghi"), "With its only line end right at the start, the text would lose nearly everything.");
}
[Test]
public void ACutNeverSplitsASurrogatePair()
{
Assert.That(IRetrievalContextExtensions.CutAtLineEnd("ab😀cd", 3), Is.EqualTo("ab"));
Assert.That(RetrievalContextExtensions.CutAtLineEnd("ab😀cd", 3), Is.EqualTo("ab"));
}
[Test]
public void NothingIsLeftOfATextWithoutRoom()
{
Assert.That(IRetrievalContextExtensions.CutAtLineEnd("text", 0), Is.Empty);
Assert.That(RetrievalContextExtensions.CutAtLineEnd("text", 0), Is.Empty);
}
[Test]