using AIStudio.Models.Matching;
using AIStudio.Provider;
namespace AIStudio.Models.Hosting;
///
/// The ordinary host: it serves models under the names they are known by, through the ordinary API.
///
///
/// Most hosts differ from each other in one sentence, and this is what carries the rest. A host
/// which wraps its names says how to unwrap one; a host which speaks an API the others do not says
/// so; everything else is stated here once.
///
/// What a source means for a host: the page names where the behaviour is documented, so that a
/// person can re-check it in a minute. The statements themselves were read off the app's own
/// provider implementations and the model corpus, both of which are in this repository -- the
/// pages are where somebody looks when they doubt them.
///
public abstract class ModelHost : IModelHost
{
///
/// The two capabilities which say through which API a model is reached.
///
private const Capability THE_APIS = Capability.CHAT_COMPLETION_API | Capability.RESPONSES_API;
///
public abstract LLMProviders Provider { get; }
///
public abstract ModelSource Source { get; }
///
///
/// Nothing is wrapped here: this host serves models under the names they are known by.
///
public virtual bool TryUnwrap(in ModelId id, out ModelId inner, out ModelVendor? declaredVendor)
{
inner = id;
declaredVendor = null;
return false;
}
///
///
/// The Responses API is OpenAI's own, and the app speaks it in exactly one place, its OpenAI
/// provider. Wherever else a model is reached, it is reached through the ordinary chat
/// completion API -- whatever the model itself could do at its vendor.
///
public virtual ModelProfile ApplyTransport(in ModelProfile profile) => ThroughTheOrdinaryApi(profile);
///
/// Puts a profile on the ordinary chat completion API.
///
///
/// A profile which says nothing about APIs is left alone. An embedding model is reached through
/// neither of the two, and answering that it speaks the chat completion API would be a claim
/// nobody made.
///
/// What the model can do.
/// What it can do when reached through the ordinary API.
public static ModelProfile ThroughTheOrdinaryApi(in ModelProfile profile)
{
if (!profile.HasAny(THE_APIS))
return profile;
return profile with { Capabilities = (profile.Capabilities & ~Capability.RESPONSES_API) | Capability.CHAT_COMPLETION_API };
}
}