← All source files

V18 / 8d896b8a86e5

ContextBoundFactory.cs

Interfaces/Gui/LilithGui.Worker/ContextBoundFactory.cs

Changed in this version
CS
using System.Reflection;

namespace Lilith.Gui.Worker;

// Optional host-side runtime tuning, without changing any pinned release source.
internal sealed class ContextBoundFactory(object agent, MethodInfo create, int maximum)
{
    internal static void Configure(Assembly assembly, object agent, int maximum)
    {
        if (maximum is < 2048 or > 131072) throw new ArgumentOutOfRangeException(nameof(maximum));
        var property = agent.GetType().GetProperty("ProviderFactory", BindingFlags.Instance | BindingFlags.NonPublic)
            ?? throw new NotSupportedException("This release cannot configure its runtime context.");
        var create = assembly.GetType("Lilith.Agent.LilithExtensions")?.GetMethod("CreateClient", BindingFlags.Public | BindingFlags.Static)
            ?? throw new NotSupportedException("This release has no provider factory.");
        var provider = property.PropertyType.GenericTypeArguments[1].GenericTypeArguments[0];
        var factory = new ContextBoundFactory(agent, create, maximum);
        property.SetValue(agent, typeof(ContextBoundFactory).GetMethod(nameof(Create))!.MakeGenericMethod(provider).CreateDelegate(property.PropertyType, factory));
    }

    public async Task<T> Create<T>(bool startServerIfNotRunning)
    {
        var client = await (Task<T>)create.Invoke(null, [agent, startServerIfNotRunning])!;
        for (var type = client!.GetType(); type is not null; type = type.BaseType)
        {
            var context = type.GetProperty("NumCtx", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
            if (context is null) continue;
            context.SetValue(client, Math.Min((int)context.GetValue(client)!, maximum));
            return client;
        }
        throw new NotSupportedException("This release cannot bound its model context.");
    }
}