From 490db036c7a3c941bebac81dc87e97ee732639a3 Mon Sep 17 00:00:00 2001 From: I538344 Date: Fri, 13 Feb 2026 11:43:07 +0100 Subject: [PATCH 1/4] Agent Tool Integration Layer : Proof of Concept --- logback.xml | 4 +- sample-code/spring-app/pom.xml | 6 + .../AgentToolIntegrationLayerTest.java | 113 ++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java diff --git a/logback.xml b/logback.xml index 2bbaaa365..c29966f70 100644 --- a/logback.xml +++ b/logback.xml @@ -12,8 +12,8 @@ - - + + diff --git a/sample-code/spring-app/pom.xml b/sample-code/spring-app/pom.xml index b06359ebe..9b0169799 100644 --- a/sample-code/spring-app/pom.xml +++ b/sample-code/spring-app/pom.xml @@ -241,6 +241,12 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + + com.sap.cloud.security + java-security-test + 3.6.6 + test + diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java new file mode 100644 index 000000000..e5d16d7f7 --- /dev/null +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java @@ -0,0 +1,113 @@ +package com.sap.ai.sdk.app.controllers; + +import com.auth0.jwt.JWT; +import com.sap.cloud.environment.servicebinding.SapVcapServicesServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.ServiceIdentifier; +import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor; +import com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.AuthenticationServiceOptions; +import com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.IasOptions; +import com.sap.cloud.sdk.cloudplatform.connectivity.OnBehalfOf; +import com.sap.cloud.sdk.cloudplatform.connectivity.ServiceBindingDestinationLoader; +import com.sap.cloud.sdk.cloudplatform.connectivity.ServiceBindingDestinationOptions; +import com.sap.cloud.sdk.cloudplatform.security.AuthToken; +import com.sap.cloud.sdk.cloudplatform.security.AuthTokenAccessor; +import io.vavr.control.Try; +import java.util.Collections; +import lombok.SneakyThrows; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * How to run this test: + * + *

1. Get the VCAP_SERVICES: Navigate to BTP + * > agent-approuter > environment variables and copy the VCAP_SERVICES part + * starting with {"identity". + * + *

2. Get the JSON_WEB_TOKEN: Copy your password while logging into Cloud Identity. Make a Bruno request to + * https://ma.accounts400.ondemand.com/oauth2/token with the following URL encoded body: + * + *

+ *   grant_type=client_credentials
+ *   &client_id=<approuter-client-id>
+ *   &client_secret=<approuter-client-secret>
+ *   &username=<your-email>
+ *   &password=<Cloud-Indentity-password>
+ * 
+ */ +class AgentToolIntegrationLayerTest { + + private static final String VCAP_SERVICES = +""" +"""; + + private static final String JSON_WEB_TOKEN = +""" +"""; + + String payload = + "{\"message\": {\"role\": \"user\",\"parts\": [{ \"kind\": \"data\", \"data\": { \"userQuery\": \"Plan a travel itinerary for me for Berlin\" }}],\"kind\": \"message\"}}"; + + String payloadBig = +""" +{ + "message": { + "role": "user", + "parts": [ + { + "kind": "data", + "data": { + "userQuery": "Plan a travel itinerary for me for Berlin" + } + } + ], + "kind": "message" + } +} +"""; + + @BeforeEach + void prepareInboundAccessToken() { + DefaultServiceBindingAccessor.setInstance( + new SapVcapServicesServiceBindingAccessor( + Collections.singletonMap("VCAP_SERVICES", VCAP_SERVICES)::get)); + AuthTokenAccessor.setAuthTokenFacade( + () -> Try.success(new AuthToken(JWT.decode(JSON_WEB_TOKEN)))); + } + + @Test + @SneakyThrows + void testAgentToolIntegrationLayer() { + var options = + ServiceBindingDestinationOptions.forService(ServiceIdentifier.IDENTITY_AUTHENTICATION) + .withOption( + AuthenticationServiceOptions.withTargetUri( + "https://gen-ai-hub-sdk-8pengs8d.eu12.sapdas.cloud.sap")) + .withOption(IasOptions.withApplicationName("Agent2Joule")) + .onBehalfOf(OnBehalfOf.NAMED_USER_CURRENT_TENANT) + .build(); + + var destination = ServiceBindingDestinationLoader.defaultLoaderChain().getDestination(options); + + String atilUrl = + "https://gen-ai-hub-sdk-8pengs8d.eu12.sapdas.cloud.sap/api/content/v1/capabilities/com.sap.ai.sdk/my_assistant_capability/scenarios/plan_travel/v1/message:send?assistant=my_assistant_i563080"; + var httpPost = new HttpPost(atilUrl); + httpPost.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON)); + httpPost.setHeader( + "x-callback-target", "https://echo-server.cfapps.eu12-001.hana.ondemand.com"); + httpPost.setHeader("x-global-user-id", "01361f5a-9ca7-4593-9c54-2425a127edff"); + httpPost.setHeader("Accept-Language", "en"); + + var response = + ApacheHttpClient5Accessor.getHttpClient(destination) + .execute(httpPost, new BasicHttpClientResponseHandler()); + System.out.println(response); + } +} From 2c7328b0c01647de44818c85a54d5e1f4856940d Mon Sep 17 00:00:00 2001 From: I538344 Date: Fri, 13 Feb 2026 11:51:02 +0100 Subject: [PATCH 2/4] exclude junit --- sample-code/spring-app/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sample-code/spring-app/pom.xml b/sample-code/spring-app/pom.xml index 9b0169799..eb25cd0e6 100644 --- a/sample-code/spring-app/pom.xml +++ b/sample-code/spring-app/pom.xml @@ -246,6 +246,12 @@ java-security-test 3.6.6 test + + + junit + junit + + From 5b2ad76aa37d64c34e28d68774fdda94100d5fa9 Mon Sep 17 00:00:00 2001 From: I538344 Date: Mon, 16 Feb 2026 11:05:32 +0100 Subject: [PATCH 3/4] fix dependencies --- sample-code/spring-app/pom.xml | 52 ++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/sample-code/spring-app/pom.xml b/sample-code/spring-app/pom.xml index eb25cd0e6..90550e884 100644 --- a/sample-code/spring-app/pom.xml +++ b/sample-code/spring-app/pom.xml @@ -241,17 +241,51 @@ com.fasterxml.jackson.dataformat jackson-dataformat-yaml + - com.sap.cloud.security - java-security-test - 3.6.6 + com.sap.cloud.environment.servicebinding.api + java-access-api + test + + + com.sap.cloud.environment.servicebinding.api + java-core-api + test + + + com.auth0 + java-jwt + test + + + com.sap.cloud.sdk.cloudplatform + connectivity-apache-httpclient5 + test + + + com.sap.cloud.environment.servicebinding + java-sap-vcap-services + test + + + io.vavr + vavr + test + + + com.sap.cloud.sdk.cloudplatform + security + test + + + org.apache.httpcomponents.core5 + httpcore5 + test + + + org.apache.httpcomponents.client5 + httpclient5 test - - - junit - junit - - From 1a68a4e11ce4d5ffcd64c6186a378d68772e6cb9 Mon Sep 17 00:00:00 2001 From: I538344 Date: Tue, 17 Feb 2026 14:05:26 +0100 Subject: [PATCH 4/4] Working --- sample-code/spring-app/pom.xml | 12 ++++++++++++ .../controllers/AgentToolIntegrationLayerTest.java | 14 ++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/sample-code/spring-app/pom.xml b/sample-code/spring-app/pom.xml index 90550e884..55c46cca1 100644 --- a/sample-code/spring-app/pom.xml +++ b/sample-code/spring-app/pom.xml @@ -66,6 +66,18 @@ com.sap.ai.sdk core + + + com.sap.cloud.sdk.cloudplatform + connectivity-oauth + + + + + com.sap.cloud.sdk.cloudplatform + connectivity-oauth + 5.27.0-SNAPSHOT + com.sap.ai.sdk.foundationmodels diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java index e5d16d7f7..4d35a91c5 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/AgentToolIntegrationLayerTest.java @@ -1,9 +1,11 @@ package com.sap.ai.sdk.app.controllers; +import static com.sap.cloud.environment.servicebinding.api.ServiceIdentifier.IDENTITY_AUTHENTICATION; +import static org.apache.hc.core5.http.ContentType.APPLICATION_JSON; + import com.auth0.jwt.JWT; import com.sap.cloud.environment.servicebinding.SapVcapServicesServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; -import com.sap.cloud.environment.servicebinding.api.ServiceIdentifier; import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor; import com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.AuthenticationServiceOptions; import com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.IasOptions; @@ -17,7 +19,6 @@ import lombok.SneakyThrows; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; -import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.io.entity.StringEntity; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,9 +54,6 @@ class AgentToolIntegrationLayerTest { """; String payload = - "{\"message\": {\"role\": \"user\",\"parts\": [{ \"kind\": \"data\", \"data\": { \"userQuery\": \"Plan a travel itinerary for me for Berlin\" }}],\"kind\": \"message\"}}"; - - String payloadBig = """ { "message": { @@ -86,7 +84,7 @@ void prepareInboundAccessToken() { @SneakyThrows void testAgentToolIntegrationLayer() { var options = - ServiceBindingDestinationOptions.forService(ServiceIdentifier.IDENTITY_AUTHENTICATION) + ServiceBindingDestinationOptions.forService(IDENTITY_AUTHENTICATION) .withOption( AuthenticationServiceOptions.withTargetUri( "https://gen-ai-hub-sdk-8pengs8d.eu12.sapdas.cloud.sap")) @@ -97,9 +95,9 @@ void testAgentToolIntegrationLayer() { var destination = ServiceBindingDestinationLoader.defaultLoaderChain().getDestination(options); String atilUrl = - "https://gen-ai-hub-sdk-8pengs8d.eu12.sapdas.cloud.sap/api/content/v1/capabilities/com.sap.ai.sdk/my_assistant_capability/scenarios/plan_travel/v1/message:send?assistant=my_assistant_i563080"; + "/api/content/v1/capabilities/com.sap.ai.sdk/my_assistant_capability/scenarios/plan_travel/v1/message:send?assistant=my_assistant_i563080"; var httpPost = new HttpPost(atilUrl); - httpPost.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON)); + httpPost.setEntity(new StringEntity(payload, APPLICATION_JSON.withCharset((String) null))); httpPost.setHeader( "x-callback-target", "https://echo-server.cfapps.eu12-001.hana.ondemand.com"); httpPost.setHeader("x-global-user-id", "01361f5a-9ca7-4593-9c54-2425a127edff");