11package com .google .adk .tools .applicationintegrationtoolset ;
22
3+ import static com .google .common .base .Strings .isNullOrEmpty ;
4+
35import com .fasterxml .jackson .databind .JsonNode ;
46import com .fasterxml .jackson .databind .ObjectMapper ;
7+ import com .fasterxml .jackson .databind .node .ObjectNode ;
58import com .google .adk .tools .BaseTool ;
6- import com .google .adk .tools .applicationintegrationtoolset .ApplicationIntegrationTool .DefaultHttpExecutor ;
7- import com .google .adk .tools .applicationintegrationtoolset .ApplicationIntegrationTool .HttpExecutor ;
8- import com .google .auth .oauth2 .GoogleCredentials ;
9- import com .google .common .collect .ImmutableList ;
10- import com .google .common .collect .ImmutableMap ;
11- import java .io .IOException ;
12- import java .net .URI ;
13- import java .net .http .HttpRequest ;
14- import java .net .http .HttpResponse ;
9+ import com .google .adk .tools .applicationintegrationtoolset .IntegrationConnectorTool .DefaultHttpExecutor ;
10+ import com .google .adk .tools .applicationintegrationtoolset .IntegrationConnectorTool .HttpExecutor ;
1511import java .util .ArrayList ;
16- import java .util .Arrays ;
1712import java .util .Iterator ;
1813import java .util .List ;
1914import java .util .Map ;
2318public class ApplicationIntegrationToolset {
2419 String project ;
2520 String location ;
26- String integration ;
27- List <String > triggers ;
28- private final HttpExecutor httpExecutor ;
21+ @ Nullable String integration ;
22+ @ Nullable List <String > triggers ;
23+ @ Nullable String connection ;
24+ @ Nullable Map <String , List <String >> entityOperations ;
25+ @ Nullable List <String > actions ;
26+ @ Nullable String toolNamePrefix ;
27+ @ Nullable String toolInstructions ;
2928 public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
29+ HttpExecutor httpExecutor ;
3030
3131 /**
3232 * ApplicationIntegrationToolset generates tools from a given Application Integration resource.
@@ -35,80 +35,80 @@ public class ApplicationIntegrationToolset {
3535 *
3636 * <p>integrationTool = new ApplicationIntegrationToolset( project="test-project",
3737 * location="us-central1", integration="test-integration",
38- * triggers=ImmutableList.of("api_trigger/test_trigger", "api_trigger/test_trigger_2"));
38+ * triggers=ImmutableList.of("api_trigger/test_trigger",
39+ * "api_trigger/test_trigger_2"),connection=null,enitityOperations=null,actions=null,toolNamePrefix="test-integration-tool",toolInstructions="This
40+ * tool is used to get response from test-integration.");
41+ *
42+ * <p>connectionTool = new ApplicationIntegrationToolset( project="test-project",
43+ * location="us-central1", integration=null, triggers=null, connection="test-connection",
44+ * entityOperations=ImmutableMap.of("Entity1", ImmutableList.of("LIST", "GET", "UPDATE")),
45+ * "Entity2", ImmutableList.of()), actions=ImmutableList.of("ExecuteCustomQuery"),
46+ * toolNamePrefix="test-tool", toolInstructions="This tool is used to list, get and update issues
47+ * in Jira.");
3948 *
4049 * @param project The GCP project ID.
4150 * @param location The GCP location of integration.
4251 * @param integration The integration name.
4352 * @param triggers(Optional) The list of trigger ids in the integration.
53+ * @param connection(Optional) The connection name.
54+ * @param entityOperations(Optional) The entity operations.
55+ * @param actions(Optional) The actions.
56+ * @param toolNamePrefix(Optional) The tool name prefix.
57+ * @param toolInstructions(Optional) The tool instructions.
4458 */
4559 public ApplicationIntegrationToolset (
46- String project , String location , String integration , List <String > triggers ) {
47- this (project , location , integration , triggers , new DefaultHttpExecutor ());
60+ String project ,
61+ String location ,
62+ String integration ,
63+ List <String > triggers ,
64+ String connection ,
65+ Map <String , List <String >> entityOperations ,
66+ List <String > actions ,
67+ String toolNamePrefix ,
68+ String toolInstructions ) {
69+ this (
70+ project ,
71+ location ,
72+ integration ,
73+ triggers ,
74+ connection ,
75+ entityOperations ,
76+ actions ,
77+ toolNamePrefix ,
78+ toolInstructions ,
79+ new DefaultHttpExecutor ());
4880 }
4981
5082 ApplicationIntegrationToolset (
5183 String project ,
5284 String location ,
5385 String integration ,
5486 List <String > triggers ,
87+ String connection ,
88+ Map <String , List <String >> entityOperations ,
89+ List <String > actions ,
90+ String toolNamePrefix ,
91+ String toolInstructions ,
5592 HttpExecutor httpExecutor ) {
5693 this .project = project ;
5794 this .location = location ;
5895 this .integration = integration ;
5996 this .triggers = triggers ;
97+ this .connection = connection ;
98+ this .entityOperations = entityOperations ;
99+ this .actions = actions ;
100+ this .toolNamePrefix = toolNamePrefix ;
101+ this .toolInstructions = toolInstructions ;
60102 this .httpExecutor = httpExecutor ;
61103 }
62104
63- String generateOpenApiSpec () throws Exception {
64- String url =
65- String .format (
66- "https://%s-integrations.googleapis.com/v1/projects/%s/locations/%s:generateOpenApiSpec" ,
67- this .location , this .project , this .location );
68-
69- String jsonRequestBody =
70- OBJECT_MAPPER .writeValueAsString (
71- ImmutableMap .of (
72- "apiTriggerResources" ,
73- ImmutableList .of (
74- ImmutableMap .of (
75- "integrationResource" ,
76- this .integration ,
77- "triggerId" ,
78- Arrays .asList (this .triggers ))),
79- "fileFormat" ,
80- "JSON" ));
81- HttpRequest request =
82- HttpRequest .newBuilder ()
83- .uri (URI .create (url ))
84- .header ("Authorization" , "Bearer " + getAccessToken ())
85- .header ("Content-Type" , "application/json" )
86- .POST (HttpRequest .BodyPublishers .ofString (jsonRequestBody ))
87- .build ();
88- HttpResponse <String > response =
89- httpExecutor .send (request , HttpResponse .BodyHandlers .ofString ());
90-
91- if (response .statusCode () < 200 || response .statusCode () >= 300 ) {
92- throw new Exception ("Error fetching OpenAPI spec. Status: " + response .statusCode ());
93- }
94- return response .body ();
95- }
96-
97- String getAccessToken () throws IOException {
98- GoogleCredentials credentials =
99- GoogleCredentials .getApplicationDefault ()
100- .createScoped (ImmutableList .of ("https://www.googleapis.com/auth/cloud-platform" ));
101- credentials .refreshIfExpired ();
102- return credentials .getAccessToken ().getTokenValue ();
103- }
104-
105105 List <String > getPathUrl (String openApiSchemaString ) throws Exception {
106106 List <String > pathUrls = new ArrayList <>();
107107 JsonNode topLevelNode = OBJECT_MAPPER .readTree (openApiSchemaString );
108108 JsonNode specNode = topLevelNode .path ("openApiSpec" );
109109 if (specNode .isMissingNode () || !specNode .isTextual ()) {
110110 throw new IllegalArgumentException (
111- "API response must contain an 'openApiSpec' key with a string value ." );
111+ "Failed to get OpenApiSpec, please check the project and region for the integration ." );
112112 }
113113 JsonNode rootNode = OBJECT_MAPPER .readTree (specNode .asText ());
114114 JsonNode pathsNode = rootNode .path ("paths" );
@@ -121,29 +121,74 @@ List<String> getPathUrl(String openApiSchemaString) throws Exception {
121121 return pathUrls ;
122122 }
123123
124- @ Nullable String extractTriggerIdFromPath (String path ) {
125- String prefix = "triggerId=api_trigger/" ;
126- int startIndex = path .indexOf (prefix );
127- if (startIndex == -1 ) {
128- return null ;
129- }
130- return path .substring (startIndex + prefix .length ());
131- }
132-
133124 public List <BaseTool > getTools () throws Exception {
134- String openApiSchemaString = generateOpenApiSpec ();
135- List <String > pathUrls = getPathUrl (openApiSchemaString );
136-
125+ String openApiSchemaString = null ;
137126 List <BaseTool > tools = new ArrayList <>();
138- for (String pathUrl : pathUrls ) {
139- String toolName = extractTriggerIdFromPath (pathUrl );
140- if (toolName != null ) {
141- tools .add (new ApplicationIntegrationTool (openApiSchemaString , pathUrl , toolName , "" ));
142- } else {
143- System .err .println (
144- "Failed to get tool name , Please check the integration name , trigger id and location"
145- + " and project id." );
127+ if (!isNullOrEmpty (this .integration )) {
128+ IntegrationClient integrationClient =
129+ new IntegrationClient (
130+ this .project ,
131+ this .location ,
132+ this .integration ,
133+ this .triggers ,
134+ null ,
135+ null ,
136+ null ,
137+ this .httpExecutor );
138+ openApiSchemaString = integrationClient .generateOpenApiSpec ();
139+ List <String > pathUrls = getPathUrl (openApiSchemaString );
140+ for (String pathUrl : pathUrls ) {
141+ String toolName = integrationClient .getOperationIdFromPathUrl (openApiSchemaString , pathUrl );
142+ if (toolName != null ) {
143+ tools .add (
144+ new IntegrationConnectorTool (
145+ openApiSchemaString , pathUrl , toolName , "" , null , null , null , this .httpExecutor ));
146+ }
146147 }
148+ } else if (!isNullOrEmpty (this .connection )
149+ && (this .entityOperations != null || this .actions != null )) {
150+ IntegrationClient integrationClient =
151+ new IntegrationClient (
152+ this .project ,
153+ this .location ,
154+ null ,
155+ null ,
156+ this .connection ,
157+ this .entityOperations ,
158+ this .actions ,
159+ this .httpExecutor );
160+ ObjectNode parentOpenApiSpec = OBJECT_MAPPER .createObjectNode ();
161+ ObjectNode openApiSpec =
162+ integrationClient .getOpenApiSpecForConnection (toolNamePrefix , toolInstructions );
163+ String openApiSpecString = OBJECT_MAPPER .writeValueAsString (openApiSpec );
164+ parentOpenApiSpec .put ("openApiSpec" , openApiSpecString );
165+ openApiSchemaString = OBJECT_MAPPER .writeValueAsString (parentOpenApiSpec );
166+ List <String > pathUrls = getPathUrl (openApiSchemaString );
167+ for (String pathUrl : pathUrls ) {
168+ String toolName = integrationClient .getOperationIdFromPathUrl (openApiSchemaString , pathUrl );
169+ if (!isNullOrEmpty (toolName )) {
170+ ConnectionsClient connectionsClient =
171+ new ConnectionsClient (
172+ this .project , this .location , this .connection , this .httpExecutor , OBJECT_MAPPER );
173+ ConnectionsClient .ConnectionDetails connectionDetails =
174+ connectionsClient .getConnectionDetails ();
175+
176+ tools .add (
177+ new IntegrationConnectorTool (
178+ openApiSchemaString ,
179+ pathUrl ,
180+ toolName ,
181+ "" ,
182+ connectionDetails .name ,
183+ connectionDetails .serviceName ,
184+ connectionDetails .host ,
185+ this .httpExecutor ));
186+ }
187+ }
188+ } else {
189+ throw new IllegalArgumentException (
190+ "Invalid request, Either integration or (connection and"
191+ + " (entityOperations or actions)) should be provided." );
147192 }
148193
149194 return tools ;
0 commit comments