From 1d7a535b4d55a9b642dae09aa749f1569db5ece6 Mon Sep 17 00:00:00 2001 From: Otavio Rodolfo Piske Date: Fri, 28 Nov 2025 14:59:34 -0300 Subject: [PATCH] Move core java code from Wanaku to the Capabilities SDK This supports fixing issue wanaku-ai/wanaku#673 --- .github/workflows/early-access.yml | 37 ++ .github/workflows/main-build.yml | 16 +- .github/workflows/pr-builds.yml | 15 +- .github/workflows/trigger-early-access.yml | 22 ++ capabilities-api/pom.xml | 22 ++ .../sdk/api/discovery/DiscoveryCallback.java | 73 ++++ .../api/discovery/RegistrationManager.java | 55 +++ .../ConfigurationNotFoundException.java | 64 ++++ .../DataStoreResourceNotFoundException.java | 68 ++++ .../EntityAlreadyExistsException.java | 71 ++++ .../InvalidResponseTypeException.java | 71 ++++ .../NamespaceNotFoundException.java | 67 ++++ .../NonConvertableResponseException.java | 71 ++++ .../exceptions/PromptNotFoundException.java | 15 + .../exceptions/ResourceNotFoundException.java | 68 ++++ .../exceptions/ServiceNotFoundException.java | 68 ++++ .../ServiceUnavailableException.java | 79 +++++ .../api/exceptions/ToolNotFoundException.java | 67 ++++ .../sdk/api/exceptions/WanakuException.java | 59 ++++ .../sdk/api/types/AudioContent.java | 71 ++++ .../sdk/api/types/CallableReference.java | 63 ++++ .../capabilities/sdk/api/types/DataStore.java | 182 ++++++++++ .../sdk/api/types/EmbeddedResource.java | 54 +++ .../sdk/api/types/ForwardReference.java | 109 ++++++ .../sdk/api/types/ImageContent.java | 71 ++++ .../sdk/api/types/InputSchema.java | 91 +++++ .../sdk/api/types/LabelsAwareEntity.java | 114 ++++++ .../sdk/api/types/NameNamespacePair.java | 13 + .../capabilities/sdk/api/types/Namespace.java | 73 ++++ .../sdk/api/types/PromptContent.java | 27 ++ .../sdk/api/types/PromptMessage.java | 70 ++++ .../sdk/api/types/PromptReference.java | 217 ++++++++++++ .../capabilities/sdk/api/types/Property.java | 124 +++++++ .../sdk/api/types/RemoteToolReference.java | 185 ++++++++++ .../sdk/api/types/ResourceReference.java | 325 ++++++++++++++++++ .../sdk/api/types/TextContent.java | 54 +++ .../sdk/api/types/ToolReference.java | 229 ++++++++++++ .../sdk/api/types/WanakuEntity.java | 27 ++ .../sdk/api/types/WanakuError.java | 26 ++ .../sdk/api/types/WanakuResponse.java | 36 ++ .../api/types/discovery/ActivityRecord.java | 129 +++++++ .../sdk/api/types/discovery/ServiceState.java | 98 ++++++ .../api/types/discovery/StandardMessages.java | 28 ++ .../sdk/api/types/discovery/package-info.java | 18 + .../sdk/api/types/io/PromptPayload.java | 39 +++ .../api/types/io/ProvisionAwarePayload.java | 49 +++ .../sdk/api/types/io/ResourcePayload.java | 80 +++++ .../sdk/api/types/io/ToolPayload.java | 80 +++++ .../sdk/api/types/io/package-info.java | 18 + .../sdk/api/types/management/ServerInfo.java | 33 ++ .../sdk/api/types/package-info.java | 22 ++ .../api/types/providers/ServiceTarget.java | 136 ++++++++ .../sdk/api/types/providers/ServiceType.java | 68 ++++ .../src/main/resources/META-INF/beans.xml | 0 capabilities-bom/pom.xml | 15 + capabilities-common/pom.xml | 7 +- .../common/exceptions/WanakuWebException.java | 2 +- .../capabilities-config-provider-api/pom.xml | 21 ++ .../provider/api/ConfigProvisioner.java | 44 +++ .../config/provider/api/ConfigResource.java | 68 ++++ .../sdk/config/provider/api/ConfigStore.java | 39 +++ .../provider/api/ConfigWriteException.java | 30 ++ .../sdk/config/provider/api/ConfigWriter.java | 29 ++ .../api/DefaultConfigProvisioner.java | 39 +++ .../provider/api/DefaultConfigResource.java | 54 +++ .../config/provider/api/NoopConfigStore.java | 27 ++ .../config/provider/api/NoopSecretStore.java | 13 + .../provider/api/PropertyBasedStore.java | 50 +++ .../config/provider/api/PropertyProvider.java | 19 + .../provider/api/ProvisionedConfig.java | 19 + .../provider/api/ProvisioningException.java | 31 ++ .../config/provider/api/ReservedConfigs.java | 19 + .../sdk/config/provider/api/SecretStore.java | 6 + .../sdk/config/provider/api/SecretWriter.java | 15 + .../capabilities-config-provider-file/pom.xml | 33 ++ .../config/provider/file/ConfigFileStore.java | 19 + .../provider/file/EncryptionHelper.java | 82 +++++ .../file/FileConfigurationWriter.java | 35 ++ .../provider/file/FileSecretWriter.java | 52 +++ .../sdk/config/provider/file/FileStore.java | 23 ++ .../provider/file/PropertyFileProvider.java | 49 +++ .../config/provider/file/SecretFileStore.java | 60 ++++ .../src/main/resources/application.properties | 0 .../provider/file/EncryptionHelperTest.java | 103 ++++++ capabilities-config-providers/pom.xml | 20 ++ capabilities-data-files/pom.xml | 8 + .../sdk/data/files/FileHeader.java | 2 +- .../sdk/data/files/InstanceDataManager.java | 27 +- .../sdk/data/files/InstanceDataReader.java | 2 +- .../sdk/data/files/FileHeaderTest.java | 2 +- .../data/files/InstanceDataManagerTest.java | 4 +- capabilities-discovery/pom.xml | 6 + .../sdk/discovery/DiscoveryLogCallback.java | 6 +- .../discovery/DiscoveryServiceHttpClient.java | 6 +- .../discovery/ZeroDepRegistrationManager.java | 12 +- .../sdk/discovery/util/DiscoveryHelper.java | 2 +- capabilities-exchange/pom.xml | 45 +-- .../sdk/util/ProvisioningHelper.java | 4 +- capabilities-parent/pom.xml | 49 ++- capabilities-runtime/pom.xml | 5 + .../provisioners/FileProvisionerLoader.java | 12 +- .../exceptions/ServiceAuthException.java | 2 +- .../sdk/services/ServicesHttpClient.java | 18 +- pom.xml | 2 + 104 files changed, 5080 insertions(+), 124 deletions(-) create mode 100644 .github/workflows/early-access.yml create mode 100644 .github/workflows/trigger-early-access.yml create mode 100644 capabilities-api/pom.xml create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/DiscoveryCallback.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/RegistrationManager.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ConfigurationNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/DataStoreResourceNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/EntityAlreadyExistsException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/InvalidResponseTypeException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NamespaceNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NonConvertableResponseException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/PromptNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ResourceNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceUnavailableException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ToolNotFoundException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/WanakuException.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/AudioContent.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/CallableReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/DataStore.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/EmbeddedResource.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ForwardReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ImageContent.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/InputSchema.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/LabelsAwareEntity.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/NameNamespacePair.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Namespace.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptContent.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptMessage.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Property.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/RemoteToolReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ResourceReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/TextContent.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ToolReference.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuEntity.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuError.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuResponse.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ActivityRecord.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ServiceState.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/StandardMessages.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/package-info.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/PromptPayload.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ProvisionAwarePayload.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ResourcePayload.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ToolPayload.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/package-info.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/management/ServerInfo.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/package-info.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceTarget.java create mode 100644 capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceType.java create mode 100644 capabilities-api/src/main/resources/META-INF/beans.xml create mode 100644 capabilities-config-providers/capabilities-config-provider-api/pom.xml create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigProvisioner.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigResource.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriteException.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriter.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigProvisioner.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigResource.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopConfigStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopSecretStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyBasedStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyProvider.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisionedConfig.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisioningException.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ReservedConfigs.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretWriter.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/pom.xml create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/ConfigFileStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelper.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileConfigurationWriter.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileSecretWriter.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/PropertyFileProvider.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/SecretFileStore.java create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/main/resources/application.properties create mode 100644 capabilities-config-providers/capabilities-config-provider-file/src/test/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelperTest.java create mode 100644 capabilities-config-providers/pom.xml diff --git a/.github/workflows/early-access.yml b/.github/workflows/early-access.yml new file mode 100644 index 0000000..f57adef --- /dev/null +++ b/.github/workflows/early-access.yml @@ -0,0 +1,37 @@ +name: early-access + +on: + workflow_dispatch: + workflow_call: + +jobs: + publish-snapshot: + name: Publish Snapshot + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'zulu' + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN + gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + cache: maven + + - name: Publish snapshot to Maven Central + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: | + export GPG_TTY=$(tty) + mvn -Pdist -B --file pom.xml deploy diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index b3291f8..75e9146 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -19,26 +19,16 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Checkout Wanaku Main project - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: - repository: wanaku-ai/wanaku + ref: ${{ github.ref_name }} persist-credentials: false - ref: main - path: wanaku + fetch-depth: 0 - name: Set up JDK 21 uses: actions/setup-java@v4 with: java-version: '21' distribution: 'temurin' cache: maven - - name: Build Wanaku Main Project - run: mvn -DskipTests clean install - working-directory: ${{ github.workspace }}/wanaku - - uses: actions/checkout@v4 - with: - ref: main - persist-credentials: false - fetch-depth: 0 - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/.github/workflows/pr-builds.yml b/.github/workflows/pr-builds.yml index 18e0d6a..122656c 100644 --- a/.github/workflows/pr-builds.yml +++ b/.github/workflows/pr-builds.yml @@ -41,26 +41,15 @@ jobs: fail-fast: true steps: - - name: Checkout Wanaku Main project - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: - repository: wanaku-ai/wanaku persist-credentials: false - ref: main - path: wanaku + fetch-depth: 0 - name: Set up JDK 21 uses: actions/setup-java@v4 with: java-version: '21' distribution: 'temurin' cache: maven - - name: Build Wanaku Main Project - run: mvn -DskipTests clean install - working-directory: ${{ github.workspace }}/wanaku - - uses: actions/checkout@v4 - with: - ref: main - persist-credentials: false - fetch-depth: 0 - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/.github/workflows/trigger-early-access.yml b/.github/workflows/trigger-early-access.yml new file mode 100644 index 0000000..af399f0 --- /dev/null +++ b/.github/workflows/trigger-early-access.yml @@ -0,0 +1,22 @@ +name: Trigger Early Access + +on: + schedule: + # Run every 2 days at 00:00 UTC + - cron: '0 0 */2 * *' + +jobs: + trigger: + name: Trigger Early Access Workflow + runs-on: ubuntu-latest + steps: + - name: Trigger early-access workflow + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'early-access.yml', + ref: 'main' + }) diff --git a/capabilities-api/pom.xml b/capabilities-api/pom.xml new file mode 100644 index 0000000..f21f87b --- /dev/null +++ b/capabilities-api/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + ai.wanaku.sdk + capabilities-parent + 0.0.9-SNAPSHOT + ../capabilities-parent/pom.xml + + + capabilities-api + + + + com.fasterxml.jackson.core + jackson-annotations + + + + \ No newline at end of file diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/DiscoveryCallback.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/DiscoveryCallback.java new file mode 100644 index 0000000..7489173 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/DiscoveryCallback.java @@ -0,0 +1,73 @@ +package ai.wanaku.capabilities.sdk.api.discovery; + +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; + +/** + * Callback interface for receiving notifications about service registration lifecycle events. + * + *

Implementations of this interface can be registered with a {@link RegistrationManager} + * to receive notifications when registration-related operations occur, such as successful + * registration, deregistration attempts, or periodic health check pings.

+ * + *

Callbacks are invoked synchronously after the corresponding operation completes. + * If a callback throws an exception, it will be logged but will not prevent other + * registered callbacks from executing.

+ * + *

Usage example:

+ *
{@code
+ * RegistrationManager manager = ...;
+ * manager.addCallBack(new RegistrationCallback() {
+ *     @Override
+ *     public void onRegistration(RegistrationManager manager) {
+ *         // Handle successful registration
+ *     }
+ *
+ *     @Override
+ *     public void onPing(RegistrationManager manager, int status) {
+ *         // Handle ping result
+ *     }
+ *
+ *     @Override
+ *     public void onDeregistration(RegistrationManager manager, int status) {
+ *         // Handle deregistration result
+ *     }
+ * });
+ * }
+ * + * @see RegistrationManager#addCallBack(DiscoveryCallback) + */ +public interface DiscoveryCallback { + + /** + * Invoked after a ping operation is sent to the discovery service. + * This callback is triggered when the service sends a heartbeat to indicate + * it is still active and operational. + * + * @param manager the {@link RegistrationManager} that performed the ping operation + * @param target the {@link ServiceTarget} that was pinged + * @param status the HTTP status code returned by the ping operation + * (200 indicates success, other values indicate various failure conditions) + */ + void onPing(RegistrationManager manager, ServiceTarget target, int status); + + /** + * Invoked after the service has been successfully registered with the discovery service. + * This callback is only called when registration completes successfully. + * + * @param manager the {@link RegistrationManager} that performed the registration + * @param target the {@link ServiceTarget} that was registered + */ + void onRegistration(RegistrationManager manager, ServiceTarget target); + + /** + * Invoked after a deregistration attempt is made with the discovery service. + * This callback is triggered when the service is being shut down or explicitly + * removed from the registry. + * + * @param manager the {@link RegistrationManager} that performed the deregistration operation + * @param target the {@link ServiceTarget} that was deregistered + * @param status the HTTP status code returned by the deregistration operation + * (200 indicates success, other values indicate various failure conditions) + */ + void onDeregistration(RegistrationManager manager, ServiceTarget target, int status); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/RegistrationManager.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/RegistrationManager.java new file mode 100644 index 0000000..34090bd --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/discovery/RegistrationManager.java @@ -0,0 +1,55 @@ +package ai.wanaku.capabilities.sdk.api.discovery; + +/** + * The `RegistrationManager` interface defines the contract for a class responsible for managing the lifecycle + * registration of a capability service within the Wanaku ecosystem. + * + *

Implementations of this interface handle the processes of registering, deregistering, + * and monitoring the status of a service's registration. It acts as the primary interface + * for a capability service to interact with the Wanaku registration mechanism.

+ */ +public interface RegistrationManager { + + /** + * Registers the capability service with Wanaku + */ + void register(); + + /** + * Deregisters the capability service from the Wanaku registration system. + * This method notifies the registry that the service is no longer available + * or is shutting down, allowing for proper cleanup and resource release. + */ + void deregister(); + + /** + * Sends a "ping" or heartbeat signal to the Wanaku registration system. + * This method is used to periodically inform the registry that the service is still active + * and operational, preventing its registration from expiring due to inactivity. + */ + void ping(); + + /** + * Notifies the Wanaku registration system that the last attempted operation (tool call + * or resource acquisition) from this service failed. + * + * @param reason A descriptive string explaining the reason for the failure. + * This information can be used for logging, debugging, or alerting purposes + * by the registration system. + */ + void lastAsFail(String reason); + + /** + * Notifies the Wanaku registration system that the last attempted operation (tool call + * or resource acquisition) from this service was successful. + * This method can be used to update the service's status within the registry, + * indicating its continued health and availability. + */ + void lastAsSuccessful(); + + /** + * Adds a callback to be run after some operations have executed + * @param callback the callback to add + */ + void addCallBack(DiscoveryCallback callback); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ConfigurationNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ConfigurationNotFoundException.java new file mode 100644 index 0000000..fc6e4c2 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ConfigurationNotFoundException.java @@ -0,0 +1,64 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception can be thrown if a configuration is expected in some way, but it is not found. + */ +public class ConfigurationNotFoundException extends WanakuException { + + /** + * Constructs a new instance of this exception without a message or cause. + */ + public ConfigurationNotFoundException() {} + + /** + * Constructs a new instance of this exception with the specified detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + */ + public ConfigurationNotFoundException(String message) { + super(message); + } + + /** + * Constructs a new instance of this exception with the specified detail message and cause. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public ConfigurationNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new instance of this exception with the specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public ConfigurationNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new instance of this exception with the specified detail message, cause, + * enable suppression and writable stack trace. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + * @param enableSuppression whether suppression is enabled + * @param writableStackTrace whether stack traces should be writtable + */ + public ConfigurationNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Creates a new instance of this exception for the given tool name. + * + * @param toolName the name of the tool that was not found + * @return a new instance of this exception with a message indicating that the tool was not found + */ + public static ConfigurationNotFoundException forName(String toolName) { + return new ConfigurationNotFoundException(String.format("Tool %s not found", toolName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/DataStoreResourceNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/DataStoreResourceNotFoundException.java new file mode 100644 index 0000000..d4065a4 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/DataStoreResourceNotFoundException.java @@ -0,0 +1,68 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when attempting to retrieve an item from the DataStore that does not exist. + * + * @see WanakuException + */ +public class DataStoreResourceNotFoundException extends WanakuException { + + /** + * Constructs an instance of the exception with no detail message or cause. + */ + public DataStoreResourceNotFoundException() { + super(); + } + + /** + * Constructs an instance of the exception with a specified detail message. + * + * @param message the detail message for this exception + */ + public DataStoreResourceNotFoundException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception with a specified cause and a detail message. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public DataStoreResourceNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of the exception with a specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public DataStoreResourceNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of the exception with a specified detail message, cause, suppression enabled or disabled, + * and writable stack trace enabled or disabled. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + * @param enableSuppression whether suppression is enabled or disabled + * @param writableStackTrace whether the stack trace should be writable + */ + public DataStoreResourceNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a data store resource could not be found. + * + * @param resourceName the name of the missing data store resource + * @return a new instance of this exception for the specified resource name + */ + public static DataStoreResourceNotFoundException forName(String resourceName) { + return new DataStoreResourceNotFoundException(String.format("DataStore resource %s not found", resourceName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/EntityAlreadyExistsException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/EntityAlreadyExistsException.java new file mode 100644 index 0000000..7675376 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/EntityAlreadyExistsException.java @@ -0,0 +1,71 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when an attempt is made to create an entity that already exists. + * + * This custom exception extends {@link WanakuException} and provides a + * clear indication of when a requested entity cannot be created because it already exists. + * It is mapped to HTTP status code 409 (Conflict) by the router. + */ +public class EntityAlreadyExistsException extends WanakuException { + + /** + * Default constructor for the exception, providing no additional information. + */ + public EntityAlreadyExistsException() { + super(); + } + + /** + * Constructor that allows specifying a custom error message for the exception. + * + * @param message The detailed message describing which entity already exists. + */ + public EntityAlreadyExistsException(String message) { + super(message); + } + + /** + * Constructor that provides both a custom error message and an underlying cause for the exception. + * + * @param message The detailed message describing which entity already exists. + * @param cause The root cause of the exception, providing additional context. + */ + public EntityAlreadyExistsException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor that specifies an underlying cause for the exception without a custom error message. + * + * @param cause The root cause of the exception, providing additional context. + */ + public EntityAlreadyExistsException(Throwable cause) { + super(cause); + } + + /** + * Constructor that allows specifying both a custom error message and an underlying cause for the exception, + * along with options to enable suppression or writable stack trace. + * + * @param message The detailed message describing which entity already exists. + * @param cause The root cause of the exception, providing additional context. + * @param enableSuppression Whether to allow suppressing this exception during exception propagation. + * @param writableStackTrace Whether to include a stack trace with this exception. + */ + public EntityAlreadyExistsException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Factory method that creates a new instance of the exception for a given entity name, + * providing a pre-formatted error message indicating that the entity already exists. + * + * @param entityName The name or identifier of the entity that already exists. + * @return A new instance of the {@link EntityAlreadyExistsException} class with a custom error message. + */ + public static EntityAlreadyExistsException forName(String entityName) { + return new EntityAlreadyExistsException(String.format("Entity %s already exists", entityName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/InvalidResponseTypeException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/InvalidResponseTypeException.java new file mode 100644 index 0000000..eb8579b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/InvalidResponseTypeException.java @@ -0,0 +1,71 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception can be thrown if a response of certain type is expected, but it came differently. + * + * Typically used to indicate that an API or service returned a response in an unexpected format, + * such as an Integer object instead of String, or vice versa. + */ +public class InvalidResponseTypeException extends WanakuException { + + /** + * Constructs a new instance of this exception without a message or cause. + */ + public InvalidResponseTypeException() {} + + /** + * Constructs a new instance of this exception with the specified detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + */ + public InvalidResponseTypeException(String message) { + super(message); + } + + /** + * Constructs a new instance of this exception with the specified detail message and cause. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public InvalidResponseTypeException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new instance of this exception with the specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public InvalidResponseTypeException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new instance of this exception with the specified detail message, cause, + * enable suppression and writable stack trace. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + * @param enableSuppression whether suppression is enabled + * @param writableStackTrace whether stack traces should be writtable + */ + public InvalidResponseTypeException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Creates a new instance of this exception for the given tool name. + * + * Note that this method is incorrectly named - it should probably be renamed to something like + * {@code forResponseType} or similar. This will throw an exception with a message indicating + * that the response type was not found. + * + * @param toolName the name of the tool (or response type) that was expected but not found + * @return a new instance of this exception with a message indicating that the response type was not found + */ + public static InvalidResponseTypeException forName(String toolName) { + return new InvalidResponseTypeException(String.format("Tool %s not found", toolName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NamespaceNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NamespaceNotFoundException.java new file mode 100644 index 0000000..8739c37 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NamespaceNotFoundException.java @@ -0,0 +1,67 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when a specified namespace cannot be located or does not exist. + * @see WanakuException + */ +public class NamespaceNotFoundException extends WanakuException { + + /** + * Constructs an instance of the exception with no detail message or cause. + */ + public NamespaceNotFoundException() { + super(); + } + + /** + * Constructs an instance of the exception with a specified detail message. + * + * @param message the detail message for this exception + */ + public NamespaceNotFoundException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception with a specified cause and a detail message. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public NamespaceNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of the exception with a specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public NamespaceNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of the exception with a specified detail message, cause, suppression enabled or disabled, + * and writable stack trace enabled or disabled. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + */ + public NamespaceNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a namespace could not be found. + * + * @param namespaceId the identifier of the missing namespace + * @return a new instance of this exception for the specified namespace identifier + */ + public static NamespaceNotFoundException forId(String namespaceId) { + return new NamespaceNotFoundException(String.format("Namespace %s not found", namespaceId)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NonConvertableResponseException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NonConvertableResponseException.java new file mode 100644 index 0000000..0d3074c --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/NonConvertableResponseException.java @@ -0,0 +1,71 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception can be thrown if a response is not convertible to the required type. + * + * Typically used when attempting to deserialize or convert a response from a service or API, + * but encountering issues due to mismatched types, formats, or other errors. + */ +public class NonConvertableResponseException extends WanakuException { + + /** + * Constructs a new instance of this exception without a message or cause. + */ + public NonConvertableResponseException() {} + + /** + * Constructs a new instance of this exception with the specified detail message. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + */ + public NonConvertableResponseException(String message) { + super(message); + } + + /** + * Constructs a new instance of this exception with the specified detail message and cause. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public NonConvertableResponseException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new instance of this exception with the specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + */ + public NonConvertableResponseException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new instance of this exception with the specified detail message, cause, + * enable suppression and writable stack trace. + * + * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method) + * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) + * @param enableSuppression whether or not suppression is enabled + * @param writableStackTrace whether or not stack traces should be writtable + */ + public NonConvertableResponseException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Creates a new instance of this exception for the given tool name. + * + * Note that this method is incorrectly named - it should probably be renamed to something like + * {@code forResponseType} or similar. This will throw an exception with a message indicating + * that the response was not convertible to the required type. + * + * @param toolName the name of the tool (or response) that could not be converted to the required type + * @return a new instance of this exception with a message indicating that the response was not convertible + */ + public static NonConvertableResponseException forName(String toolName) { + return new NonConvertableResponseException(String.format("Tool %s not found", toolName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/PromptNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/PromptNotFoundException.java new file mode 100644 index 0000000..9f21fbd --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/PromptNotFoundException.java @@ -0,0 +1,15 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * Exception thrown when a prompt cannot be found. + */ +public class PromptNotFoundException extends WanakuException { + /** + * Constructs a new PromptNotFoundException with the specified prompt name. + * + * @param promptName the name of the prompt that was not found + */ + public PromptNotFoundException(String promptName) { + super(String.format("Prompt '%s' not found", promptName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ResourceNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ResourceNotFoundException.java new file mode 100644 index 0000000..61b009a --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ResourceNotFoundException.java @@ -0,0 +1,68 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception can be thrown if the resource is not found. + * + * This custom exception extends {@link WanakuException} and provides a + * clear indication of when a requested resource cannot be located or accessed. + */ +public class ResourceNotFoundException extends WanakuException { + + /** + * Default constructor for the exception, providing no additional information. + */ + public ResourceNotFoundException() {} + + /** + * Constructor that allows specifying a custom error message for the exception. + * + * @param message The detailed message describing why the resource was not found. + */ + public ResourceNotFoundException(String message) { + super(message); + } + + /** + * Constructor that provides both a custom error message and an underlying cause for the exception. + * + * @param message The detailed message describing why the resource was not found. + * @param cause The root cause of the exception, providing additional context. + */ + public ResourceNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor that specifies an underlying cause for the exception without a custom error message. + * + * @param cause The root cause of the exception, providing additional context. + */ + public ResourceNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructor that allows specifying both a custom error message and an underlying cause for the exception, + * along with options to enable suppression or writable stack trace. + * + * @param message The detailed message describing why the resource was not found. + * @param cause The root cause of the exception, providing additional context. + * @param enableSuppression Whether to allow suppressing this exception during exception propagation. + * @param writableStackTrace Whether to include a stack trace with this exception. + */ + public ResourceNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Factory method that creates a new instance of the exception for a given resource name, + * providing a pre-formatted error message indicating that the resource was not found. + * + * @param resourceName The name or identifier of the resource that was not found. + * @return A new instance of the {@link ResourceNotFoundException} class with a custom error message. + */ + public static ResourceNotFoundException forName(String resourceName) { + return new ResourceNotFoundException(String.format("Resource %s not found", resourceName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceNotFoundException.java new file mode 100644 index 0000000..c21646e --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceNotFoundException.java @@ -0,0 +1,68 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when a specified service cannot be located or does not exist. + * + * @see WanakuException + */ +public class ServiceNotFoundException extends WanakuException { + + /** + * Constructs an instance of the exception with no detail message or cause. + */ + public ServiceNotFoundException() { + super(); + } + + /** + * Constructs an instance of the exception with a specified detail message. + * + * @param message the detail message for this exception + */ + public ServiceNotFoundException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception with a specified cause and a detail message. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ServiceNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of the exception with a specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ServiceNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of the exception with a specified detail message, cause, suppression enabled or disabled, + * and writable stack trace enabled or disabled. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + * @param enableSuppression whether suppression is enabled or disabled + * @param writableStackTrace whether the stack trace should be writable + */ + public ServiceNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a service could not be found. + * + * @param serviceName the name of the missing service + * @return a new instance of this exception for the specified service name + */ + public static ServiceNotFoundException forName(String serviceName) { + return new ServiceNotFoundException(String.format("Service %s not found", serviceName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceUnavailableException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceUnavailableException.java new file mode 100644 index 0000000..e7ee711 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ServiceUnavailableException.java @@ -0,0 +1,79 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when a specified service is not available. + * + * @see WanakuException + */ +public class ServiceUnavailableException extends WanakuException { + + /** + * Constructs an instance of the exception with no detail message or cause. + */ + public ServiceUnavailableException() { + super(); + } + + /** + * Constructs an instance of the exception with a specified detail message. + * + * @param message the detail message for this exception + */ + public ServiceUnavailableException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception with a specified cause and a detail message. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ServiceUnavailableException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of the exception with a specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ServiceUnavailableException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of the exception with a specified detail message, cause, suppression enabled or disabled, + * and writable stack trace enabled or disabled. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + * @param enableSuppression whether suppression is enabled or disabled + * @param writableStackTrace whether the stack trace should be writable + */ + public ServiceUnavailableException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a service was not available. + * + * @param serviceName the name of the missing service + * @return a new instance of this exception for the specified service name + */ + public static ServiceUnavailableException forName(String serviceName) { + return new ServiceUnavailableException(String.format("Service is not available at %s", serviceName)); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a service was not available at + * a specific address. + * + * @param address the address of the missing service + * @return a new instance of this exception for the specified service name + */ + public static ServiceUnavailableException forAddress(String address) { + return new ServiceUnavailableException(String.format("Service is not available at the address %s", address)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ToolNotFoundException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ToolNotFoundException.java new file mode 100644 index 0000000..3cd678f --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/ToolNotFoundException.java @@ -0,0 +1,67 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This exception is thrown when a specified tool cannot be located or does not exist. + * @see WanakuException + */ +public class ToolNotFoundException extends WanakuException { + + /** + * Constructs an instance of the exception with no detail message or cause. + */ + public ToolNotFoundException() { + super(); + } + + /** + * Constructs an instance of the exception with a specified detail message. + * + * @param message the detail message for this exception + */ + public ToolNotFoundException(String message) { + super(message); + } + + /** + * Constructs an instance of the exception with a specified cause and a detail message. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ToolNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of the exception with a specified cause. + * + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + */ + public ToolNotFoundException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of the exception with a specified detail message, cause, suppression enabled or disabled, + * and writable stack trace enabled or disabled. + * + * @param message the detail message for this exception + * @param cause the cause (which is saved for later retrieval by the {@link Throwable#getCause()} method) + * @param enableSuppression whether or not suppression is enabled or disabled + * @param writableStackTrace whether or not the stack trace should be writable + */ + public ToolNotFoundException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + /** + * Returns a new instance of this exception with a formatted string indicating that a tool could not be found. + * + * @param toolName the name of the missing tool + * @return a new instance of this exception for the specified tool name + */ + public static ToolNotFoundException forName(String toolName) { + return new ToolNotFoundException(String.format("Tool %s not found", toolName)); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/WanakuException.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/WanakuException.java new file mode 100644 index 0000000..d75b2a3 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/exceptions/WanakuException.java @@ -0,0 +1,59 @@ +package ai.wanaku.capabilities.sdk.api.exceptions; + +/** + * This is the base exception class. + * + * The {@link WanakuException} class extends the built-in {@link RuntimeException} to provide + * a custom exception hierarchy. + */ +public class WanakuException extends RuntimeException { + + /** + * Constructs an instance of this exception with no detail message or cause. + * + * This constructor provides a basic implementation for instances where no additional context is needed. + */ + public WanakuException() { + super(); + } + + /** + * Constructs an instance of this exception with the specified detail message and without a cause. + * + * @param message The message describing the reason for this exception being thrown. + */ + public WanakuException(String message) { + super(message); + } + + /** + * Constructs an instance of this exception with the specified detail message and underlying cause. + * + * @param message The message describing the reason for this exception being thrown. + * @param cause The root cause that led to this exception being thrown. + */ + public WanakuException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs an instance of this exception with the specified underlying cause but without a detail message. + * + * @param cause The root cause that led to this exception being thrown. + */ + public WanakuException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of this exception with the specified detail message and underlying cause, along with suppression flags. + * + * @param message The message describing the reason for this exception being thrown. + * @param cause The root cause that led to this exception being thrown. + * @param enableSuppression Whether to suppress the reporting of this exception's cause. + * @param writableStackTrace Whether to make the stack trace associated with this exception writable. + */ + public WanakuException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/AudioContent.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/AudioContent.java new file mode 100644 index 0000000..c1ccf00 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/AudioContent.java @@ -0,0 +1,71 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents audio content in a prompt message. + * Audio is provided as base64-encoded data with a MIME type. + */ +public class AudioContent implements PromptContent { + private static final String TYPE = "audio"; + + /** + * Base64-encoded audio data. + */ + private String data; + + /** + * MIME type of the audio (e.g., "audio/mp3", "audio/wav", "audio/ogg"). + */ + private String mimeType; + + public AudioContent() {} + + public AudioContent(String data, String mimeType) { + this.data = data; + this.mimeType = mimeType; + } + + @Override + public String getType() { + return TYPE; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + AudioContent that = (AudioContent) o; + return Objects.equals(data, that.data) && Objects.equals(mimeType, that.mimeType); + } + + @Override + public int hashCode() { + return Objects.hash(data, mimeType); + } + + @Override + public String toString() { + return "AudioContent{" + "type='" + + TYPE + '\'' + ", mimeType='" + + mimeType + '\'' + ", dataLength=" + + (data != null ? data.length() : 0) + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/CallableReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/CallableReference.java new file mode 100644 index 0000000..fb885c4 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/CallableReference.java @@ -0,0 +1,63 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * Represents a reference to a callable entity that can be invoked with arguments. + *

+ * A callable reference is an abstraction for any object or function that can be invoked, + * potentially with arguments. This interface provides metadata about the callable entity + * including its name, description, type, input schema, and namespace. + *

+ * This interface is implemented by various tool and capability reference types to provide + * a common contract for invocable entities in the Wanaku system. + * + * @see ToolReference + * @see RemoteToolReference + */ +public interface CallableReference { + /** + * Gets the name of this callable reference. + * + * @return the name of this callable reference + */ + String getName(); + + /** + * Gets the human-readable description of this callable reference. + *

+ * The description provides information about what this callable does, + * its purpose, and how it should be used. + * + * @return a human-readable description of this callable reference + */ + String getDescription(); + + /** + * Gets the type associated with this callable reference. + *

+ * The type typically indicates the category or implementation mechanism + * of the callable (e.g., "http", "function", "tool"). + * + * @return the type associated with this callable reference + */ + String getType(); + + /** + * Gets the input schema for this callable reference. + *

+ * The input schema describes the expected structure, format, and validation + * rules for arguments that can be passed to this callable. + * + * @return the input schema for this callable reference + */ + InputSchema getInputSchema(); + + /** + * Gets the namespace in which this callable reference is registered. + *

+ * The namespace provides logical grouping and isolation for callable + * references within the Wanaku system. + * + * @return the namespace identifier + */ + String getNamespace(); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/DataStore.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/DataStore.java new file mode 100644 index 0000000..4766e1b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/DataStore.java @@ -0,0 +1,182 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Entity representing a data store entry for persisting arbitrary binary or text data. + * + *

DataStore provides a generic storage mechanism for files, configurations, or any other + * content that needs to be stored and retrieved through the Wanaku API. The data is typically + * stored as Base64-encoded content to safely handle binary files and special characters. + * + *

Usage Example: + *

{@code
+ * // Creating a new data store entry
+ * DataStore dataStore = new DataStore();
+ * dataStore.setName("config.yaml");
+ * dataStore.setData(Base64.getEncoder().encodeToString(fileBytes));
+ * dataStore.addLabel("environment", "production");
+ *
+ * // The ID will be automatically assigned by the persistence layer
+ * }
+ * + *

Storage Format: + *

+ * + * @see LabelsAwareEntity + * @see WanakuEntity + */ +public class DataStore extends LabelsAwareEntity { + + /** + * Unique identifier for this data store entry. + * Automatically generated by the persistence layer when the entry is created. + */ + private String id; + + /** + * Human-readable name for this data store entry. + * Typically represents the original filename or a descriptive label. + * Multiple data stores can share the same name. + */ + private String name; + + /** + * The stored content, typically Base64-encoded. + * This field contains the actual data payload, which is usually encoded + * to safely handle binary files and special characters. + */ + private String data; + + /** + * Default constructor required for serialization/deserialization. + */ + public DataStore() {} + + /** + * Constructs a DataStore with all fields initialized. + * + * @param id the unique identifier for this data store entry + * @param name the human-readable name for this entry + * @param data the content to store (typically Base64-encoded) + */ + public DataStore(String id, String name, String data) { + this.id = id; + this.name = name; + this.data = data; + } + + /** + * Returns the unique identifier for this data store entry. + * + * @return the ID, or {@code null} if not yet persisted + */ + @Override + public String getId() { + return id; + } + + /** + * Sets the unique identifier for this data store entry. + * Typically called by the persistence layer. + * + * @param id the unique identifier + */ + @Override + public void setId(String id) { + this.id = id; + } + + /** + * Returns the human-readable name of this data store entry. + * + * @return the name, typically representing the filename or label + */ + public String getName() { + return name; + } + + /** + * Sets the human-readable name for this data store entry. + * + * @param name the name to set (e.g., filename or descriptive label) + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the stored content data. + * + * @return the data content, typically Base64-encoded + */ + public String getData() { + return data; + } + + /** + * Sets the content data to be stored. + * + *

The data should typically be Base64-encoded when storing binary files + * or content with special characters. For example: + *

{@code
+     * byte[] fileBytes = Files.readAllBytes(path);
+     * dataStore.setData(Base64.getEncoder().encodeToString(fileBytes));
+     * }
+ * + * @param data the content to store (typically Base64-encoded) + */ + public void setData(String data) { + this.data = data; + } + + /** + * Compares this DataStore to another object for equality. + * Two DataStore instances are considered equal if they have the same id, name, data, and labels. + * + * @param o the object to compare with + * @return {@code true} if the objects are equal, {@code false} otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DataStore dataStore = (DataStore) o; + return Objects.equals(id, dataStore.id) + && Objects.equals(name, dataStore.name) + && Objects.equals(data, dataStore.data) + && Objects.equals(getLabels(), dataStore.getLabels()); + } + + /** + * Returns a hash code value for this DataStore. + * The hash code is computed based on the id, name, data, and labels fields. + * + * @return a hash code value for this object + */ + @Override + public int hashCode() { + return Objects.hash(id, name, data, getLabels()); + } + + /** + * Returns a string representation of this DataStore. + * The string includes the id, name, data, and labels fields. + * + * @return a string representation of this DataStore + */ + @Override + public String toString() { + return "DataStore{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", data='" + data + '\'' + + ", labels=" + getLabels() + + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/EmbeddedResource.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/EmbeddedResource.java new file mode 100644 index 0000000..4e0f635 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/EmbeddedResource.java @@ -0,0 +1,54 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents an embedded resource in a prompt message. + * This allows prompts to reference other resources. + */ +public class EmbeddedResource implements PromptContent { + private static final String TYPE = "resource"; + + /** + * The resource being embedded. + */ + private ResourceReference resource; + + public EmbeddedResource() {} + + public EmbeddedResource(ResourceReference resource) { + this.resource = resource; + } + + @Override + public String getType() { + return TYPE; + } + + public ResourceReference getResource() { + return resource; + } + + public void setResource(ResourceReference resource) { + this.resource = resource; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + EmbeddedResource that = (EmbeddedResource) o; + return Objects.equals(resource, that.resource); + } + + @Override + public int hashCode() { + return Objects.hash(resource); + } + + @Override + public String toString() { + return "EmbeddedResource{" + "type='" + TYPE + '\'' + ", resource=" + resource + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ForwardReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ForwardReference.java new file mode 100644 index 0000000..2d77c73 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ForwardReference.java @@ -0,0 +1,109 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents a reference to a forward service. + * + * This class holds information about the address of the forward service, + * allowing it to be easily accessed and modified. + */ +public class ForwardReference implements WanakuEntity { + private String id; + private String name; + private String address; + private String namespace; + + /** + * Default constructor for ForwardReference. + */ + public ForwardReference() {} + + /** + * The name of the reference + * @return name of the reference as a string + */ + public String getName() { + return name; + } + + /** + * Sets the name of the reference + * @param name the name of the reference as a string + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the address of the forward service. + * + * @return the address as a string + */ + public String getAddress() { + return address; + } + + /** + * Sets the address of the forward service. + * + * @param address the new address to use for the forward service + */ + public void setAddress(String address) { + this.address = address; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + /** + * Gets the namespace in which this forward is registered. + * + * @return the namespace identifier + */ + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace in which this forward is registered. + * + * @param namespace the namespace identifier to set + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ForwardReference that = (ForwardReference) o; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(address, that.address) + && Objects.equals(namespace, that.namespace); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, address, namespace); + } + + @Override + public String toString() { + return "ForwardReference{" + "id='" + + id + '\'' + ", name='" + + name + '\'' + ", address='" + + address + '\'' + ", namespace='" + + namespace + '\'' + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ImageContent.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ImageContent.java new file mode 100644 index 0000000..1fa7d39 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ImageContent.java @@ -0,0 +1,71 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents image content in a prompt message. + * Images are provided as base64-encoded data with a MIME type. + */ +public class ImageContent implements PromptContent { + private static final String TYPE = "image"; + + /** + * Base64-encoded image data. + */ + private String data; + + /** + * MIME type of the image (e.g., "image/png", "image/jpeg"). + */ + private String mimeType; + + public ImageContent() {} + + public ImageContent(String data, String mimeType) { + this.data = data; + this.mimeType = mimeType; + } + + @Override + public String getType() { + return TYPE; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ImageContent that = (ImageContent) o; + return Objects.equals(data, that.data) && Objects.equals(mimeType, that.mimeType); + } + + @Override + public int hashCode() { + return Objects.hash(data, mimeType); + } + + @Override + public String toString() { + return "ImageContent{" + "type='" + + TYPE + '\'' + ", mimeType='" + + mimeType + '\'' + ", dataLength=" + + (data != null ? data.length() : 0) + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/InputSchema.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/InputSchema.java new file mode 100644 index 0000000..830509c --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/InputSchema.java @@ -0,0 +1,91 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Represents the input schema for a tool, including type, properties, and required fields. + */ +public class InputSchema { + + private String type; + private Map properties = new HashMap<>(); + private List required; + + /** + * Default constructor for InputSchema. + */ + public InputSchema() {} + + /** + * Gets the type of the input schema. + * + * @return the type of the input schema + */ + public String getType() { + return type; + } + + /** + * Sets the type of the input schema. + * + * @param type the new type of the input schema + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the properties of the input schema. + * + * @return a map of property names to Property objects + */ + public Map getProperties() { + return properties; + } + + /** + * Sets the properties of the input schema. + * + * @param properties a map of property names to Property objects + */ + public void setProperties(Map properties) { + this.properties = properties; + } + + /** + * Gets the list of required fields in the input schema. + * + * @return a list of required field names + */ + public List getRequired() { + return required; + } + + /** + * Sets the list of required fields in the input schema. + * + * @param required a list of required field names + */ + public void setRequired(List required) { + this.required = required; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + InputSchema that = (InputSchema) o; + return Objects.equals(type, that.type) + && Objects.equals(properties, that.properties) + && Objects.equals(required, that.required); + } + + @Override + public int hashCode() { + return Objects.hash(type, properties, required); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/LabelsAwareEntity.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/LabelsAwareEntity.java new file mode 100644 index 0000000..5db87de --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/LabelsAwareEntity.java @@ -0,0 +1,114 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.HashMap; +import java.util.Map; + +/** + * Abstract base class for Wanaku entities that support labels. + *

+ * Labels provide a flexible mechanism for attaching key-value metadata to entities, + * enabling categorization, filtering, and organization of resources within the + * Wanaku system. + * + * @param the type of the entity identifier + * @see WanakuEntity + */ +public abstract class LabelsAwareEntity implements WanakuEntity { + + private Map labels; + + /** + * Gets the labels as a map. + * + * @return the map of labels, never null + */ + public Map getLabels() { + if (labels == null) { + labels = new HashMap<>(); + } + return labels; + } + + /** + * Sets the labels from a map. + * + * @param labels the map of labels + */ + public void setLabels(Map labels) { + this.labels = labels; + } + + /** + * Adds a single label. + * + * @param key the label key + * @param value the label value + */ + public void addLabel(String key, String value) { + getLabels().put(key, value); + } + + /** + * Adds multiple labels from a map. + * + * @param labelsMap the labels to add + */ + public void addLabels(Map labelsMap) { + if (labelsMap != null) { + getLabels().putAll(labelsMap); + } + } + + /** + * Gets the value of a specific label by key. + * + * @param labelKey the label key to look up + * @return the label value, or null if not found + */ + public String getLabelValue(String labelKey) { + if (labels == null) { + return null; + } + return labels.get(labelKey); + } + + /** + * Checks if a label with the given key exists. + * + * @param labelKey the label key to check + * @return true if the label exists, false otherwise + */ + public boolean hasLabel(String labelKey) { + if (labels == null) { + return false; + } + return labels.containsKey(labelKey); + } + + /** + * Checks if a label with the given key and value exists. + * + * @param labelKey the label key to check + * @param labelValue the label value to check + * @return true if the label exists with the given value, false otherwise + */ + public boolean hasLabel(String labelKey, String labelValue) { + if (labels == null) { + return false; + } + return labelValue.equals(labels.get(labelKey)); + } + + /** + * Removes a label by key. + * + * @param labelKey the label key to remove + * @return true if a label was removed, false otherwise + */ + public boolean removeLabel(String labelKey) { + if (labels == null) { + return false; + } + return labels.remove(labelKey) != null; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/NameNamespacePair.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/NameNamespacePair.java new file mode 100644 index 0000000..d6b890b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/NameNamespacePair.java @@ -0,0 +1,13 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * A record representing a name and namespace pair for identifying Wanaku entities. + *

+ * This immutable record is used throughout the Wanaku system to uniquely identify + * capabilities, tools, and resources by combining their name with their namespace. + * The combination of name and namespace provides a fully qualified identifier. + * + * @param name the entity name + * @param namespace the namespace in which the entity resides + */ +public record NameNamespacePair(String name, String namespace) {} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Namespace.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Namespace.java new file mode 100644 index 0000000..d828a8f --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Namespace.java @@ -0,0 +1,73 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * Represents a namespace within the Wanaku system. + *

+ * Namespaces provide logical grouping and isolation for capabilities, tools, and resources. + * Each namespace has a unique identifier, a human-readable name, and a path that defines + * its location within the namespace hierarchy. + */ +public class Namespace extends LabelsAwareEntity { + private String id; + private String name; + private String path; + + /** + * Gets the unique identifier for this namespace. + * + * @return the namespace identifier + */ + @Override + public String getId() { + return id; + } + + /** + * Sets the unique identifier for this namespace. + * + * @param id the namespace identifier to set + */ + @Override + public void setId(String id) { + this.id = id; + } + + /** + * Gets the human-readable name of this namespace. + * + * @return the namespace name + */ + public String getName() { + return name; + } + + /** + * Sets the human-readable name of this namespace. + * + * @param name the namespace name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the hierarchical path of this namespace. + *

+ * The path defines the location of this namespace within the namespace hierarchy + * and is used for namespace resolution and organization. + * + * @return the namespace path + */ + public String getPath() { + return path; + } + + /** + * Sets the hierarchical path of this namespace. + * + * @param path the namespace path to set + */ + public void setPath(String path) { + this.path = path; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptContent.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptContent.java new file mode 100644 index 0000000..e71af13 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptContent.java @@ -0,0 +1,27 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + +/** + * Base interface for different types of prompt content. + * According to MCP specification, content can be: + * - TextContent + * - ImageContent + * - AudioContent + * - EmbeddedResource + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = TextContent.class, name = "text"), + @JsonSubTypes.Type(value = ImageContent.class, name = "image"), + @JsonSubTypes.Type(value = AudioContent.class, name = "audio"), + @JsonSubTypes.Type(value = EmbeddedResource.class, name = "resource") +}) +public interface PromptContent { + /** + * Gets the type of content. + * @return The content type (e.g., "text", "image", "audio", "resource") + */ + String getType(); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptMessage.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptMessage.java new file mode 100644 index 0000000..cc58a5f --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptMessage.java @@ -0,0 +1,70 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents a message in an MCP prompt. + * Each message has a role and content according to the MCP specification. + */ +public class PromptMessage { + /** + * The role of the message sender. + * Valid values: "user", "assistant" + */ + private String role; + + /** + * The content of the message. + * This is a polymorphic field that can be one of: + * - TextContent + * - ImageContent + * - AudioContent + * - EmbeddedResource + */ + private PromptContent content; + + public PromptMessage() {} + + public PromptMessage(String role, PromptContent content) { + this.role = role; + this.content = content; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public PromptContent getContent() { + return content; + } + + public void setContent(PromptContent content) { + this.content = content; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PromptMessage that = (PromptMessage) o; + return Objects.equals(role, that.role) && Objects.equals(content, that.content); + } + + @Override + public int hashCode() { + return Objects.hash(role, content); + } + + @Override + public String toString() { + return "PromptMessage{" + "role='" + role + '\'' + ", content=" + content + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptReference.java new file mode 100644 index 0000000..6317555 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/PromptReference.java @@ -0,0 +1,217 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.List; +import java.util.Objects; + +/** + * Represents a prompt reference in the MCP protocol. + * Prompts are reusable templates that can leverage multiple tools and provide + * example interactions for LLMs. + */ +public class PromptReference implements WanakuEntity { + private String id; + + /** + * The name of the prompt. + */ + private String name; + + /** + * A description of what the prompt does. + */ + private String description; + + /** + * The prompt messages following MCP specification. + * Each message has a role (user, assistant) and content. + */ + private List messages; + + /** + * List of arguments/parameters this prompt accepts. + */ + private List arguments; + + /** + * Optional list of tool names that this prompt may use. + */ + private List toolReferences; + + /** + * The namespace this prompt belongs to. + */ + private String namespace; + + /** + * Configuration URI for the prompt. + */ + private String configurationURI; + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getMessages() { + return messages; + } + + public void setMessages(List messages) { + this.messages = messages; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + public List getToolReferences() { + return toolReferences; + } + + public void setToolReferences(List toolReferences) { + this.toolReferences = toolReferences; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getConfigurationURI() { + return configurationURI; + } + + public void setConfigurationURI(String configurationURI) { + this.configurationURI = configurationURI; + } + + /** + * Represents an argument/parameter for a prompt. + */ + public static class PromptArgument { + /** + * The name of the argument. + */ + private String name; + + /** + * A description of the argument. + */ + private String description; + + /** + * Whether this argument is required. + */ + private boolean required; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + PromptArgument that = (PromptArgument) o; + return required == that.required + && Objects.equals(name, that.name) + && Objects.equals(description, that.description); + } + + @Override + public int hashCode() { + return Objects.hash(name, description, required); + } + + @Override + public String toString() { + return "PromptArgument{" + "name='" + + name + '\'' + ", description='" + + description + '\'' + ", required=" + + required + '}'; + } + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + PromptReference that = (PromptReference) o; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && Objects.equals(messages, that.messages) + && Objects.equals(arguments, that.arguments) + && Objects.equals(toolReferences, that.toolReferences) + && Objects.equals(namespace, that.namespace) + && Objects.equals(configurationURI, that.configurationURI); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, description, messages, arguments, toolReferences, namespace, configurationURI); + } + + @Override + public String toString() { + return "PromptReference{" + "id='" + + id + '\'' + ", name='" + + name + '\'' + ", description='" + + description + '\'' + ", messages=" + + messages + ", arguments=" + + arguments + ", toolReferences=" + + toolReferences + ", namespace='" + + namespace + '\'' + ", configurationURI='" + + configurationURI + '\'' + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Property.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Property.java new file mode 100644 index 0000000..881635d --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/Property.java @@ -0,0 +1,124 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents a single property in the input schema. + */ +public class Property { + + private String type; + private String description; + private String target; + private String scope; + private String value; + + /** + * Gets the type of the property. + * + * @return the type of the property + */ + public String getType() { + return type; + } + + /** + * Sets the type of the property. + * + * @param type the new type of the property + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the description of the property. + * + * @return the description of the property + */ + public String getDescription() { + return description; + } + + /** + * Sets the description of the property. + * + * @param description the new description of the property + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the target of the property. + * + * @return the target of the property + */ + public String getTarget() { + return target; + } + + /** + * Sets the target of the property. + * + * @param target the new target of the property + */ + public void setTarget(String target) { + this.target = target; + } + + /** + * Gets the scope of the property. + * + * @return the scope of the property + */ + public String getScope() { + return scope; + } + + /** + * Sets the scope of the property. + * + * @param scope the new scope of the property + */ + public void setScope(String scope) { + this.scope = scope; + } + + /** + * Gets the value of the property. + * + * @return the value of the property + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the property. + * + * @param value the new value of the property + */ + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + + Property that = (Property) o; + return Objects.equals(type, that.type) + && Objects.equals(description, that.description) + && Objects.equals(target, that.target) + && Objects.equals(scope, that.scope) + && Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(type, description, target, scope, value); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/RemoteToolReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/RemoteToolReference.java new file mode 100644 index 0000000..1d77157 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/RemoteToolReference.java @@ -0,0 +1,185 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents a reference to a tool capability available on a remote MCP server. + *

+ * A remote tool reference contains metadata about a tool that is provided by an + * external service or remote MCP server, rather than being locally implemented. + * This class is used when tools are discovered through forward proxies or when + * integrating with remote capability providers. + *

+ * Remote tool references can be converted to standard {@link ToolReference} + * instances using the {@link #asToolReference(RemoteToolReference)} method, + * which assigns a placeholder URI to indicate the remote nature of the tool. + * + * @see ToolReference + * @see CallableReference + */ +public class RemoteToolReference extends LabelsAwareEntity implements CallableReference { + private String id; + private String name; + private String description; + private String type; + private InputSchema inputSchema; + private String namespace; + + /** + * Gets the name of the tool. + * + * @return the name of the tool + */ + @Override + public String getName() { + return name; + } + + /** + * Sets the name of the tool. + * + * @param name the new name of the tool + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the description of the tool. + * + * @return the description of the tool + */ + @Override + public String getDescription() { + return description; + } + + /** + * Sets the description of the tool. + * + * @param description the new description of the tool + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the type of the tool reference. + * + * @return the type of the tool reference + */ + @Override + public String getType() { + return type; + } + + /** + * Sets the type of the tool reference and returns the current object for method chaining. + * + * @param type the new type of the tool reference + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the input schema of the tool reference. + * + * @return the input schema of the tool reference + */ + @Override + public InputSchema getInputSchema() { + return inputSchema; + } + + /** + * Sets the input schema of the tool reference. + * + * @param inputSchema the new input schema of the tool reference + */ + public void setInputSchema(InputSchema inputSchema) { + this.inputSchema = inputSchema; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + RemoteToolReference that = (RemoteToolReference) o; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && Objects.equals(type, that.type) + && Objects.equals(inputSchema, that.inputSchema) + && Objects.equals(this.getLabels(), that.getLabels()); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, description, type, inputSchema); + } + + @Override + public String toString() { + return "RemoteToolReference{" + "id='" + + id + '\'' + ", name='" + + name + '\'' + ", description='" + + description + '\'' + ", type='" + + type + '\'' + ", inputSchema=" + + inputSchema + '\'' + ", labels='" + + this.getLabels() + '\'' + '}'; + } + + /** + * Converts a remote tool reference to a standard tool reference. + *

+ * This utility method creates a {@link ToolReference} from a {@link RemoteToolReference} + * by copying all metadata and assigning a placeholder URI {@code ""} to indicate + * that the tool is provided by a remote service. + * + * @param ref the remote tool reference to convert + * @return a tool reference with the same metadata and a placeholder remote URI + */ + public static ToolReference asToolReference(RemoteToolReference ref) { + ToolReference ret = new ToolReference(); + + ret.setDescription(ref.getDescription()); + ret.setInputSchema(ref.getInputSchema()); + ret.setName(ref.getName()); + ret.setType(ref.getType()); + ret.setUri(""); + ret.setId(ref.getId()); + + return ret; + } + + /** + * Gets the namespace in which this remote tool is registered. + * + * @return the namespace identifier + */ + @Override + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace in which this remote tool is registered. + * + * @param namespace the namespace identifier to set + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ResourceReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ResourceReference.java new file mode 100644 index 0000000..5eae3d1 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ResourceReference.java @@ -0,0 +1,325 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.List; +import java.util.Objects; + +/** + * Represents a resource reference, containing details such as location, type, and parameters. + */ +public class ResourceReference extends LabelsAwareEntity { + private String id; + + /** + * The location of the resource (e.g., URL, file path). + */ + private String location; + + /** + * The type of the resource (e.g., image, text, binary). + */ + private String type; + + /** + * A brief name for the resource. + */ + private String name; + + /** + * A longer description of the resource. + */ + private String description; + + /** + * The MIME type of the resource (e.g., image/jpeg, text/plain). + */ + private String mimeType; + + /** + * A list of parameters associated with the resource. + */ + private List params; + + private String configurationURI; + private String secretsURI; + private String namespace; + + /** + * Gets the location of the resource. + * + * @return the resource location (e.g., URL, file path) + */ + public String getLocation() { + return location; + } + + /** + * Sets the location of the resource. + * + * @param location The new location of the resource. + */ + public void setLocation(String location) { + this.location = location; + } + + /** + * Gets the type of the resource. + * + * @return the resource type (e.g., image, text, binary) + */ + public String getType() { + return type; + } + + /** + * Sets the type of the resource. + * + * @param type The new type of the resource. + */ + public void setType(String type) { + this.type = type; + } + + /** + * Gets the brief name of the resource. + * + * @return the resource name + */ + public String getName() { + return name; + } + + /** + * Sets a brief name for the resource. + * + * @param name The new name of the resource. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the longer description of the resource. + * + * @return the resource description + */ + public String getDescription() { + return description; + } + + /** + * Sets a longer description of the resource. + * + * @param description The new description of the resource. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the MIME type of the resource. + * + * @return the MIME type (e.g., image/jpeg, text/plain) + */ + public String getMimeType() { + return mimeType; + } + + /** + * Sets the MIME type of the resource. + * + * @param mimeType The new MIME type of the resource. + */ + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + /** + * Gets the list of parameters associated with the resource. + * + * @return the list of resource parameters + */ + public List getParams() { + return params; + } + + /** + * Sets a list of parameters associated with the resource. + * + * @param params The new list of parameters for the resource. + */ + public void setParams(List params) { + this.params = params; + } + + /** + * Gets the URI location for the resource configuration. + *

+ * The configuration URI points to the location where non-sensitive + * configuration data for this resource is stored. + * + * @return the configuration URI, or {@code null} if not configured + */ + public String getConfigurationURI() { + return configurationURI; + } + + /** + * Sets the URI location for the resource configuration. + * + * @param configurationURI the configuration URI to set + */ + public void setConfigurationURI(String configurationURI) { + this.configurationURI = configurationURI; + } + + /** + * Gets the URI location for the secrets associated with this resource. + *

+ * The secrets URI points to the location where sensitive data such as + * credentials, API keys, or tokens for this resource are stored. + * + * @return the secrets URI, or {@code null} if not configured + */ + public String getSecretsURI() { + return secretsURI; + } + + /** + * Sets the URI location for the secrets associated with this resource. + * + * @param secretsURI the secrets URI to set + */ + public void setSecretsURI(String secretsURI) { + this.secretsURI = secretsURI; + } + + /** + * Gets the namespace in which this resource is registered. + * + * @return the namespace identifier + */ + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace in which this resource is registered. + * + * @param namespace the namespace identifier to set + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + /** + * A nested class representing a parameter of the resource. + */ + public static class Param { + /** + * The name of the parameter (e.g. "key", "value"). + */ + private String name; + + /** + * The value of the parameter. + */ + private String value; + + /** + * Gets the name of the parameter. + * + * @return the parameter name + */ + public String getName() { + return name; + } + + /** + * Sets the name of the parameter. + * + * @param name The new name of the parameter. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the value of the parameter. + * + * @return the parameter value + */ + public String getValue() { + return value; + } + + /** + * Sets the value of the parameter. + * + * @param value The new value of the parameter. + */ + public void setValue(String value) { + this.value = value; + } + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + return "ResourceReference{" + "id='" + + id + '\'' + ", location='" + + location + '\'' + ", type='" + + type + '\'' + ", name='" + + name + '\'' + ", description='" + + description + '\'' + ", mimeType='" + + mimeType + '\'' + ", params=" + + params + ", configurationURI='" + + configurationURI + '\'' + ", secretsURI='" + + secretsURI + '\'' + ", namespace='" + + namespace + '\'' + ", labels='" + + this.getLabels() + '\'' + '}'; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ResourceReference that = (ResourceReference) o; + return Objects.equals(id, that.id) + && Objects.equals(location, that.location) + && Objects.equals(type, that.type) + && Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && Objects.equals(mimeType, that.mimeType) + && Objects.equals(params, that.params) + && Objects.equals(configurationURI, that.configurationURI) + && Objects.equals(secretsURI, that.secretsURI) + && Objects.equals(namespace, that.namespace) + && Objects.equals(this.getLabels(), that.getLabels()); + } + + @Override + public int hashCode() { + return Objects.hash( + id, + location, + type, + name, + description, + mimeType, + params, + configurationURI, + secretsURI, + namespace, + this.getLabels()); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/TextContent.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/TextContent.java new file mode 100644 index 0000000..f394135 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/TextContent.java @@ -0,0 +1,54 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * Represents text content in a prompt message. + * This is the most common content type for prompts. + */ +public class TextContent implements PromptContent { + private static final String TYPE = "text"; + + /** + * The text content. + */ + private String text; + + public TextContent() {} + + public TextContent(String text) { + this.text = text; + } + + @Override + public String getType() { + return TYPE; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + TextContent that = (TextContent) o; + return Objects.equals(text, that.text); + } + + @Override + public int hashCode() { + return Objects.hash(text); + } + + @Override + public String toString() { + return "TextContent{" + "type='" + TYPE + '\'' + ", text='" + text + '\'' + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ToolReference.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ToolReference.java new file mode 100644 index 0000000..663750b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/ToolReference.java @@ -0,0 +1,229 @@ +package ai.wanaku.capabilities.sdk.api.types; + +import java.util.Objects; + +/** + * This class represents a reference to a tool with various attributes such as name, description, URI, type, and input schema. + */ +public class ToolReference extends LabelsAwareEntity implements CallableReference { + private String id; + private String name; + private String description; + private String uri; + private String type; + private InputSchema inputSchema; + private String namespace; + private String configurationURI; + private String secretsURI; + + /** + * Default constructor for ToolReference. + */ + public ToolReference() {} + + /** + * Gets the name of the tool. + * + * @return the name of the tool + */ + @Override + public String getName() { + return name; + } + + /** + * Sets the name of the tool. + * + * @param name the new name of the tool + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets the description of the tool. + * + * @return the description of the tool + */ + @Override + public String getDescription() { + return description; + } + + /** + * Sets the description of the tool. + * + * @param description the new description of the tool + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets the URI of the tool reference. + * + * @return the URI of the tool reference + */ + public String getUri() { + return uri; + } + + /** + * Sets the URI of the tool reference and returns the current object for method chaining. + * + * @param uri the new URI of the tool reference + * @return the current ToolReference object + */ + public ToolReference setUri(String uri) { + this.uri = uri; + return this; + } + + /** + * Gets the type of the tool reference. + * + * @return the type of the tool reference + */ + @Override + public String getType() { + return type; + } + + /** + * Sets the type of the tool reference and returns the current object for method chaining. + * + * @param type the new type of the tool reference + * @return the current ToolReference object + */ + public ToolReference setType(String type) { + this.type = type; + return this; + } + + /** + * Gets the input schema of the tool reference. + * + * @return the input schema of the tool reference + */ + @Override + public InputSchema getInputSchema() { + return inputSchema; + } + + /** + * Sets the input schema of the tool reference. + * + * @param inputSchema the new input schema of the tool reference + */ + public void setInputSchema(InputSchema inputSchema) { + this.inputSchema = inputSchema; + } + + /** + * Gets the namespace in which this tool is registered. + * + * @return the namespace identifier + */ + @Override + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace in which this tool is registered. + * + * @param namespace the namespace identifier to set + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + /** + * Gets the URI location for the tool configuration. + *

+ * The configuration URI points to the location where non-sensitive + * configuration data for this tool is stored. + * + * @return the configuration URI, or {@code null} if not configured + */ + public String getConfigurationURI() { + return configurationURI; + } + + /** + * Sets the URI location for the tool configuration. + * + * @param configurationURI the configuration URI to set + */ + public void setConfigurationURI(String configurationURI) { + this.configurationURI = configurationURI; + } + + /** + * Gets the URI location for the secrets associated with this tool. + *

+ * The secrets URI points to the location where sensitive data such as + * credentials, API keys, or tokens for this tool are stored. + * + * @return the secrets URI, or {@code null} if not configured + */ + public String getSecretsURI() { + return secretsURI; + } + + /** + * Sets the URI location for the secrets associated with this tool. + * + * @param secretsURI the secrets URI to set + */ + public void setSecretsURI(String secretsURI) { + this.secretsURI = secretsURI; + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ToolReference that = (ToolReference) o; + return Objects.equals(id, that.id) + && Objects.equals(name, that.name) + && Objects.equals(description, that.description) + && Objects.equals(uri, that.uri) + && Objects.equals(type, that.type) + && Objects.equals(inputSchema, that.inputSchema) + && Objects.equals(configurationURI, that.configurationURI) + && Objects.equals(secretsURI, that.secretsURI) + && Objects.equals(this.getLabels(), that.getLabels()); + } + + @Override + public int hashCode() { + return Objects.hash( + id, name, description, uri, type, inputSchema, configurationURI, secretsURI, this.getLabels()); + } + + @Override + public String toString() { + return "ToolReference{" + "id='" + + id + '\'' + ", name='" + + name + '\'' + ", description='" + + description + '\'' + ", uri='" + + uri + '\'' + ", type='" + + type + '\'' + ", inputSchema=" + + inputSchema + ", configurations=" + + configurationURI + ", secrets=" + + secretsURI + ", labels='" + + this.getLabels() + '\'' + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuEntity.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuEntity.java new file mode 100644 index 0000000..57a6140 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuEntity.java @@ -0,0 +1,27 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * Base interface for all Wanaku entity types. + *

+ * This interface provides a common contract for entities that require identity management + * within the Wanaku system. All entities implementing this interface must provide an + * identifier of type {@code K}. + * + * @param the type of the entity identifier + */ +public interface WanakuEntity { + + /** + * Gets the unique identifier for this entity. + * + * @return the entity identifier, or {@code null} if not yet assigned + */ + K getId(); + + /** + * Sets the unique identifier for this entity. + * + * @param id the entity identifier to set + */ + void setId(K id); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuError.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuError.java new file mode 100644 index 0000000..f1cd0ad --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuError.java @@ -0,0 +1,26 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * Represents an error response from the Wanaku API or services. + *

+ * This immutable record encapsulates error information that is returned to clients + * when API operations fail or encounter errors. It provides a simple, standardized + * way to communicate error details across the Wanaku system. + *

+ * The error message should be descriptive and provide enough context for clients + * to understand what went wrong and potentially take corrective action. + * + * @param message the error message describing what went wrong, or {@code null} if no message is available + */ +public record WanakuError(String message) { + + /** + * Default constructor that creates a {@link WanakuError} with no message. + *

+ * This constructor is provided for cases where an error indicator is needed + * but no specific message is available at the time of creation. + */ + public WanakuError() { + this(null); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuResponse.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuResponse.java new file mode 100644 index 0000000..e563ccd --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/WanakuResponse.java @@ -0,0 +1,36 @@ +package ai.wanaku.capabilities.sdk.api.types; + +/** + * Represents a Wanaku response, which can contain either an error or data. + * + * @param The type of the data in the response. + * @param error An optional error to include in the response + * @param data The data to include in the response. + */ +public record WanakuResponse(WanakuError error, T data) { + + /** + * Creates a new Wanaku response with no error and no data. + */ + public WanakuResponse() { + this(null, null); + } + + /** + * Creates a new Wanaku response with the given error message and no data. + * + * @param error The error message to include in the response. + */ + public WanakuResponse(String error) { + this(new WanakuError(error), null); + } + + /** + * Creates a new Wanaku response with no error and the given data. + * + * @param data The data to include in the response. + */ + public WanakuResponse(T data) { + this(null, data); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ActivityRecord.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ActivityRecord.java new file mode 100644 index 0000000..89a8575 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ActivityRecord.java @@ -0,0 +1,129 @@ +package ai.wanaku.capabilities.sdk.api.types.discovery; + +import ai.wanaku.capabilities.sdk.api.types.WanakuEntity; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Records the activity and health status of a service in the Wanaku system. + *

+ * This entity tracks service lifecycle information including when the service was last + * observed, its current active status, and a history of state transitions. Activity records + * are used by the service discovery mechanism to monitor service health and availability. + */ +public class ActivityRecord implements WanakuEntity { + private String id; + private Instant lastSeen; + private boolean active; + private List states = new ArrayList<>(); + + /** + * Default constructor for ActivityRecord. + */ + public ActivityRecord() {} + + /** + * Gets the unique identifier for this activity record. + * + * @return the activity record identifier + */ + @Override + public String getId() { + return id; + } + + /** + * Sets the unique identifier for this activity record. + * + * @param id the activity record identifier to set + */ + @Override + public void setId(String id) { + this.id = id; + } + + /** + * Gets the timestamp when this service was last observed as active. + * + * @return the last seen timestamp, or {@code null} if never observed + */ + public Instant getLastSeen() { + return lastSeen; + } + + /** + * Sets the timestamp when this service was last observed as active. + * + * @param lastSeen the last seen timestamp to set + */ + public void setLastSeen(Instant lastSeen) { + this.lastSeen = lastSeen; + } + + /** + * Checks whether the service is currently active. + * + * @return {@code true} if the service is active, {@code false} otherwise + */ + public boolean isActive() { + return active; + } + + /** + * Sets the active status of the service. + * + * @param active {@code true} to mark the service as active, {@code false} otherwise + */ + public void setActive(boolean active) { + this.active = active; + } + + /** + * Gets the list of state transitions for this service. + *

+ * The states list maintains a history of service state changes, allowing + * tracking of service health and availability over time. + * + * @return the list of service states + */ + public List getStates() { + return states; + } + + /** + * Sets the list of state transitions for this service. + * + * @param states the list of service states to set + */ + public void setStates(List states) { + this.states = states; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ActivityRecord that = (ActivityRecord) o; + return active == that.active + && Objects.equals(id, that.id) + && Objects.equals(lastSeen, that.lastSeen) + && Objects.equals(states, that.states); + } + + @Override + public int hashCode() { + return Objects.hash(id, lastSeen, active, states); + } + + @Override + public String toString() { + return "ActivityRecord{" + "id='" + + id + '\'' + ", lastSeen=" + + lastSeen + ", active=" + + active + ", states=" + + states + '}'; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ServiceState.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ServiceState.java new file mode 100644 index 0000000..b6003d4 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/ServiceState.java @@ -0,0 +1,98 @@ +package ai.wanaku.capabilities.sdk.api.types.discovery; + +import java.time.Instant; +import java.util.Objects; + +/** + * Contains the state of the service for an specific point in time + */ +public class ServiceState { + private Instant timestamp; + private boolean healthy; + private String reason; + + public ServiceState() {} + + /** + * Saves the current state of the service + * @param timestamp the current timestamp + * @param healthy whether it is healthy (true for healthy, false otherwise) + * @param reason Optional state message (ignored if healthy) + */ + public ServiceState(Instant timestamp, boolean healthy, String reason) { + this.timestamp = timestamp; + this.healthy = healthy; + this.reason = reason; + } + + /** + * Gets the timestamp when this service state was recorded. + * + * @return the timestamp + */ + public Instant getTimestamp() { + return timestamp; + } + + /** + * Sets the timestamp when this service state was recorded. + * + * @param timestamp the timestamp to set + */ + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + public boolean isHealthy() { + return healthy; + } + + public void setHealthy(boolean healthy) { + this.healthy = healthy; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceState that = (ServiceState) o; + return healthy == that.healthy + && Objects.equals(timestamp, that.timestamp) + && Objects.equals(reason, that.reason); + } + + @Override + public int hashCode() { + return Objects.hash(timestamp, healthy, reason); + } + + @Override + public String toString() { + return "ServiceState{" + "timestamp=" + timestamp + ", healthy=" + healthy + ", reason='" + reason + '\'' + '}'; + } + + public static ServiceState newHealthy() { + return new ServiceState(Instant.now(), true, StandardMessages.HEALTHY); + } + + public static ServiceState newUnhealthy(String reason) { + return new ServiceState(Instant.now(), false, reason); + } + + public static ServiceState newMissingInAction() { + return new ServiceState(Instant.now(), false, StandardMessages.MISSING_IN_ACTION); + } + + public static ServiceState newInactive() { + return new ServiceState(Instant.now(), true, StandardMessages.AUTO_DEREGISTRATION); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/StandardMessages.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/StandardMessages.java new file mode 100644 index 0000000..1f7e11a --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/StandardMessages.java @@ -0,0 +1,28 @@ +package ai.wanaku.capabilities.sdk.api.types.discovery; + +/** + * Standard status messages used in the service discovery and health monitoring system. + *

+ * This utility class defines constant messages that represent common service states + * within the Wanaku discovery mechanism. These messages are used to communicate + * service health and availability status. + */ +public final class StandardMessages { + /** + * Message indicating that a service is operating normally and is healthy. + */ + public static final String HEALTHY = "healthy"; + + /** + * Message indicating that a service has not been observed within the expected timeframe + * and may be unavailable. + */ + public static final String MISSING_IN_ACTION = "missing in action"; + + /** + * Message indicating that a service has been automatically deregistered due to inactivity. + */ + public static final String AUTO_DEREGISTRATION = "inactive due to service auto-deregistration"; + + private StandardMessages() {} +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/package-info.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/package-info.java new file mode 100644 index 0000000..d28c6f5 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/discovery/package-info.java @@ -0,0 +1,18 @@ +/** + * Service discovery and health monitoring types. + *

+ * This package contains types used for service discovery, health monitoring, + * and activity tracking within the Wanaku system. These types enable the + * router to discover available capability providers and monitor their + * health and availability over time. + *

+ * Key types include: + *

    + *
  • {@link ai.wanaku.api.types.discovery.ActivityRecord} - Service activity and health records
  • + *
  • {@link ai.wanaku.api.types.discovery.ServiceState} - Service state information
  • + *
  • {@link ai.wanaku.api.types.discovery.StandardMessages} - Standard status messages
  • + *
+ * + * @see ai.wanaku.api.types + */ +package ai.wanaku.capabilities.sdk.api.types.discovery; diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/PromptPayload.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/PromptPayload.java new file mode 100644 index 0000000..376cc0b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/PromptPayload.java @@ -0,0 +1,39 @@ +package ai.wanaku.capabilities.sdk.api.types.io; + +import ai.wanaku.capabilities.sdk.api.types.PromptReference; + +/** + * Represents a payload for prompt operations that may require provisioning. + */ +public final class PromptPayload implements ProvisionAwarePayload { + private PromptReference promptReference; + private String configurationData; + private String secretsData; + + @Override + public PromptReference getPayload() { + return promptReference; + } + + public void setPayload(PromptReference promptReference) { + this.promptReference = promptReference; + } + + @Override + public String getConfigurationData() { + return configurationData; + } + + public void setConfigurationData(String configurationData) { + this.configurationData = configurationData; + } + + @Override + public String getSecretsData() { + return secretsData; + } + + public void setSecretsData(String secretsData) { + this.secretsData = secretsData; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ProvisionAwarePayload.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ProvisionAwarePayload.java new file mode 100644 index 0000000..d064fd4 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ProvisionAwarePayload.java @@ -0,0 +1,49 @@ +package ai.wanaku.capabilities.sdk.api.types.io; + +/** + * Interface for payloads that carry provisioning information. + *

+ * This interface defines the contract for payloads that bundle together a primary + * payload object (such as a tool or resource reference) along with associated + * configuration and secrets data needed for provisioning and deployment. + *

+ * Implementations of this interface are used during capability provisioning to + * ensure that all necessary configuration and sensitive data are transmitted + * together with the capability reference. + * + * @param the type of the primary payload object + */ +public interface ProvisionAwarePayload { + + /** + * Gets the primary payload object. + *

+ * This typically contains the reference to a tool, resource, or other capability + * being provisioned. + * + * @return the payload object + */ + T getPayload(); + + /** + * Gets the configuration data associated with this payload. + *

+ * Configuration data contains non-sensitive settings and parameters required + * for provisioning the capability. The format and content are specific to the + * type of capability being provisioned. + * + * @return the configuration data as a string, or {@code null} if no configuration is provided + */ + String getConfigurationData(); + + /** + * Gets the secrets data associated with this payload. + *

+ * Secrets data contains sensitive information such as credentials, API keys, + * or tokens required for provisioning the capability. This data should be + * handled securely and not logged or persisted in plain text. + * + * @return the secrets data as a string, or {@code null} if no secrets are provided + */ + String getSecretsData(); +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ResourcePayload.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ResourcePayload.java new file mode 100644 index 0000000..b433232 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ResourcePayload.java @@ -0,0 +1,80 @@ +package ai.wanaku.capabilities.sdk.api.types.io; + +import ai.wanaku.capabilities.sdk.api.types.ResourceReference; + +/** + * Payload for provisioning resource capabilities with associated configuration and secrets. + *

+ * This class bundles a {@link ResourceReference} with its corresponding configuration + * and secrets data, facilitating the complete provisioning of a resource capability + * within the Wanaku system. + *

+ * The payload includes: + *

    + *
  • A resource reference that identifies and describes the resource
  • + *
  • Configuration data with non-sensitive settings
  • + *
  • Secrets data with sensitive credentials or tokens
  • + *
+ */ +public class ResourcePayload implements ProvisionAwarePayload { + private ResourceReference resourceReference; + private String configurationData; + private String secretsData; + + /** + * Gets the resource reference contained in this payload. + * + * @return the resource reference + */ + @Override + public ResourceReference getPayload() { + return resourceReference; + } + + /** + * Sets the resource reference for this payload. + * + * @param resourceReference the resource reference to set + */ + public void setPayload(ResourceReference resourceReference) { + this.resourceReference = resourceReference; + } + + /** + * Gets the configuration data for provisioning this resource. + * + * @return the configuration data, or {@code null} if not provided + */ + @Override + public String getConfigurationData() { + return configurationData; + } + + /** + * Sets the configuration data for provisioning this resource. + * + * @param configurationData the configuration data to set + */ + public void setConfigurationData(String configurationData) { + this.configurationData = configurationData; + } + + /** + * Gets the secrets data required for provisioning this resource. + * + * @return the secrets data, or {@code null} if not provided + */ + @Override + public String getSecretsData() { + return secretsData; + } + + /** + * Sets the secrets data required for provisioning this resource. + * + * @param secretsData the secrets data to set + */ + public void setSecretsData(String secretsData) { + this.secretsData = secretsData; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ToolPayload.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ToolPayload.java new file mode 100644 index 0000000..0be0506 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/ToolPayload.java @@ -0,0 +1,80 @@ +package ai.wanaku.capabilities.sdk.api.types.io; + +import ai.wanaku.capabilities.sdk.api.types.ToolReference; + +/** + * Payload for provisioning tool capabilities with associated configuration and secrets. + *

+ * This class bundles a {@link ToolReference} with its corresponding configuration + * and secrets data, facilitating the complete provisioning of a tool capability + * within the Wanaku system. + *

+ * The payload includes: + *

    + *
  • A tool reference that identifies and describes the tool
  • + *
  • Configuration data with non-sensitive settings
  • + *
  • Secrets data with sensitive credentials or tokens
  • + *
+ */ +public final class ToolPayload implements ProvisionAwarePayload { + private ToolReference toolReference; + private String configurationData; + private String secretsData; + + /** + * Gets the tool reference contained in this payload. + * + * @return the tool reference + */ + @Override + public ToolReference getPayload() { + return toolReference; + } + + /** + * Sets the tool reference for this payload. + * + * @param toolReference the tool reference to set + */ + public void setPayload(ToolReference toolReference) { + this.toolReference = toolReference; + } + + /** + * Gets the configuration data for provisioning this tool. + * + * @return the configuration data, or {@code null} if not provided + */ + @Override + public String getConfigurationData() { + return configurationData; + } + + /** + * Sets the configuration data for provisioning this tool. + * + * @param configurationData the configuration data to set + */ + public void setConfigurationData(String configurationData) { + this.configurationData = configurationData; + } + + /** + * Gets the secrets data required for provisioning this tool. + * + * @return the secrets data, or {@code null} if not provided + */ + @Override + public String getSecretsData() { + return secretsData; + } + + /** + * Sets the secrets data required for provisioning this tool. + * + * @param secretsData the secrets data to set + */ + public void setSecretsData(String secretsData) { + this.secretsData = secretsData; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/package-info.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/package-info.java new file mode 100644 index 0000000..c4475ad --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/io/package-info.java @@ -0,0 +1,18 @@ +/** + * Input/Output payload types for capability provisioning. + *

+ * This package contains payload classes used for transmitting capabilities + * along with their associated configuration and secrets data. These payloads + * facilitate the complete provisioning of tools and resources, ensuring that + * all necessary configuration and sensitive data are bundled together. + *

+ * Key types include: + *

    + *
  • {@link ai.wanaku.api.types.io.ProvisionAwarePayload} - Interface for provisioning payloads
  • + *
  • {@link ai.wanaku.api.types.io.ToolPayload} - Tool provisioning payload
  • + *
  • {@link ai.wanaku.api.types.io.ResourcePayload} - Resource provisioning payload
  • + *
+ * + * @see ai.wanaku.api.types + */ +package ai.wanaku.capabilities.sdk.api.types.io; diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/management/ServerInfo.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/management/ServerInfo.java new file mode 100644 index 0000000..9772e66 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/management/ServerInfo.java @@ -0,0 +1,33 @@ +package ai.wanaku.capabilities.sdk.api.types.management; + +/** + * Contains server information, such as the version of the server. + * + * This class encapsulates essential details about the server, making it + * easy to access its configuration. + */ +public class ServerInfo { + + /** + * The version of the server software or platform running on this instance. + */ + private String version; + + /** + * Returns the current version of the server. + * + * @return The server version as a string. + */ + public String getVersion() { + return version; + } + + /** + * Sets the version of the server to a new value. + * + * @param version The updated server version as a string. + */ + public void setVersion(String version) { + this.version = version; + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/package-info.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/package-info.java new file mode 100644 index 0000000..729853b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/package-info.java @@ -0,0 +1,22 @@ +/** + * Core type definitions and data models for the Wanaku system. + *

+ * This package contains the fundamental data structures used throughout Wanaku, + * including entity types for capabilities, tools, resources, namespaces, and + * their associated metadata. These types form the foundation of the Wanaku + * API and are used for data exchange between components. + *

+ * Key types include: + *

    + *
  • {@link ai.wanaku.capabilities.sdk.api.types.WanakuEntity} - Base interface for all entities
  • + *
  • {@link ai.wanaku.capabilities.sdk.api.types.ToolReference} - Tool capability references
  • + *
  • {@link ai.wanaku.capabilities.sdk.api.types.ResourceReference} - Resource capability references
  • + *
  • {@link ai.wanaku.capabilities.sdk.api.types.ForwardReference} - Forward proxy references
  • + *
  • {@link ai.wanaku.capabilities.sdk.api.types.Namespace} - Namespace entities for logical grouping
  • + *
  • {@link ai.wanaku.capabilities.sdk.api.types.NameNamespacePair} - Name-namespace identifier pairs
  • + *
+ * + * @see ai.wanaku.capabilities.api.types.io + * @see ai.wanaku.capabilities.api.types.discovery + */ +package ai.wanaku.capabilities.sdk.api.types; diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceTarget.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceTarget.java new file mode 100644 index 0000000..679b699 --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceTarget.java @@ -0,0 +1,136 @@ +package ai.wanaku.capabilities.sdk.api.types.providers; + +import ai.wanaku.capabilities.sdk.api.types.WanakuEntity; +import java.util.Objects; + +/** + * Represents a target service endpoint that can be either a resource provider or a tool invoker. + * + * This class encapsulates information about a service, including its target and configurations, + * providing a structured way to represent and manage services in a system. + */ +public class ServiceTarget implements WanakuEntity { + private String id; + private String service; + private String host; + private int port; + private ServiceType serviceType; + + /** + * Default constructor for ServiceTarget. + */ + public ServiceTarget() {} + + /** + * Constructs a new instance of {@link ServiceTarget}. + * + * @param id The unique identifier for the service. + * @param service The name of the service. + * @param host The host address of the service. + * @param port The port number of the service. + * @param serviceType The type of service, either RESOURCE_PROVIDER or TOOL_INVOKER. + */ + public ServiceTarget(String id, String service, String host, int port, ServiceType serviceType) { + this.id = id; + this.service = service; + this.host = host; + this.port = port; + this.serviceType = serviceType; + } + + /** + * Gets the name of the service. + * + * @return The name of the service. + */ + public String getService() { + return service; + } + + /** + * Gets the host address of the service. + * + * @return The host address of the service. + */ + public String getHost() { + return host; + } + + /** + * Gets the port number of the service. + * + * @return The port number of the service. + */ + public int getPort() { + return port; + } + + /** + * Gets the type of service, either RESOURCE_PROVIDER or TOOL_INVOKER. + * + * @return The type of service. + */ + public ServiceType getServiceType() { + return serviceType; + } + + /** + * Returns a string representation of the service address in the format "host:port". + * + * @return A string representation of the service address. + */ + public String toAddress() { + return String.format("%s:%d", host, port); + } + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceTarget that = (ServiceTarget) o; + return port == that.port + && Objects.equals(id, that.id) + && Objects.equals(service, that.service) + && Objects.equals(host, that.host) + && serviceType == that.serviceType; + } + + @Override + public int hashCode() { + return Objects.hash(id, service, host, port, serviceType); + } + + @Override + public String toString() { + return "ServiceTarget{" + "id='" + + id + '\'' + ", service='" + + service + '\'' + ", host='" + + host + '\'' + ", port=" + + port + ", serviceType=" + + serviceType + '}'; + } + + /** + * Creates a new instance of {@link ServiceTarget} with the specified parameters with the given service type. + * + * @param service The name of the service. + * @param address The host address of the service. + * @param port The port number of the service. + * @param serviceType The type of service (RESOURCE_PROVIDER, TOOL_INVOKER, or MULTI_CAPABILITY). + * @return A new instance of {@link ServiceTarget}. + */ + public static ServiceTarget newEmptyTarget(String service, String address, int port, ServiceType serviceType) { + return new ServiceTarget(null, service, address, port, serviceType); + } +} diff --git a/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceType.java b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceType.java new file mode 100644 index 0000000..868d10b --- /dev/null +++ b/capabilities-api/src/main/java/ai/wanaku/capabilities/sdk/api/types/providers/ServiceType.java @@ -0,0 +1,68 @@ +package ai.wanaku.capabilities.sdk.api.types.providers; + +/** + * Defines types of downstream services + */ +public enum ServiceType { + /** + * Provides resources + */ + RESOURCE_PROVIDER("resource-provider", 1), + + /** + * Invokes tools + */ + TOOL_INVOKER("tool-invoker", 2), + + /** + * This can do both: invoke tools and provide resources + */ + MULTI_CAPABILITY("multi-capability", 3); + + private final String value; + private final int intValue; + + ServiceType(String value, int intValue) { + this.value = value; + this.intValue = intValue; + } + + /** + * The string value representing the service type + * @return the string value representing the service type + */ + public String asValue() { + return value; + } + + /** + * Gets the integer value representing this service type. + * + * @return the integer value + */ + public int intValue() { + return intValue; + } + + /** + * Converts an integer value to the corresponding ServiceType. + * + * @param value the integer value (1 for RESOURCE_PROVIDER, 2 for TOOL_INVOKER, 3 for MULTI_CAPABILITY) + * @return the corresponding ServiceType + * @throws IllegalArgumentException if the value does not correspond to any ServiceType + */ + public static ServiceType fromIntValue(int value) { + if (value == 1) { + return RESOURCE_PROVIDER; + } + if (value == 2) { + return TOOL_INVOKER; + } + + if (value == 3) { + return MULTI_CAPABILITY; + } + + throw new IllegalArgumentException("Invalid service type: " + value); + } +} diff --git a/capabilities-api/src/main/resources/META-INF/beans.xml b/capabilities-api/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..e69de29 diff --git a/capabilities-bom/pom.xml b/capabilities-bom/pom.xml index 9fd6e2e..6a54896 100644 --- a/capabilities-bom/pom.xml +++ b/capabilities-bom/pom.xml @@ -16,6 +16,11 @@ + + ai.wanaku.sdk + capabilities-api + ${project.version} + ai.wanaku.sdk capabilities-common @@ -31,6 +36,16 @@ capabilities-data-files ${project.version} + + ai.wanaku.sdk + capabilities-config-provider-api + ${project.version} + + + ai.wanaku.sdk + capabilities-config-provider-file + ${project.version} + ai.wanaku.sdk capabilities-exchange diff --git a/capabilities-common/pom.xml b/capabilities-common/pom.xml index 0110e2f..192656f 100644 --- a/capabilities-common/pom.xml +++ b/capabilities-common/pom.xml @@ -17,7 +17,12 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-databind.version} + + + + ai.wanaku.sdk + capabilities-api + ${project.version} diff --git a/capabilities-common/src/main/java/ai/wanaku/capabilities/sdk/common/exceptions/WanakuWebException.java b/capabilities-common/src/main/java/ai/wanaku/capabilities/sdk/common/exceptions/WanakuWebException.java index d01d2e2..4bf0dd6 100644 --- a/capabilities-common/src/main/java/ai/wanaku/capabilities/sdk/common/exceptions/WanakuWebException.java +++ b/capabilities-common/src/main/java/ai/wanaku/capabilities/sdk/common/exceptions/WanakuWebException.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.common.exceptions; -import ai.wanaku.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; /** * Exception thrown when web-related operations fail in the Wanaku capabilities SDK. diff --git a/capabilities-config-providers/capabilities-config-provider-api/pom.xml b/capabilities-config-providers/capabilities-config-provider-api/pom.xml new file mode 100644 index 0000000..3a5935f --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + ai.wanaku.sdk + capabilities-config-providers + 0.0.9-SNAPSHOT + + + capabilities-config-provider-api + Wanaku Capabilities SDK :: Config Providers :: Config Provider :: API + + + + ai.wanaku.sdk + capabilities-api + ${project.version} + + + + \ No newline at end of file diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigProvisioner.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigProvisioner.java new file mode 100644 index 0000000..12d35cf --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigProvisioner.java @@ -0,0 +1,44 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.net.URI; + +/** + * A base interface for provisioning new configurations and secrets for a tool. + * Implementations of this interface are responsible for handling the storage + * of configuration data and sensitive secret information, typically returning + * a {@link URI} that points to the location of the provisioned data. + */ +public interface ConfigProvisioner { + + /** + * Provisions a new configuration for a tool. + * This method takes an identifier and the configuration data as a string, + * and is expected to store this configuration in a persistent or accessible manner. + * + * @param id The unique identifier for the configuration. + * @param data The configuration data as a String. The format of this data + * (e.g., JSON, YAML, properties) depends on the specific + * implementation and the tool's requirements. + * @return A {@link URI} pointing to the location where the configuration has been provisioned. + * This URI could be a file path, a URL to a remote service, or any other + * scheme relevant to the provisioning mechanism. + * @throws ProvisioningException If an error occurs during the provisioning process. + */ + URI provisionConfiguration(String id, String data); + + /** + * Provisions a new secret for a tool. + * This method is similar to {@link #provisionConfiguration(String, String)} but is + * specifically for sensitive data (secrets) that may require different + * storage, encryption, or access control mechanisms. + * + * @param id The unique identifier for the secret. + * @param data The secret data as a String. It is highly recommended that + * implementations handle this data securely (e.g., encryption at rest). + * @return A {@link URI} pointing to the location where the secret has been provisioned. + * Similar to configurations, this URI's scheme depends on the + * specific provisioning mechanism. + * @throws ProvisioningException If an error occurs during the provisioning process. + */ + URI provisionSecret(String id, String data); +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigResource.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigResource.java new file mode 100644 index 0000000..c19fbb8 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigResource.java @@ -0,0 +1,68 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.Map; + +/** + * Represents a resource that provides access to both configurations and secrets. + * This interface combines functionalities typically found in a {@link ConfigStore} + * and a {@link SecretStore}, allowing unified access to various types of sensitive and non-sensitive data. + */ +public interface ConfigResource { + + /** + * Retrieves all available configuration entries. + * + * @return A {@link Map} where keys are configuration names (Strings) and values are + * their corresponding String representations. Returns an empty map if no configurations are found. + */ + Map getConfigs(); + + /** + * Retrieves configuration entries that start with a given prefix. + * This is useful for grouping and fetching related configurations, such as all settings for a specific module. + * + * @param prefix The prefix to filter configuration names by. Must not be null. + * @return A {@link Map} containing configuration entries whose names start with the specified prefix. + * Keys are configuration names and values are their corresponding String representations. + * Returns an empty map if no configurations match the prefix. + */ + Map getConfigs(String prefix); + + /** + * Retrieves the configuration entry associated with the given key. + * + * @param key The exact key of the configuration entry to retrieve. Must not be null. + * @return The String value of the configuration entry, or {@code null} if no entry + * with the specified key is found. + */ + String getConfig(String key); + + /** + * Retrieves all available secret entries. + * Secrets are typically sensitive data like API keys, database credentials, etc. + * + * @return A {@link Map} where keys are secret names (Strings) and values are + * their corresponding String representations. Returns an empty map if no secrets are found. + */ + Map getSecrets(); + + /** + * Retrieves all available secret entries that start with a given prefix. + * Secrets are typically sensitive data like API keys, database credentials, etc. + * This is useful for grouping and fetching related configurations, such as all settings for a specific module. + * + * @param prefix The prefix to filter configuration names by. Must not be null. + * @return A {@link Map} where keys are secret names (Strings) and values are + * their corresponding String representations. Returns an empty map if no secrets are found. + */ + Map getSecrets(String prefix); + + /** + * Retrieves the secret entry associated with the given key. + * + * @param key The exact key of the secret entry to retrieve. Must not be null. + * @return The String value of the secret entry, or {@code null} if no secret + * with the specified key is found. + */ + String getSecret(String key); +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigStore.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigStore.java new file mode 100644 index 0000000..4b7dd3c --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigStore.java @@ -0,0 +1,39 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.Map; + +/** + * A config store abstracts the actual store where the configs are located. + * Implementations of this interface provide methods for retrieving configuration entries + * from various underlying storage mechanisms. + */ +public interface ConfigStore { + + /** + * Retrieves all configuration entries from the store. + * + * @return A {@link Map} where keys are configuration names (Strings) and values are + * their corresponding String representations. If no entries are found, an empty map is returned. + */ + Map getEntries(); + + /** + * Retrieves configuration entries that start with a given prefix. + * This can be useful for fetching related configurations, e.g., all database-related settings. + * + * @param prefix The prefix to filter configuration names by. Must not be null. + * @return A {@link Map} containing configuration entries whose names start with the specified prefix. + * Keys are configuration names and values are their corresponding String representations. + * If no entries match the prefix, an empty map is returned. + */ + Map getEntries(String prefix); + + /** + * Retrieves the configuration entry associated with the given name. + * + * @param name The exact name of the configuration entry to retrieve. Must not be null. + * @return The String value of the configuration entry, or {@code null} if no entry + * with the specified name is found. + */ + String get(String name); +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriteException.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriteException.java new file mode 100644 index 0000000..1bcd049 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriteException.java @@ -0,0 +1,30 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; + +/** + * Exception thrown to indicate an error during the process of writing configuration data. + * This exception typically wraps lower-level exceptions that occur due to I/O issues, + * permission problems, or data formatting errors when attempting to persist + * configuration information. + */ +public class ConfigWriteException extends WanakuException { + public ConfigWriteException() {} + + public ConfigWriteException(String message) { + super(message); + } + + public ConfigWriteException(String message, Throwable cause) { + super(message, cause); + } + + public ConfigWriteException(Throwable cause) { + super(cause); + } + + public ConfigWriteException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriter.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriter.java new file mode 100644 index 0000000..f1409f5 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ConfigWriter.java @@ -0,0 +1,29 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.net.URI; + +/** + * An interface for writing configuration data. + * Implementations of this interface are responsible for persisting or otherwise + * making available configuration data identified by a unique ID. + */ +public interface ConfigWriter { + + /** + * Writes configuration data to a destination. + * The specific destination and mechanism for writing are determined by the + * implementing class. + * + * @param id The unique identifier for the configuration data. This ID can be used + * by the implementation to determine the storage location or naming convention. + * @param data The actual configuration data as a String. The format of this string + * (e.g., JSON, XML, plain text) is dependent on the specific usage + * and the expectations of the system consuming the configuration. + * @return A {@link URI} representing the location or identifier of the written + * configuration data. This URI can be used later to access or reference + * the stored configuration. + * @throws ConfigWriteException If an error occurs during the writing process, + * such as an I/O error, permission issue, or invalid data. + */ + URI write(String id, String data); +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigProvisioner.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigProvisioner.java new file mode 100644 index 0000000..6c54a23 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigProvisioner.java @@ -0,0 +1,39 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.net.URI; + +/** + * Default implementation of the {@link ConfigProvisioner} interface. + * This class uses a {@link ConfigWriter} to provision configurations + * and a {@link SecretWriter} to provision secrets. It acts as a simple + * delegator, passing the provisioning requests directly to the + * respective writer implementations. + */ +public class DefaultConfigProvisioner implements ConfigProvisioner { + private final ConfigWriter configWriter; + private final SecretWriter secretWriter; + + /** + * Constructs a new {@code DefaultConfigProvisioner} with the specified + * {@link ConfigWriter} and {@link SecretWriter}. + * + * @param configWriter The {@link ConfigWriter} to use for provisioning configurations. + * Must not be {@code null}. + * @param secretWriter The {@link SecretWriter} to use for provisioning secrets. + * Must not be {@code null}. + */ + public DefaultConfigProvisioner(ConfigWriter configWriter, SecretWriter secretWriter) { + this.configWriter = configWriter; + this.secretWriter = secretWriter; + } + + @Override + public URI provisionConfiguration(String id, String data) { + return configWriter.write(id, data); + } + + @Override + public URI provisionSecret(String id, String data) { + return secretWriter.write(id, data); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigResource.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigResource.java new file mode 100644 index 0000000..2645277 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/DefaultConfigResource.java @@ -0,0 +1,54 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.Map; + +/** + * A default implementation of the {@link ConfigResource} interface. + * This class aggregates a {@link ConfigStore} and a {@link SecretStore} to provide a unified + * interface for accessing both configurations and secrets. + */ +public class DefaultConfigResource implements ConfigResource { + private final ConfigStore configStore; + private final SecretStore secretStore; + + /** + * Constructs a new {@link DefaultConfigResource} with the specified configuration and secret stores. + * + * @param configStore The {@link ConfigStore} to use for retrieving configurations. Must not be null. + * @param secretStore The {@link SecretStore} to use for retrieving secrets. Must not be null. + */ + public DefaultConfigResource(ConfigStore configStore, SecretStore secretStore) { + this.configStore = configStore; + this.secretStore = secretStore; + } + + @Override + public Map getConfigs() { + return configStore.getEntries(); + } + + @Override + public Map getConfigs(String prefix) { + return configStore.getEntries(prefix); + } + + @Override + public String getConfig(String key) { + return configStore.get(key); + } + + @Override + public Map getSecrets() { + return secretStore.getEntries(); + } + + @Override + public Map getSecrets(String prefix) { + return secretStore.getEntries(prefix); + } + + @Override + public String getSecret(String key) { + return secretStore.get(key); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopConfigStore.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopConfigStore.java new file mode 100644 index 0000000..4ec4f79 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopConfigStore.java @@ -0,0 +1,27 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.Map; + +/** + * A no-operation implementation of {@link ConfigStore} that returns empty results. + *

+ * This implementation is useful as a default or placeholder when no actual + * configuration storage is available or needed. All methods return empty + * maps or empty strings rather than null values. + */ +public class NoopConfigStore implements ConfigStore { + @Override + public Map getEntries() { + return Map.of(); + } + + @Override + public Map getEntries(String prefix) { + return Map.of(); + } + + @Override + public String get(String name) { + return ""; + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopSecretStore.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopSecretStore.java new file mode 100644 index 0000000..dbad901 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/NoopSecretStore.java @@ -0,0 +1,13 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +/** + * A no-operation implementation of {@link SecretStore} that returns empty results. + *

+ * This implementation extends {@link NoopConfigStore} to provide the same + * no-operation behavior for secret storage. It is useful as a default or + * placeholder when no actual secret storage is available or needed. + * + * @see NoopConfigStore + * @see SecretStore + */ +public class NoopSecretStore extends NoopConfigStore implements SecretStore {} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyBasedStore.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyBasedStore.java new file mode 100644 index 0000000..7d22f4b --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyBasedStore.java @@ -0,0 +1,50 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.stream.Collectors; + +/** + * An abstract base class for {@link ConfigStore} implementations that retrieve configurations from a + * {@link Properties} object. + * This class handles the common logic for accessing properties, providing a foundation for + * concrete property-based configuration stores. + */ +public abstract class PropertyBasedStore implements ConfigStore { + + protected final Properties properties; + + /** + * Constructs a new {@link PropertyBasedStore} with the given {@link PropertyProvider}. + * The properties are loaded from the provider during construction. + * + * @param propertyProvider The provider from which to obtain the {@link Properties} object. + * Must not be {@code null}. + */ + protected PropertyBasedStore(PropertyProvider propertyProvider) { + this.properties = propertyProvider.getProperties(); + } + + @Override + public Map getEntries() { + Map map = new HashMap<>(); + + properties.forEach((key, value) -> map.put(key.toString(), value.toString())); + return map; + } + + @Override + public Map getEntries(String prefix) { + final Map configs = properties.entrySet().stream() + .filter(e -> e.getKey().toString().startsWith(prefix)) + .collect(Collectors.toMap( + e -> e.getKey().toString(), e -> e.getValue().toString())); + return configs; + } + + @Override + public String get(String name) { + return properties.getProperty(name); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyProvider.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyProvider.java new file mode 100644 index 0000000..b17539d --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/PropertyProvider.java @@ -0,0 +1,19 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.util.Properties; + +/** + * A provider of properties. + * This interface is designed for use with property-based stores; refer to the {@link PropertyBasedStore} class + * for more details on its application within such contexts. + */ +public interface PropertyProvider { + + /** + * Retrieves a {@link Properties} object containing key-value pairs. + * + * @return A {@link Properties} object. Returns an empty {@link Properties} object if no properties are available. + * Never returns {@code null}. + */ + Properties getProperties(); +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisionedConfig.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisionedConfig.java new file mode 100644 index 0000000..b046821 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisionedConfig.java @@ -0,0 +1,19 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import java.net.URI; + +/** + * Represents the result of a provisioning operation, encapsulating the URIs + * where the configurations and secrets have been provisioned. + * This record provides an immutable way to hold the locations of both + * configuration data and sensitive secret data after they have been + * successfully provisioned by a {@link ConfigProvisioner}. + * + * @param configurationsUri The {@link URI} pointing to the location of the provisioned configurations. + * This may be {@code null} if no configurations were provisioned or if + * the operation did not yield a specific URI for configurations. + * @param secretsUri The {@link URI} pointing to the location of the provisioned secrets. + * This may be {@code null} if no secrets were provisioned or if + * the operation did not yield a specific URI for secrets. + */ +public record ProvisionedConfig(URI configurationsUri, URI secretsUri) {} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisioningException.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisioningException.java new file mode 100644 index 0000000..8254550 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ProvisioningException.java @@ -0,0 +1,31 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; + +/** + * Exception thrown to indicate an error during the provisioning process. + * This exception is typically used when an operation to set up or supply + * a new configuration, secret, or other resource fails. It can wrap + * lower-level exceptions such as I/O errors, network issues, or + * problems with external systems involved in the provisioning. + */ +public class ProvisioningException extends WanakuException { + public ProvisioningException() {} + + public ProvisioningException(String message) { + super(message); + } + + public ProvisioningException(String message, Throwable cause) { + super(message, cause); + } + + public ProvisioningException(Throwable cause) { + super(cause); + } + + public ProvisioningException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ReservedConfigs.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ReservedConfigs.java new file mode 100644 index 0000000..a9acd03 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/ReservedConfigs.java @@ -0,0 +1,19 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +/** + * Reserved configuration keys + */ +public final class ReservedConfigs { + + /** + * Configurations that modify the query parameters when building URI-based addresses + */ + public static final String CONFIG_QUERY_PARAMETERS_PREFIX = "query."; + + /** + * Configurations that modify the headers when building URI-based addresses + */ + public static final String CONFIG_HEADER_PARAMETERS_PREFIX = "header."; + + private ReservedConfigs() {} +} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretStore.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretStore.java new file mode 100644 index 0000000..190a35f --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretStore.java @@ -0,0 +1,6 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +/** + * A specialized ConfigStore that stores secrets + */ +public interface SecretStore extends ConfigStore {} diff --git a/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretWriter.java b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretWriter.java new file mode 100644 index 0000000..5112130 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-api/src/main/java/ai/wanaku/capabilities/sdk/config/provider/api/SecretWriter.java @@ -0,0 +1,15 @@ +package ai.wanaku.capabilities.sdk.config.provider.api; + +/** + * An interface for writing sensitive secret data. + * This interface extends {@link ConfigWriter}, meaning that any implementation + * of {@code SecretWriter} must also implement the {@code write} method + * defined in {@code ConfigWriter}. However, {@code SecretWriter} specifically + * denotes that the data being written is considered sensitive (a "secret") + * and thus implementations should ensure appropriate security measures + * (e.g., encryption, restricted access) when handling and storing this data. + * + *

While the method signature {@code write(String id, String data)} is inherited, + * the semantic implication is that {@code data} contains confidential information. + */ +public interface SecretWriter extends ConfigWriter {} diff --git a/capabilities-config-providers/capabilities-config-provider-file/pom.xml b/capabilities-config-providers/capabilities-config-provider-file/pom.xml new file mode 100644 index 0000000..b2dd89d --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + ai.wanaku.sdk + capabilities-config-providers + 0.0.9-SNAPSHOT + + + capabilities-config-provider-file + Wanaku Capabilities SDK :: Config Providers :: Config Provider :: File + + + + ai.wanaku.sdk + capabilities-config-provider-api + ${project.version} + + + ai.wanaku.sdk + capabilities-api + ${project.version} + + + + + org.junit.jupiter + junit-jupiter + test + + + + \ No newline at end of file diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/ConfigFileStore.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/ConfigFileStore.java new file mode 100644 index 0000000..b8c7849 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/ConfigFileStore.java @@ -0,0 +1,19 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import java.net.URI; + +/** + * A concrete implementation of a configuration store that reads configurations from a file. + * This class extends {@link FileStore}, inheriting its file handling capabilities. + */ +public class ConfigFileStore extends FileStore { + + /** + * Constructs a new {@code ConfigFileStore} by specifying the URI of the configuration file. + * + * @param uri The {@link URI} of the configuration file. Must not be {@code null}. + */ + public ConfigFileStore(URI uri) { + super(uri); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelper.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelper.java new file mode 100644 index 0000000..6587873 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelper.java @@ -0,0 +1,82 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +/** + * Simple utility class for encrypting and decrypting data using AES-256. + */ +public final class EncryptionHelper { + + private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; + private static final int IV_LENGTH = 16; + + private EncryptionHelper() {} + + /** + * Encrypts data using AES-256-CBC. + * + * @param data the data to encrypt + * @param password the encryption password + * @param salt the salt for key derivation + * @return encrypted data with IV prepended + */ + public static byte[] encrypt(byte[] data, String password, String salt) throws Exception { + byte[] key = deriveKey(password, salt); + try { + byte[] iv = new byte[IV_LENGTH]; + new SecureRandom().nextBytes(iv); + + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); + byte[] encrypted = cipher.doFinal(data); + + // Prepend IV to ciphertext + byte[] result = new byte[IV_LENGTH + encrypted.length]; + System.arraycopy(iv, 0, result, 0, IV_LENGTH); + System.arraycopy(encrypted, 0, result, IV_LENGTH, encrypted.length); + return result; + } finally { + Arrays.fill(key, (byte) 0); + } + } + + /** + * Decrypts data that was encrypted with {@link #encrypt}. + * + * @param data the encrypted data (IV + ciphertext) + * @param password the encryption password + * @param salt the salt for key derivation + * @return decrypted data + * @throws IllegalArgumentException if data is null or too short + */ + public static byte[] decrypt(byte[] data, String password, String salt) throws Exception { + if (data == null || data.length < IV_LENGTH) { + throw new IllegalArgumentException("Invalid encrypted data: too short"); + } + + byte[] key = deriveKey(password, salt); + try { + byte[] iv = Arrays.copyOfRange(data, 0, IV_LENGTH); + byte[] ciphertext = Arrays.copyOfRange(data, IV_LENGTH, data.length); + + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); + return cipher.doFinal(ciphertext); + } finally { + Arrays.fill(key, (byte) 0); + } + } + + private static byte[] deriveKey(String password, String salt) throws Exception { + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(StandardCharsets.UTF_8), 65536, 256); + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + return factory.generateSecret(spec).getEncoded(); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileConfigurationWriter.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileConfigurationWriter.java new file mode 100644 index 0000000..6d55d02 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileConfigurationWriter.java @@ -0,0 +1,35 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigWriteException; +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigWriter; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class FileConfigurationWriter implements ConfigWriter { + + private final File serviceHome; + + public FileConfigurationWriter(String serviceHome) { + this(new File(serviceHome)); + } + + public FileConfigurationWriter(File serviceHome) { + this.serviceHome = serviceHome; + } + + @Override + public URI write(String id, String data) { + try { + final Path path = Paths.get(serviceHome.getAbsolutePath(), id); + Files.write(path, data.getBytes()); + + return path.toUri(); + } catch (IOException e) { + throw new ConfigWriteException("Failed to write configuration: " + id, e); + } + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileSecretWriter.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileSecretWriter.java new file mode 100644 index 0000000..b752402 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileSecretWriter.java @@ -0,0 +1,52 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigWriteException; +import ai.wanaku.capabilities.sdk.config.provider.api.SecretWriter; +import java.io.File; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Writes secrets to files, optionally encrypting them. + *

+ * Set environment variables WANAKU_SECRETS_ENCRYPTION_PASSWORD and + * WANAKU_SECRETS_ENCRYPTION_SALT to enable encryption. + */ +public class FileSecretWriter implements SecretWriter { + + private static final String ENV_PASSWORD = "WANAKU_SECRETS_ENCRYPTION_PASSWORD"; + private static final String ENV_SALT = "WANAKU_SECRETS_ENCRYPTION_SALT"; + + protected final File serviceHome; + + public FileSecretWriter(String serviceHome) { + this(new File(serviceHome)); + } + + public FileSecretWriter(File serviceHome) { + this.serviceHome = serviceHome; + } + + @Override + public URI write(String id, String data) { + try { + Path path = Paths.get(serviceHome.getAbsolutePath(), id); + byte[] bytes = data.getBytes(StandardCharsets.UTF_8); + + String password = System.getenv(ENV_PASSWORD); + String salt = System.getenv(ENV_SALT); + + if (password != null && !password.isEmpty() && salt != null && !salt.isEmpty()) { + bytes = EncryptionHelper.encrypt(bytes, password, salt); + } + + Files.write(path, bytes); + return path.toUri(); + } catch (Exception e) { + throw new ConfigWriteException("Failed to write secret: " + id, e); + } + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileStore.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileStore.java new file mode 100644 index 0000000..467c4b6 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/FileStore.java @@ -0,0 +1,23 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import ai.wanaku.capabilities.sdk.config.provider.api.PropertyBasedStore; +import java.net.URI; + +/** + * An abstract base class for {@link PropertyBasedStore} implementations that source their properties + * from a file identified by a {@link URI}. This class simplifies the creation of file-based + * configuration stores by integrating with {@link PropertyFileProvider}. + */ +abstract class FileStore extends PropertyBasedStore { + + /** + * Constructs a new {@code FileStore} by creating a {@link PropertyFileProvider} + * with the given {@link URI} and passing it to the superclass constructor. + * This sets up the store to read properties from the specified file. + * + * @param uri The {@link URI} of the file containing the properties. Must not be {@code null}. + */ + FileStore(URI uri) { + super(new PropertyFileProvider(uri)); + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/PropertyFileProvider.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/PropertyFileProvider.java new file mode 100644 index 0000000..0a3878e --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/PropertyFileProvider.java @@ -0,0 +1,49 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.config.provider.api.PropertyProvider; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URI; +import java.util.Properties; + +/** + * A concrete implementation of {@link PropertyProvider} that loads properties from a file + * specified by a {@link URI}. This provider handles reading properties from a standard + * Java properties file format. + */ +public class PropertyFileProvider implements PropertyProvider { + private final Properties properties; + + /** + * Constructs a new {@link PropertyFileProvider} and attempts to load properties from + * the file specified by the given {@link URI}. + * If the URI is {@code null}, an empty {@link Properties} object is initialized. + * + * @param uri The {@link URI} of the properties file to load. If {@code null}, + * an empty {@link Properties} object will be used. + * @throws WanakuException If the file specified by the URI is not found, or + * if an I/O error occurs during loading. + */ + public PropertyFileProvider(URI uri) { + if (uri == null) { + properties = new Properties(); + } else { + final String path = uri.getPath(); + + File file = new File(path); + properties = new Properties(); + try (FileInputStream fis = new FileInputStream(file)) { + properties.load(fis); + } catch (IOException e) { + throw new WanakuException(e); + } + } + } + + @Override + public Properties getProperties() { + return properties; + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/SecretFileStore.java b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/SecretFileStore.java new file mode 100644 index 0000000..35566b7 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/main/java/ai/wanaku/capabilities/sdk/config/provider/file/SecretFileStore.java @@ -0,0 +1,60 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.config.provider.api.PropertyBasedStore; +import ai.wanaku.capabilities.sdk.config.provider.api.PropertyProvider; +import ai.wanaku.capabilities.sdk.config.provider.api.SecretStore; +import java.io.StringReader; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Properties; + +/** + * Reads secrets from files, automatically decrypting if encryption is configured. + *

+ * Set environment variables WANAKU_SECRETS_ENCRYPTION_PASSWORD and + * WANAKU_SECRETS_ENCRYPTION_SALT to enable decryption. + */ +public class SecretFileStore extends PropertyBasedStore implements SecretStore { + + private static final String ENV_PASSWORD = "WANAKU_SECRETS_ENCRYPTION_PASSWORD"; + private static final String ENV_SALT = "WANAKU_SECRETS_ENCRYPTION_SALT"; + + public SecretFileStore(URI uri) { + super(new DecryptingPropertyProvider(uri)); + } + + private static class DecryptingPropertyProvider implements PropertyProvider { + private final Properties properties = new Properties(); + + DecryptingPropertyProvider(URI uri) { + if (uri == null) { + return; + } + try { + byte[] data = Files.readAllBytes(Paths.get(uri)); + + String password = System.getenv(ENV_PASSWORD); + String salt = System.getenv(ENV_SALT); + + if (password != null && !password.isEmpty() && salt != null && !salt.isEmpty()) { + data = EncryptionHelper.decrypt(data, password, salt); + } + + // Decode the secret file as UTF-8 and load via a Reader so we are not bound + // to the ISO-8859-1 encoding required by Properties.load(InputStream). + String content = new String(data, StandardCharsets.UTF_8); + properties.load(new StringReader(content)); + } catch (Exception e) { + throw new WanakuException("Failed to load secrets from " + uri, e); + } + } + + @Override + public Properties getProperties() { + return properties; + } + } +} diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/main/resources/application.properties b/capabilities-config-providers/capabilities-config-provider-file/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/capabilities-config-providers/capabilities-config-provider-file/src/test/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelperTest.java b/capabilities-config-providers/capabilities-config-provider-file/src/test/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelperTest.java new file mode 100644 index 0000000..90f7759 --- /dev/null +++ b/capabilities-config-providers/capabilities-config-provider-file/src/test/java/ai/wanaku/capabilities/sdk/config/provider/file/EncryptionHelperTest.java @@ -0,0 +1,103 @@ +package ai.wanaku.capabilities.sdk.config.provider.file; + +import static org.junit.jupiter.api.Assertions.*; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +class EncryptionHelperTest { + + private static final String PASSWORD = "test-password-123"; + private static final String SALT = "test-salt-1234567890"; + + @Test + void encryptDecryptRoundTrip() throws Exception { + String original = "api.key=secret-value\npassword=secret-password"; + byte[] encrypted = EncryptionHelper.encrypt(original.getBytes(StandardCharsets.UTF_8), PASSWORD, SALT); + byte[] decrypted = EncryptionHelper.decrypt(encrypted, PASSWORD, SALT); + + assertEquals(original, new String(decrypted, StandardCharsets.UTF_8)); + } + + @Test + void encryptDecryptRoundTripEmptyPayload() throws Exception { + byte[] original = new byte[0]; + + byte[] encrypted = EncryptionHelper.encrypt(original, PASSWORD, SALT); + byte[] decrypted = EncryptionHelper.decrypt(encrypted, PASSWORD, SALT); + + assertArrayEquals(original, decrypted); + } + + @Test + void encryptDecryptRoundTripVeryShortPayloads() throws Exception { + byte[][] payloads = { + new byte[] {0x00}, + new byte[] {0x01}, + new byte[] {(byte) 0xFF}, + new byte[] {0x00, 0x01}, + new byte[] {(byte) 0x80, 0x7F} + }; + + for (byte[] original : payloads) { + byte[] encrypted = EncryptionHelper.encrypt(original, PASSWORD, SALT); + byte[] decrypted = EncryptionHelper.decrypt(encrypted, PASSWORD, SALT); + + assertArrayEquals(original, decrypted); + } + } + + @Test + void encryptDecryptRoundTripBinaryPayload() throws Exception { + byte[] original = + new byte[] {0x00, 0x01, 0x02, 0x03, (byte) 0xFF, (byte) 0x80, (byte) 0x7F, 0x10, 0x20, (byte) 0xFE}; + + byte[] encrypted = EncryptionHelper.encrypt(original, PASSWORD, SALT); + byte[] decrypted = EncryptionHelper.decrypt(encrypted, PASSWORD, SALT); + + assertArrayEquals(original, decrypted); + } + + @Test + void encryptedDataDiffersFromOriginal() throws Exception { + String original = "secret data"; + byte[] encrypted = EncryptionHelper.encrypt(original.getBytes(StandardCharsets.UTF_8), PASSWORD, SALT); + + assertNotEquals(original, new String(encrypted, StandardCharsets.UTF_8)); + } + + @Test + void differentIVsProduceDifferentCiphertext() throws Exception { + byte[] data = "same data".getBytes(StandardCharsets.UTF_8); + byte[] encrypted1 = EncryptionHelper.encrypt(data, PASSWORD, SALT); + byte[] encrypted2 = EncryptionHelper.encrypt(data, PASSWORD, SALT); + + assertFalse(Arrays.equals(encrypted1, encrypted2)); + } + + @Test + void wrongPasswordFails() throws Exception { + byte[] encrypted = EncryptionHelper.encrypt("data".getBytes(StandardCharsets.UTF_8), PASSWORD, SALT); + + assertThrows(Exception.class, () -> EncryptionHelper.decrypt(encrypted, "wrong-password", SALT)); + } + + @Test + void wrongSaltFails() throws Exception { + byte[] encrypted = EncryptionHelper.encrypt("data".getBytes(StandardCharsets.UTF_8), PASSWORD, SALT); + + assertThrows(Exception.class, () -> EncryptionHelper.decrypt(encrypted, PASSWORD, "wrong-salt")); + } + + @Test + void decryptNullDataThrowsIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, () -> EncryptionHelper.decrypt(null, PASSWORD, SALT)); + } + + @Test + void decryptTooShortDataThrowsIllegalArgumentException() { + byte[] tooShort = new byte[15]; // IV_LENGTH is 16 + assertThrows(IllegalArgumentException.class, () -> EncryptionHelper.decrypt(tooShort, PASSWORD, SALT)); + } +} diff --git a/capabilities-config-providers/pom.xml b/capabilities-config-providers/pom.xml new file mode 100644 index 0000000..d0547ff --- /dev/null +++ b/capabilities-config-providers/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + ai.wanaku.sdk + capabilities-parent + 0.0.9-SNAPSHOT + ../capabilities-parent/pom.xml + + + pom + capabilities-config-providers + Wanaku Capabilities SDK :: Config Provider + + + capabilities-config-provider-api + capabilities-config-provider-file + + + \ No newline at end of file diff --git a/capabilities-data-files/pom.xml b/capabilities-data-files/pom.xml index ffc7f70..2a3b641 100644 --- a/capabilities-data-files/pom.xml +++ b/capabilities-data-files/pom.xml @@ -13,4 +13,12 @@ Wanaku Capabilities SDK :: Data Files + + + ai.wanaku.sdk + capabilities-api + ${project.version} + + + \ No newline at end of file diff --git a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/FileHeader.java b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/FileHeader.java index bf519a5..f3d895e 100644 --- a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/FileHeader.java +++ b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/FileHeader.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.data.files; -import ai.wanaku.api.types.providers.ServiceType; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceType; /** * Represents the header of a data file, containing metadata such as format name, service type, and file version. diff --git a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManager.java b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManager.java index e0fe6b9..3121096 100644 --- a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManager.java +++ b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManager.java @@ -1,8 +1,8 @@ package ai.wanaku.capabilities.sdk.data.files; -import ai.wanaku.api.exceptions.WanakuException; -import ai.wanaku.api.types.providers.ServiceTarget; -import ai.wanaku.api.types.providers.ServiceType; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceType; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -10,9 +10,20 @@ import org.slf4j.LoggerFactory; /** - * Manages permanent data for a capabilities instance, such as its service ID. - * This class is used by a {@code RegistrationManager} to store information - * after registration with the Wanaku Discovery and Registration API. + * Manages persistent storage of service instance data for capability provider services. + *

+ * This class handles the lifecycle of service instance data files, including reading existing + * service entries, writing new entries, and managing the data directory structure. Each service + * instance maintains its identity across restarts by persisting its ID to a binary data file. + *

+ * The manager creates data files with the naming convention {@code .wanaku.dat} + * in the specified data directory. These files contain a {@link FileHeader} followed by + * {@link ServiceEntry} data. + * + * @see ServiceEntry + * @see FileHeader + * @see InstanceDataReader + * @see InstanceDataWriter */ public class InstanceDataManager { private static final Logger LOG = LoggerFactory.getLogger(InstanceDataManager.class); @@ -78,7 +89,7 @@ public ServiceEntry readEntry() { return reader.readEntry(); } catch (IOException e) { - throw new RuntimeException(e); + throw new WanakuException(e); } } @@ -109,7 +120,7 @@ public void writeEntry(ServiceTarget serviceTarget) { try (InstanceDataWriter writer = new InstanceDataWriter(file, fileHeader)) { writer.write(new ServiceEntry(serviceTarget.getId())); } catch (IOException e) { - throw new RuntimeException(e); + throw new WanakuException(e); } } diff --git a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataReader.java b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataReader.java index 433ecb9..a712236 100644 --- a/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataReader.java +++ b/capabilities-data-files/src/main/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataReader.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.data.files; -import ai.wanaku.api.types.providers.ServiceType; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceType; import java.io.File; import java.io.FileInputStream; import java.io.IOException; diff --git a/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/FileHeaderTest.java b/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/FileHeaderTest.java index b5b0fb6..dd4f180 100644 --- a/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/FileHeaderTest.java +++ b/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/FileHeaderTest.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.data.files; -import ai.wanaku.api.types.providers.ServiceType; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceType; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; diff --git a/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java b/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java index 5f002f8..01091d5 100644 --- a/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java +++ b/capabilities-data-files/src/test/java/ai/wanaku/capabilities/sdk/data/files/InstanceDataManagerTest.java @@ -1,7 +1,7 @@ package ai.wanaku.capabilities.sdk.data.files; -import ai.wanaku.api.types.providers.ServiceTarget; -import ai.wanaku.api.types.providers.ServiceType; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceType; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/capabilities-discovery/pom.xml b/capabilities-discovery/pom.xml index 869d073..8d150db 100644 --- a/capabilities-discovery/pom.xml +++ b/capabilities-discovery/pom.xml @@ -14,6 +14,12 @@ Wanaku Capabilities SDK :: Discovery + + ai.wanaku.sdk + capabilities-api + ${project.version} + + ai.wanaku.sdk capabilities-common diff --git a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryLogCallback.java b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryLogCallback.java index 2281594..5777887 100644 --- a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryLogCallback.java +++ b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryLogCallback.java @@ -1,8 +1,8 @@ package ai.wanaku.capabilities.sdk.discovery; -import ai.wanaku.api.discovery.DiscoveryCallback; -import ai.wanaku.api.discovery.RegistrationManager; -import ai.wanaku.api.types.providers.ServiceTarget; +import ai.wanaku.capabilities.sdk.api.discovery.DiscoveryCallback; +import ai.wanaku.capabilities.sdk.api.discovery.RegistrationManager; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryServiceHttpClient.java b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryServiceHttpClient.java index 3ab562f..3a14a9e 100644 --- a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryServiceHttpClient.java +++ b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/DiscoveryServiceHttpClient.java @@ -2,9 +2,9 @@ import jakarta.ws.rs.core.MediaType; -import ai.wanaku.api.exceptions.WanakuException; -import ai.wanaku.api.types.discovery.ServiceState; -import ai.wanaku.api.types.providers.ServiceTarget; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.types.discovery.ServiceState; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; import ai.wanaku.capabilities.sdk.common.config.ServiceConfig; import ai.wanaku.capabilities.sdk.discovery.exceptions.InvalidResponseDataException; import ai.wanaku.capabilities.sdk.common.serializer.Serializer; diff --git a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/ZeroDepRegistrationManager.java b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/ZeroDepRegistrationManager.java index b087c47..a1687d4 100644 --- a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/ZeroDepRegistrationManager.java +++ b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/ZeroDepRegistrationManager.java @@ -3,12 +3,12 @@ import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.core.Response; -import ai.wanaku.api.discovery.DiscoveryCallback; -import ai.wanaku.api.discovery.RegistrationManager; -import ai.wanaku.api.exceptions.WanakuException; -import ai.wanaku.api.types.WanakuResponse; -import ai.wanaku.api.types.discovery.ServiceState; -import ai.wanaku.api.types.providers.ServiceTarget; +import ai.wanaku.capabilities.sdk.api.discovery.DiscoveryCallback; +import ai.wanaku.capabilities.sdk.api.discovery.RegistrationManager; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.types.WanakuResponse; +import ai.wanaku.capabilities.sdk.api.types.discovery.ServiceState; +import ai.wanaku.capabilities.sdk.api.types.providers.ServiceTarget; import ai.wanaku.capabilities.sdk.data.files.InstanceDataManager; import ai.wanaku.capabilities.sdk.data.files.ServiceEntry; import ai.wanaku.capabilities.sdk.discovery.config.RegistrationConfig; diff --git a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/util/DiscoveryHelper.java b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/util/DiscoveryHelper.java index 430c0a2..fecca71 100644 --- a/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/util/DiscoveryHelper.java +++ b/capabilities-discovery/src/main/java/ai/wanaku/capabilities/sdk/discovery/util/DiscoveryHelper.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.discovery.util; -import ai.wanaku.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; import java.net.InetAddress; import java.net.UnknownHostException; diff --git a/capabilities-exchange/pom.xml b/capabilities-exchange/pom.xml index c7b41df..11e2139 100644 --- a/capabilities-exchange/pom.xml +++ b/capabilities-exchange/pom.xml @@ -28,6 +28,12 @@ grpc-stub + + ai.wanaku.sdk + capabilities-config-provider-api + ${project.version} + + org.apache.tomcat annotations-api @@ -46,32 +52,6 @@ - - org.apache.maven.plugins - maven-dependency-plugin - ${maven-dependency-plugin.version} - - - unpack-source-jar - generate-sources - - unpack - - - - - ai.wanaku - core-exchange - ${wanaku.version} - sources - ${project.basedir}/src/main/proto - **/*.proto - - - - - - org.xolstice.maven.plugins protobuf-maven-plugin @@ -91,6 +71,19 @@ + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + package + + jar + + + + diff --git a/capabilities-exchange/src/main/java/ai/wanaku/capabilities/sdk/util/ProvisioningHelper.java b/capabilities-exchange/src/main/java/ai/wanaku/capabilities/sdk/util/ProvisioningHelper.java index 9573401..95cc6a4 100644 --- a/capabilities-exchange/src/main/java/ai/wanaku/capabilities/sdk/util/ProvisioningHelper.java +++ b/capabilities-exchange/src/main/java/ai/wanaku/capabilities/sdk/util/ProvisioningHelper.java @@ -1,7 +1,7 @@ package ai.wanaku.capabilities.sdk.util; -import ai.wanaku.core.config.provider.api.ConfigProvisioner; -import ai.wanaku.core.config.provider.api.ProvisionedConfig; +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigProvisioner; +import ai.wanaku.capabilities.sdk.config.provider.api.ProvisionedConfig; import ai.wanaku.core.exchange.Configuration; import ai.wanaku.core.exchange.ProvisionRequest; import ai.wanaku.core.exchange.Secret; diff --git a/capabilities-parent/pom.xml b/capabilities-parent/pom.xml index bd3384e..ebd67df 100644 --- a/capabilities-parent/pom.xml +++ b/capabilities-parent/pom.xml @@ -22,8 +22,8 @@ UTF-8 - 0.0.9-SNAPSHOT 2.20.1 + 2.19.2 3.1.0 2.0.17 2.25.2 @@ -31,7 +31,7 @@ 1.76.0 1.72.0 6.0.53 - 5.13.4 + 5.13.4 11.30.1 @@ -67,34 +67,32 @@ oauth2-oidc-sdk ${oauth2-oidc-sdk.version} - - + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-annotations.version} + - - - ai.wanaku - api - ${wanaku.version} - + + com.fasterxml.jackson.core + jackson-databind + ${jackson-databind.version} + - - ai.wanaku - core-config-provider-api - ${wanaku.version} - - - ai.wanaku - core-config-provider-file - ${wanaku.version} - + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + - - com.fasterxml.jackson.core - jackson-databind - ${jackson-databind.version} - + + + + jakarta.ws.rs jakarta.ws.rs-api @@ -115,7 +113,6 @@ org.junit.jupiter junit-jupiter-api - ${junit-jupiter-api.version} test diff --git a/capabilities-runtime/pom.xml b/capabilities-runtime/pom.xml index d6322cc..7f6547e 100644 --- a/capabilities-runtime/pom.xml +++ b/capabilities-runtime/pom.xml @@ -32,6 +32,11 @@ capabilities-exchange ${project.version} + + ai.wanaku.sdk + capabilities-config-provider-file + ${project.version} + \ No newline at end of file diff --git a/capabilities-runtime/src/main/java/ai/wanaku/capabilities/sdk/runtime/provisioners/FileProvisionerLoader.java b/capabilities-runtime/src/main/java/ai/wanaku/capabilities/sdk/runtime/provisioners/FileProvisionerLoader.java index 84e6610..e8bf21d 100644 --- a/capabilities-runtime/src/main/java/ai/wanaku/capabilities/sdk/runtime/provisioners/FileProvisionerLoader.java +++ b/capabilities-runtime/src/main/java/ai/wanaku/capabilities/sdk/runtime/provisioners/FileProvisionerLoader.java @@ -1,12 +1,12 @@ package ai.wanaku.capabilities.sdk.runtime.provisioners; import ai.wanaku.capabilities.sdk.common.ServicesHelper; -import ai.wanaku.core.config.provider.api.ConfigProvisioner; -import ai.wanaku.core.config.provider.api.ConfigWriter; -import ai.wanaku.core.config.provider.api.DefaultConfigProvisioner; -import ai.wanaku.core.config.provider.api.SecretWriter; -import ai.wanaku.core.config.provider.file.FileConfigurationWriter; -import ai.wanaku.core.config.provider.file.FileSecretWriter; +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigProvisioner; +import ai.wanaku.capabilities.sdk.config.provider.api.ConfigWriter; +import ai.wanaku.capabilities.sdk.config.provider.api.DefaultConfigProvisioner; +import ai.wanaku.capabilities.sdk.config.provider.api.SecretWriter; +import ai.wanaku.capabilities.sdk.config.provider.file.FileConfigurationWriter; +import ai.wanaku.capabilities.sdk.config.provider.file.FileSecretWriter; import ai.wanaku.core.exchange.Configuration; import ai.wanaku.core.exchange.PayloadType; import ai.wanaku.core.exchange.ProvisionRequest; diff --git a/capabilities-security/src/main/java/ai/wanaku/capabilities/sdk/security/exceptions/ServiceAuthException.java b/capabilities-security/src/main/java/ai/wanaku/capabilities/sdk/security/exceptions/ServiceAuthException.java index 938808a..db1e3ce 100644 --- a/capabilities-security/src/main/java/ai/wanaku/capabilities/sdk/security/exceptions/ServiceAuthException.java +++ b/capabilities-security/src/main/java/ai/wanaku/capabilities/sdk/security/exceptions/ServiceAuthException.java @@ -1,6 +1,6 @@ package ai.wanaku.capabilities.sdk.security.exceptions; -import ai.wanaku.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; /** * Exception thrown when service authentication fails in the Wanaku capabilities SDK. diff --git a/capabilities-services-client/src/main/java/ai/wanaku/capabilities/sdk/services/ServicesHttpClient.java b/capabilities-services-client/src/main/java/ai/wanaku/capabilities/sdk/services/ServicesHttpClient.java index 137dc54..87a3afc 100644 --- a/capabilities-services-client/src/main/java/ai/wanaku/capabilities/sdk/services/ServicesHttpClient.java +++ b/capabilities-services-client/src/main/java/ai/wanaku/capabilities/sdk/services/ServicesHttpClient.java @@ -2,15 +2,15 @@ import jakarta.ws.rs.core.MediaType; -import ai.wanaku.api.exceptions.WanakuException; -import ai.wanaku.api.types.DataStore; -import ai.wanaku.api.types.ForwardReference; -import ai.wanaku.api.types.Namespace; -import ai.wanaku.api.types.ResourceReference; -import ai.wanaku.api.types.ToolReference; -import ai.wanaku.api.types.WanakuResponse; -import ai.wanaku.api.types.io.ResourcePayload; -import ai.wanaku.api.types.io.ToolPayload; +import ai.wanaku.capabilities.sdk.api.exceptions.WanakuException; +import ai.wanaku.capabilities.sdk.api.types.DataStore; +import ai.wanaku.capabilities.sdk.api.types.ForwardReference; +import ai.wanaku.capabilities.sdk.api.types.Namespace; +import ai.wanaku.capabilities.sdk.api.types.ResourceReference; +import ai.wanaku.capabilities.sdk.api.types.ToolReference; +import ai.wanaku.capabilities.sdk.api.types.WanakuResponse; +import ai.wanaku.capabilities.sdk.api.types.io.ResourcePayload; +import ai.wanaku.capabilities.sdk.api.types.io.ToolPayload; import ai.wanaku.capabilities.sdk.common.config.ServiceConfig; import ai.wanaku.capabilities.sdk.common.exceptions.WanakuWebException; import ai.wanaku.capabilities.sdk.common.serializer.Serializer; diff --git a/pom.xml b/pom.xml index 9bbfa6b..7077136 100644 --- a/pom.xml +++ b/pom.xml @@ -68,11 +68,13 @@ capabilities-discovery capabilities-security capabilities-data-files + capabilities-config-providers capabilities-exchange capabilities-runtime capabilities-services-client capabilities-bom capabilities-archetypes + capabilities-api