ProviderRegistry

org.llm4s.llmconnect.spi.ProviderRegistry
See theProviderRegistry companion class

Attributes

Companion
class
Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Value members

Concrete methods

def discover(loader: ClassLoader): ProviderRegistry

Every provider on loader's classpath, found through META-INF/services.

Every provider on loader's classpath, found through META-INF/services.

A provider module declares itself in META-INF/services/org.llm4s.llmconnect.spi.Llm4sProviderModule, so adding a provider is adding a dependency — no registration code at the call site.

'''This never throws, and one broken jar cannot take out the others.''' ServiceLoader's own iterator throws ServiceConfigurationError for a service entry it cannot load, and the for-comprehension over it that you would naturally write propagates the first such error and abandons every remaining provider. The loop below drives the iterator by hand and wraps each step in guarded, recording the failure in ProviderRegistryReport instead.

Value parameters

loader

the class loader to scan; defaults to the thread's context class loader, falling back to this class's own loader when a context loader is not set.

Attributes

def of(descriptors: ProviderDescriptor*): ProviderRegistry

A registry holding exactly descriptors; a later duplicate id wins.

A registry holding exactly descriptors; a later duplicate id wins.

Attributes

A registry holding exactly descriptors; a later duplicate id wins.

A registry holding exactly descriptors; a later duplicate id wins.

Attributes

A registry holding everything modules supply, of either kind.

A registry holding everything modules supply, of either kind.

Attributes

Concrete fields

The registry used when a caller supplies none: everything discovered on the classpath, computed once.

The registry used when a caller supplies none: everything discovered on the classpath, computed once.

Discovery runs on first use rather than at class-load time, so an application that always passes its own registry never pays for it.

Discovery itself is I/O - a ServiceLoader scan of the classpath - so this lazy val is a cached Action wearing the shape of Data: it reads the classpath once per JVM and every later call sees that first answer, even if the classpath could no longer produce it (a test that manipulates the classpath after default has already run, say). That is the right choice for a running application, where the classpath is fixed for the life of the process. A caller that instead needs a fresh scan, or a deterministic registry that does not depend on classpath order or on whichever other test touched default first, should build one explicitly with ProviderRegistry.of or ProviderRegistry.ofModules rather than rely on this value.

Attributes

Givens

Givens

Resolves to default wherever a using ProviderRegistry is needed. Being ambient does not change what default is: any code that picks this up implicitly still gets the same cached, first-scan-wins registry, with the same tradeoff described above.

Resolves to default wherever a using ProviderRegistry is needed. Being ambient does not change what default is: any code that picks this up implicitly still gets the same cached, first-scan-wins registry, with the same tradeoff described above.

Attributes