Class AbstractAiProvider

java.lang.Object
uno.anahata.asi.agi.event.BasicPropertyChangeSource
uno.anahata.asi.agi.provider.AbstractAiProvider
All Implemented Interfaces:
PropertyChangeSource, Rebindable
Direct Known Subclasses:
AnthropicProvider, GeminiAiProvider, OpenAiChatCompletionsProvider, OpenAiResponsesProvider

public abstract class AbstractAiProvider extends BasicPropertyChangeSource
The abstract base class for all AI model providers, now with model caching. Its primary responsibilities are to discover available models and manage API keys.
Author:
anahata
  • Field Details

    • priority

      private int priority
      The sorting priority for this provider. Lower values indicate higher priority (pinned to top).
    • asiContainer

      private transient AbstractAsiContainer asiContainer
      A transient reference to the parent container. This allows providers to access shared resources like the executor service.
    • uuid

      private String uuid
      The unique UUID for this specific provider instance. Crucial for distinguishing between multiple instances of the same provider class (e.g., two different Ollama endpoints).
    • baseUrl

      private String baseUrl
      The base URL of the provider's API endpoint.

      This allows the provider to target official cloud services or alternative backends like local proxies, Ollama, or specialized vendor endpoints.

    • apiKeysFile

      private String apiKeysFile
      An optional custom file path for this provider's API keys file. If null or empty, defaults to ~/.anahata/asi/<uuid>_api_keys.txt.
    • displayName

      private String displayName
      The user-facing display name for this instance (e.g., 'Groq Cloud').
    • description

      private String description
      The user-facing description of this instance.
    • keysAcquisitionUri

      private String keysAcquisitionUri
      The URI where users can acquire API keys for this provider.
    • tokenizerType

      private TokenizerType tokenizerType
      The type of tokenizer used by this provider. This determines how accurately the Context Window Garbage Collector can estimate the token count before making an API call.
    • apiKeyRequired

      private boolean apiKeyRequired
      Whether this provider requires an API key to function. If false, the ASI will allow requests even if the key pool is empty (e.g. local Ollama).
    • enabled

      private boolean enabled
      Whether this provider is enabled and should be offered to the user.
    • automaticallyRegisterNewlyDiscoveredModels

      private boolean automaticallyRegisterNewlyDiscoveredModels
      Whether to automatically register and persist newly discovered models when API discovery runs.
    • currentKey

      private transient String currentKey
      The API key currently in use by this provider. Captured during key rotation.
    • keyPool

      private volatile List<String> keyPool
      The internal cache of loaded API keys, reloaded from disk on change.
    • round

      private final AtomicInteger round
      Atomic counter for round-robin key selection.
    • keyPoolLastModified

      private transient long keyPoolLastModified
      The last-modified timestamp of the API keys file when it was last loaded from disk.
    • models

      private transient List<AbstractModel> models
      The master list of persistent model entities for this provider (loaded from disk .kryo files).
    • cachedApiModels

      private transient List<AbstractModel> cachedApiModels
      The transient list of models returned directly by the provider's API for diffing and alerting.
    • MARKUP_TABLE_HEADER

      public static final String MARKUP_TABLE_HEADER
      Markdown table header for provider listings.
      See Also:
  • Constructor Details

    • AbstractAiProvider

      public AbstractAiProvider()
      No-arg constructor required for Kryo serialization and dynamic instantiation.
    • AbstractAiProvider

      public AbstractAiProvider(String uuid)
      Constructs a new provider instance with a specific UUID.
      Parameters:
      uuid - The unique ID for this instance.
  • Method Details

    • initialize

      public void initialize() throws Exception
      Initializes this provider after instantiation and container binding. Subclasses can override to perform custom setup before or after calling super.initialize().
      Throws:
      Exception - if provider initialization fails.
    • persist

      public void persist() throws IOException
      Persists this AI provider entity directly to disk in the container's providers directory (~/.anahata/asi/<hostApp>/<version>/providers/<uuid>.kryo).
      Throws:
      IOException - If creating the directory or saving the file fails.
      IllegalStateException - If the parent container is null or uuid is null or blank.
    • remove

      public void remove() throws IOException
      Deletes the persisted .kryo file for this AI provider from disk and removes it from its parent container registry.
      Throws:
      IOException - If deleting the file fails.
      IllegalStateException - If the parent container is null or uuid is null or blank.
    • getModelsDirectory

      public Path getModelsDirectory() throws IOException
      Resolves the path to the models directory for this provider.
      Returns:
      The path to the models storage directory.
      Throws:
      IOException - If creating the directory fails.
    • getUnloadableModelsDirectory

      public Path getUnloadableModelsDirectory() throws IOException
      Gets the directory where model entities that failed to load are quarantined.
      Returns:
      The unloadable models directory path.
      Throws:
      IOException - If creating the directory fails.
    • loadModelsFromDisk

      public List<AbstractModel> loadModelsFromDisk() throws IOException
      Loads all persisted models from this provider's models directory on disk into memory.

      Implements resilient per-model deserialization: if a model cache file is corrupt or in an incompatible legacy format, it is quarantined to the models/unloadable/ directory and a notification is recorded in the parent container without failing the provider initialization.

      Returns:
      The list of models loaded from disk and bound to this provider.
      Throws:
      IOException - if reading the models directory fails.
    • addModel

      public void addModel(AbstractModel model) throws IOException
      Adds a new model to this provider's local models list and persists it to disk.
      Parameters:
      model - The model to add and persist.
      Throws:
      IOException - if and error occurs persisting it.
      IllegalArgumentException - if model is null or already exists in this provider.
    • addModels

      public void addModels(List<AbstractModel> modelsToAdd) throws IOException
      Adds multiple models to this provider's local models list, persists each to disk, and fires a single unified property change event for "models".
      Parameters:
      modelsToAdd - The collection of models to add and persist.
      Throws:
      IOException - If saving any model to disk fails.
      IllegalArgumentException - If the list is null or contains a null or duplicate model.
    • removeModel

      public void removeModel(AbstractModel model)
      Removes a model from this provider's in-memory list.
      Parameters:
      model - The model to remove.
      Throws:
      IllegalArgumentException - if model is null.
    • listModels

      public abstract List<? extends AbstractModel> listModels() throws Exception
      Fetches the list of all models available from the provider's remote API.
      Returns:
      A list of provider-specific AbstractModel objects.
      Throws:
      Exception - if network communication, authentication, or parsing fails.
    • getProviderId

      public String getProviderId()
      Compatibility alias for getUuid() to maintain integration with existing IDE and UI components that expect a provider ID.
      Returns:
      The unique UUID of this provider instance.
    • getModels

      public List<AbstractModel> getModels()
      Gets the master list of model entities for this provider (loaded from disk .kryo files).
      Returns:
      The master list of models.
    • getEnabledModels

      public List<AbstractModel> getEnabledModels()
      Gets the list of models that are currently enabled for this provider.
      Returns:
      The list of enabled models.
    • getModel

      public Optional<AbstractModel> getModel(String modelId)
      Finds a single model by its unique ID within this provider.
      Parameters:
      modelId - The ID of the model to find.
      Returns:
      An Optional containing the model if found, otherwise empty.
    • findModels

      public List<AbstractModel> findModels(String query, List<ResponseModality> modalities)
      Finds and filters models within this provider matching a regex/text query AND all requested response modalities.
      Parameters:
      query - Optional regex or text query to match against model ID, display name, description, supported actions, or modalities.
      modalities - Optional list of target response modalities (e.g. [IMAGE, AUDIO]). The model must support all listed modalities.
      Returns:
      A list of matching models.
    • refreshCachedApiModels

      public List<AbstractModel> refreshCachedApiModels() throws Exception
      Queries the provider's remote API to discover models and updates cachedApiModels. Binds each model to this provider before updating the cache.
      Returns:
      The list of models discovered directly from the API.
      Throws:
      Exception - if remote API communication or model discovery fails.
    • testConnection

      public String testConnection() throws Exception
      Tests connectivity to the provider's remote API endpoint and returns a human-readable status summary.

      The default implementation executes refreshCachedApiModels() and formats a summary of discovered models. Subclasses (like Ollama) can override this to return rich diagnostic details such as server versions and live running models.

      Returns:
      A descriptive connection confirmation message.
      Throws:
      Exception - if remote connectivity or authentication fails.
    • getCachedApiModel

      public AbstractModel getCachedApiModel(String modelId)
      Finds a cached API model by its unique ID.
      Parameters:
      modelId - The ID of the model to look up in cached API models.
      Returns:
      The cached API model, or null if not found.
    • getAllDisplayModels

      public List<AbstractModel> getAllDisplayModels()
      Gets the combined list of local persisted models and any newly discovered API models that are not yet persisted.
      Returns:
      A list containing all local models followed by unregistered API models.
    • getAllSupportedActions

      public Set<String> getAllSupportedActions()
      Gets a set of all unique supported actions across all models offered by this provider, using the cached model list.
      Returns:
      A set of unique action strings.
    • getKeysAcquisitionUri

      public URI getKeysAcquisitionUri()
      Gets the URI where users can acquire API keys for this provider.
      Returns:
      The acquisition URI, or null if not set.
    • getApiKeyHint

      public abstract String getApiKeyHint()
      Gets a template or hint string to display when the API keys file is empty.
      Returns:
      The API key hint text.
    • hasKeys

      public boolean hasKeys()
      Checks if there are any valid API keys configured for this provider.
      Returns:
      true if at least one key exists.
    • getKeyPoolSize

      public int getKeyPoolSize()
      Returns the total number of configured API keys for this provider.
      Returns:
      The count of valid API keys in the key pool.
    • isEffectivelyEnabled

      public boolean isEffectivelyEnabled()
      Checks if this provider is effectively enabled and ready for active model requests.

      A provider is effectively enabled if isEnabled() is true AND either it does not require an API key (e.g. local Ollama) or at least one valid API key is configured.

      Returns:
      true if enabled and properly keyed for requests.
    • toMarkupRow

      public String toMarkupRow(boolean includeModelIds)
      Formats this provider as a Markdown table row for provider listing tools.
      Parameters:
      includeModelIds - Whether to include the full comma-separated list of model IDs (true) or just the total count (false).
      Returns:
      A Markdown row representing this provider.
    • toMarkupRow

      public String toMarkupRow()
      Formats this provider as a Markdown table row, defaulting to showing the total count of models.
      Returns:
      A Markdown row representing this provider.
    • reloadKeyPoolIfNeeded

      public void reloadKeyPoolIfNeeded()
      Checks if the API keys configuration file on disk has been modified since it was last loaded. If modified, reloads the key pool from disk.
    • reloadKeyPool

      public void reloadKeyPool() throws IOException
      Reloads the API key pool from the provider's configuration file and triggers an initial key selection.
      Throws:
      IOException - If reading the key file fails.
    • getCurrentKey

      public String getCurrentKey()
      Returns the API key currently in use by this provider instance, reloading from disk if the file was modified externally.
      Returns:
      The active API key, or null if the pool is empty.
    • hokusPocus

      public void hokusPocus()
      Rotates the active key to the next available API key in the pool. Subclasses override to invalidate native API clients.
    • getProviderDirectory

      public Path getProviderDirectory() throws IOException
      Resolves the absolute path to the provider's storage directory in the active container.
      Returns:
      The path to the provider's configuration and log directory.
      Throws:
      IOException - If creating the directory fails.
    • getKeysFilePath

      public Path getKeysFilePath()
      Resolves the path to the API keys configuration file for this provider. Defaults to ~/.anahata/asi/<uuid>_api_keys.txt if apiKeysFile is not specified.
      Returns:
      The path to the API keys configuration file.
    • ensureKeysFileExists

      public void ensureKeysFileExists() throws IOException
      Ensures that the API keys file exists on the host filesystem, creating * parent directories and the file if missing.
      Throws:
      IOException
    • readApiKeysFile

      private List<String> readApiKeysFile() throws IOException
      Reads and parses the active API keys from the configuration file on disk, recording its last-modified timestamp.
      Returns:
      A list of cleaned, non-empty, non-comment API key strings read from the file.
      Throws:
      IOException - If reading the file fails.