Skip to content

Commit d99d64e

Browse files
yongkiy-googlecopybara-github
authored andcommitted
feat: add skeleton Agent Engine Deployer for ADK Java
PiperOrigin-RevId: 906820376
1 parent dd46b25 commit d99d64e

2 files changed

Lines changed: 225 additions & 0 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.deploy;
18+
19+
import java.io.IOException;
20+
import java.nio.file.Files;
21+
import java.nio.file.Path;
22+
import java.time.Instant;
23+
import java.util.logging.Level;
24+
import java.util.logging.Logger;
25+
26+
/**
27+
* Command line application to deploy an ADK Java Agent to Vertex AI Agent Engine (Reasoning
28+
* Engine).
29+
*/
30+
public class AgentEngineDeployer {
31+
private static final Logger logger = Logger.getLogger(AgentEngineDeployer.class.getName());
32+
33+
private final String region;
34+
private final String projectId;
35+
private final String agentName;
36+
private final int serverPort;
37+
private final String sourceDir;
38+
39+
private AgentEngineDeployer(
40+
String region, String projectId, String agentName, int serverPort, String sourceDir) {
41+
this.region = region;
42+
this.projectId = projectId;
43+
this.agentName = agentName;
44+
this.serverPort = serverPort;
45+
this.sourceDir = sourceDir;
46+
}
47+
48+
/** Creates a temporary Dockerfile and bundles the application for Reasoning Engine deployment. */
49+
static Path prepareBundle(int serverPort) throws IOException {
50+
Path tempDir = Files.createTempDirectory("agentEngineDeploy");
51+
Path dockerfile = tempDir.resolve("Dockerfile");
52+
53+
String dockerfileContent =
54+
String.format(
55+
"FROM eclipse-temurin:21-jdk\n"
56+
+ "WORKDIR /app\n"
57+
+ "COPY . .\n"
58+
+ "RUN ./mvnw clean package -DskipTests\n"
59+
+ "EXPOSE %d\n"
60+
+ "CMD [\"java\", \"-jar\", \"target/app.jar\"]\n",
61+
serverPort);
62+
63+
Files.writeString(dockerfile, dockerfileContent);
64+
logger.info("Prepared Dockerfile at " + dockerfile.toAbsolutePath());
65+
return tempDir;
66+
}
67+
68+
/** Orchestrates the deployment process. */
69+
public void deploy() throws IOException {
70+
logger.info("Starting Agent Engine deployment...");
71+
logger.info(
72+
String.format(
73+
"Deploying Agent '%s' to project '%s' in region '%s'...",
74+
agentName, projectId, region));
75+
76+
// TODO: Integrate with Vertex AI CreateReasoningEngine API client.
77+
logger.info("Preparation complete. Skipping actual deployment to Vertex AI for now.");
78+
}
79+
80+
/** Builder for {@link AgentEngineDeployer}. */
81+
public static class Builder {
82+
private String region;
83+
private String projectId;
84+
private String agentName;
85+
private int serverPort;
86+
private String sourceDir;
87+
88+
public Builder region(String region) {
89+
this.region = region;
90+
return this;
91+
}
92+
93+
public Builder projectId(String projectId) {
94+
this.projectId = projectId;
95+
return this;
96+
}
97+
98+
public Builder agentName(String agentName) {
99+
this.agentName = agentName;
100+
return this;
101+
}
102+
103+
public Builder serverPort(int serverPort) {
104+
this.serverPort = serverPort;
105+
return this;
106+
}
107+
108+
public Builder sourceDir(String sourceDir) {
109+
this.sourceDir = sourceDir;
110+
return this;
111+
}
112+
113+
public AgentEngineDeployer build() {
114+
if (projectId == null || projectId.isEmpty()) {
115+
throw new IllegalStateException("Project ID must be specified.");
116+
}
117+
if (agentName == null || agentName.isEmpty()) {
118+
agentName = "ADK Java Agent: " + Instant.now().toString();
119+
}
120+
if (sourceDir == null || sourceDir.isEmpty()) {
121+
sourceDir = System.getProperty("user.dir");
122+
}
123+
return new AgentEngineDeployer(region, projectId, agentName, serverPort, sourceDir);
124+
}
125+
}
126+
127+
public static Builder builder() {
128+
return new Builder();
129+
}
130+
131+
public static void main(String[] args) {
132+
Builder builder = AgentEngineDeployer.builder().region("us-central1").serverPort(8080);
133+
134+
// Minimal argument parsing logic
135+
for (int i = 0; i < args.length; i++) {
136+
switch (args[i]) {
137+
case "--project":
138+
if (i + 1 < args.length) {
139+
builder.projectId(args[++i]);
140+
}
141+
break;
142+
case "--region":
143+
if (i + 1 < args.length) {
144+
builder.region(args[++i]);
145+
}
146+
break;
147+
case "--name":
148+
if (i + 1 < args.length) {
149+
builder.agentName(args[++i]);
150+
}
151+
break;
152+
case "--port":
153+
if (i + 1 < args.length) {
154+
builder.serverPort(Integer.parseInt(args[++i]));
155+
}
156+
break;
157+
case "--source-dir":
158+
if (i + 1 < args.length) {
159+
builder.sourceDir(args[++i]);
160+
}
161+
break;
162+
default:
163+
logger.warning("Unknown argument: " + args[i]);
164+
}
165+
}
166+
167+
try {
168+
AgentEngineDeployer deployer = builder.build();
169+
deployer.deploy();
170+
} catch (Exception e) {
171+
logger.log(Level.SEVERE, "Deployment failed", e);
172+
System.exit(1);
173+
}
174+
}
175+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.deploy;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.assertThrows;
21+
22+
import java.io.IOException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import org.junit.Test;
26+
import org.junit.runner.RunWith;
27+
import org.junit.runners.JUnit4;
28+
29+
@RunWith(JUnit4.class)
30+
public class AgentEngineDeployerTest {
31+
32+
@Test
33+
public void build_withMissingProjectId_throwsException() {
34+
AgentEngineDeployer.Builder builder = AgentEngineDeployer.builder();
35+
// ProjectId is not set.
36+
assertThrows(IllegalStateException.class, builder::build);
37+
}
38+
39+
@Test
40+
public void deploy_createsDockerfileWithCorrectPort() throws IOException {
41+
int serverPort = 9090;
42+
43+
Path tempDir = AgentEngineDeployer.prepareBundle(serverPort);
44+
Path dockerfile = tempDir.resolve("Dockerfile");
45+
46+
assertThat(Files.exists(dockerfile)).isTrue();
47+
String content = Files.readString(dockerfile);
48+
assertThat(content).contains("EXPOSE " + serverPort);
49+
}
50+
}

0 commit comments

Comments
 (0)