mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-12 20:53:48 +00:00
Rebuilt how AI Studio knows what a model can do (#960)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
1 parent
d21e09dd1e
commit
d85b4e71b6
287 files changed
+18341
-3677
No files matched your search
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Frozen;
|
||||
|
||||
namespace AIStudio.Models.Live;
|
||||
|
||||
/// <summary>
|
||||
/// What the configured providers last said about the models they serve.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// One snapshot per configured provider instance, and reporting replaces the snapshot rather than
|
||||
/// adding to it. That is the same reason the registry replaces what the plugins declare: a model an
|
||||
/// installation no longer serves has to stop answering, and a window somebody halved by restarting
|
||||
/// their engine must not go on being reported alongside its correction.
|
||||
///
|
||||
/// Nothing here is written to disk. These are statements about a machine as it is running right
|
||||
/// now, and the app asks that machine again before every chat round anyway. An instance somebody
|
||||
/// deleted keeps its snapshot until the app is closed -- a few dozen kilobytes at the very worst,
|
||||
/// which is not worth a second mechanism to watch the settings for.
|
||||
/// </remarks>
|
||||
public sealed class ListedModels
|
||||
{
|
||||
/// <summary>
|
||||
/// The one the app reports into and asks.
|
||||
/// </summary>
|
||||
public static ListedModels Shared { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Per configured provider instance, what its model list said about each model.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Both keys ignore case. The IDs come back from the same list they were stored under, so
|
||||
/// ordinal would do -- but a model an organization wrote into a configuration plugin by hand
|
||||
/// was typed by a person, and the availability check already treats such a name as the same
|
||||
/// model regardless of case. Being stricter here would leave exactly those people without the
|
||||
/// numbers.
|
||||
/// </remarks>
|
||||
private readonly ConcurrentDictionary<string, FrozenDictionary<string, ModelListing>> byProvider = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Takes over what one provider instance said about its models, replacing what it said before.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only ever call this with a whole list in hand. Reporting a filtered part of one would tell
|
||||
/// this instance that everything left out has stopped existing.
|
||||
/// </remarks>
|
||||
/// <param name="configuredProviderId">The instance that was asked. Nothing happens without one.</param>
|
||||
/// <param name="listings">What its list stated, with the models it stated nothing about left in or out as convenient.</param>
|
||||
public void Report(string configuredProviderId, IEnumerable<ModelListing> listings)
|
||||
{
|
||||
//
|
||||
// A provider instance nobody has configured yet is not a machine we could ask again later,
|
||||
// so there is nothing to remember it by. The provider dialog is not such a case: it works
|
||||
// on a fully built instance from the moment it opens, ID included.
|
||||
//
|
||||
if (string.IsNullOrWhiteSpace(configuredProviderId))
|
||||
return;
|
||||
|
||||
var stated = new Dictionary<string, ModelListing>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var listing in listings)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(listing.ModelId) || !listing.IsKnown)
|
||||
continue;
|
||||
|
||||
stated[listing.ModelId] = listing;
|
||||
}
|
||||
|
||||
this.byProvider[configuredProviderId] = stated.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What one provider instance said about one of its models.
|
||||
/// </summary>
|
||||
/// <param name="configuredProviderId">The instance serving the model.</param>
|
||||
/// <param name="modelId">The model, named the way that instance names it.</param>
|
||||
/// <returns>What it stated, which is nothing when it was never asked or said nothing.</returns>
|
||||
public ModelListing Of(string configuredProviderId, string modelId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(configuredProviderId) || string.IsNullOrWhiteSpace(modelId))
|
||||
return ModelListing.NOTHING;
|
||||
|
||||
if (!this.byProvider.TryGetValue(configuredProviderId, out var stated))
|
||||
return ModelListing.NOTHING;
|
||||
|
||||
return stated.TryGetValue(modelId, out var listing) ? listing : ModelListing.NOTHING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
namespace AIStudio.Models.Live;
|
||||
|
||||
/// <summary>
|
||||
/// What a provider's own model list says about one of the models it serves.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// That list is fetched anyway: before every chat round, before every assistant run, and whenever
|
||||
/// somebody opens the provider dialog. Reading what it already carries therefore costs no request
|
||||
/// of its own, which is the whole reason these numbers are taken from here and not asked for.
|
||||
///
|
||||
/// This describes one installation, never the model as such. Two machines may serve the same
|
||||
/// weights behind different settings, and a statement about one of them says nothing about the
|
||||
/// other -- which is why a listing is kept per configured provider instance and is gone with the
|
||||
/// process. It is also the only source for a self-hosted model: a rule can say what the weights
|
||||
/// were trained for, but only the engine knows what its operator started it with.
|
||||
/// </remarks>
|
||||
/// <param name="ModelId">The model, named the way the provider names it in its list.</param>
|
||||
/// <param name="Context">The window the provider states for it, or unknown where it states none.</param>
|
||||
public readonly record struct ModelListing(string ModelId, ContextWindow Context)
|
||||
{
|
||||
/// <summary>
|
||||
/// What we have about a model nobody has reported anything about.
|
||||
/// </summary>
|
||||
public static readonly ModelListing NOTHING = new(string.Empty, ContextWindow.UNKNOWN);
|
||||
|
||||
/// <summary>
|
||||
/// Whether this listing states anything at all.
|
||||
/// </summary>
|
||||
public bool IsKnown => this.Context.IsKnown;
|
||||
|
||||
/// <summary>
|
||||
/// What a provider stated about one model, as every model list states it: a name and a number.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A window of zero or less is dropped rather than repaired, and so is a nameless entry. A
|
||||
/// provider answering that way is saying something we cannot interpret, and falling back to
|
||||
/// what the rules say about the model is the one answer nobody has to invent. Every dialect
|
||||
/// comes through here, so that none of them has to decide that on its own.
|
||||
/// </remarks>
|
||||
/// <param name="modelId">The model, named the way the provider names it.</param>
|
||||
/// <param name="contextWindowTokens">The window the provider stated, where it stated one.</param>
|
||||
/// <returns>The listing, or nothing when there is nothing usable to keep.</returns>
|
||||
public static ModelListing For(string modelId, int? contextWindowTokens) => string.IsNullOrWhiteSpace(modelId) || contextWindowTokens is not > 0
|
||||
? NOTHING
|
||||
: new(modelId, ContextWindow.Of(contextWindowTokens.Value));
|
||||
|
||||
/// <summary>
|
||||
/// Puts what the provider stated over what the rules worked out.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A stated window replaces the whole window, the ceiling included, for the same reason the
|
||||
/// expert settings do: what a model card says it could be raised to is a statement about the
|
||||
/// model, while this is a statement about the installation serving it. Whoever started that
|
||||
/// engine has already decided, and a ceiling nobody can reach without restarting it is not a
|
||||
/// number to keep showing.
|
||||
/// </remarks>
|
||||
/// <param name="profile">What is known about the model without this listing.</param>
|
||||
/// <returns>The profile, with what the provider stated in it.</returns>
|
||||
public ModelProfile ApplyTo(in ModelProfile profile) => this.IsKnown ? profile with { Context = this.Context } : profile;
|
||||
}
|
||||
Reference in new issue
Block a user