Registering a provider 

Two mechanisms pick up your provider class. Use the attribute when you can.

Preferred: the #[AsLlmProvider] attribute 

Add the attribute to any provider class that lives under the Netresearch\NrLlm\ namespace. The compiler pass auto-tags the service, sets it public (so backend diagnostics can resolve it by class name), and registers it with LlmServiceManager in priority order:

Classes/Provider/MyProvider.php
use Netresearch\NrLlm\Attribute\AsLlmProvider;
use Netresearch\NrLlm\Provider\AbstractProvider;

#[AsLlmProvider(priority: 85)]
final class MyProvider extends AbstractProvider
{
    public function getIdentifier(): string
    {
        return 'my-provider';
    }

    public function getName(): string
    {
        return 'My LLM Service';
    }

    // ... chatCompletion(), embeddings(), supportsFeature()
}
Copied!

Priority is an ordering hint only. Providers are still resolved by their getIdentifier() at runtime. Higher priority wins when two providers otherwise tie.

Third-party fallback: yaml tagging 

Extensions that sit outside the Netresearch\NrLlm\ namespace still work via the original mechanism — declare a service with the nr_llm.provider tag:

EXT:my_ext/Configuration/Services.yaml
services:
  Acme\MyExt\Provider\AcmeProvider:
    public: true
    tags:
      - name: nr_llm.provider
        priority: 85
Copied!

When both yaml tagging AND the attribute are present on the same service, the yaml wins (the attribute pass skips already-tagged services). Treat this as an override hook rather than an additive mechanism.

Capability interfaces 

Priority governs registration order only; it says nothing about what a provider can do. Capabilities are advertised by implementing the relevant interface from NetresearchNrLlmProviderContract:

  • VisionCapableInterface — image analysis
  • StreamingCapableInterface — SSE streaming
  • ToolCapableInterface — function / tool calling
  • DocumentCapableInterface — PDF / structured document input

LlmServiceManager dispatches to a provider only when the caller's requested operation matches a capability the provider actually advertises. A provider that doesn't implement VisionCapableInterface can never be asked to describe an image, regardless of priority. See ADR-022: Attribute-Based Provider Registration for the attribute-discovery design decision and the Symfony registerAttributeForAutoconfiguration alternative we evaluated.