Skip to content

Commit dedd203

Browse files
committed
feat(spring-boot-starter): add Spring Boot auto-configuration starter with sample app
1 parent 5f13e58 commit dedd203

25 files changed

Lines changed: 1205 additions & 0 deletions

contrib/samples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@
2727
<module>github/adktriaging</module>
2828
<module>helloworld</module>
2929
<module>mcpfilesystem</module>
30+
<module>spring-boot-adk-template</module>
3031
</modules>
3132
</project>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Spring Boot ADK Template
2+
3+
Sample Spring Boot application demonstrating the **`google-adk-spring-boot-starter`** in its simplest form. The user code consists of:
4+
5+
- One `@Bean LlmAgent rootAgent()` — the agent topology
6+
- One `@Bean App` — wraps the root agent under an app name
7+
- One `@Service AgentService` — illustrates injection of the starter-provided `Runner`
8+
9+
Everything else (`Runner`, `BaseSessionService`, `BaseArtifactService`, `RunConfig`) is wired by the starter.
10+
11+
## Prerequisites
12+
13+
- Java 17
14+
- Maven
15+
- This module is built as part of the ADK aggregator; no separate install of the starter is required.
16+
17+
## Build and run
18+
19+
From the repository root:
20+
21+
```bash
22+
mvn -pl contrib/samples/spring-boot-adk-template -am verify
23+
```
24+
25+
To run interactively:
26+
27+
```bash
28+
mvn -pl contrib/samples/spring-boot-adk-template -am spring-boot:run
29+
```
30+
31+
## Configuration
32+
33+
`src/main/resources/application.yaml` shows the full property surface as comments. The defaults give an all-in-memory configuration with no GCP credentials required — switch backends by uncommenting the relevant blocks (`adk.session.type=VERTEX_AI`, `adk.session.type=FIRESTORE`, `adk.artifacts.gcs-enabled=true`, etc.).
34+
35+
See the [starter README](../../spring-boot-starter/README.md) for the full property reference.
36+
37+
## Use Spring AI as the LLM substrate (optional)
38+
39+
This sample uses a string model name (`"gemini-2.5-flash"`). To swap to Spring AI's `ChatModel` ecosystem (OpenAI, Anthropic, Gemini, Ollama, Vertex AI, Azure OpenAI, Bedrock):
40+
41+
1. Add `com.google.adk:google-adk-spring-ai` and your preferred Spring AI provider artifact to `pom.xml`.
42+
2. Configure the provider via `spring.ai.*` properties (e.g. `spring.ai.openai.api-key`).
43+
3. Inject the auto-configured `SpringAI` bean into `AgentConfig.rootAgent()` and pass it to `.model(...)`.
44+
45+
## Project structure
46+
47+
```
48+
src/main/java/com/example/springbootadktemplate/
49+
├── SpringBootAdkTemplateApplication.java — @SpringBootApplication entry point
50+
├── AgentService.java — sample @Service injecting Runner + LlmAgent
51+
└── config/AgentConfig.java — @Bean LlmAgent + @Bean App
52+
src/main/resources/application.yaml — spring.application.name + (commented) adk.* properties
53+
src/test/java/com/example/springbootadktemplate/
54+
└── SpringBootAdkTemplateApplicationTest.java — context-load test asserting every starter bean is reachable
55+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2026 Google LLC
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
-->
11+
<project xmlns="http://maven.apache.org/POM/4.0.0"
12+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
13+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
14+
<modelVersion>4.0.0</modelVersion>
15+
16+
<parent>
17+
<groupId>com.google.adk</groupId>
18+
<artifactId>google-adk-samples</artifactId>
19+
<version>1.5.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
20+
<relativePath>..</relativePath>
21+
</parent>
22+
23+
<groupId>com.google.adk.samples</groupId>
24+
<artifactId>google-adk-sample-spring-boot-template</artifactId>
25+
<name>Google ADK - Sample - Spring Boot Template</name>
26+
<description>Spring Boot template demonstrating the google-adk-spring-boot-starter.</description>
27+
<packaging>jar</packaging>
28+
29+
<properties>
30+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
31+
<java.version>17</java.version>
32+
<exec.mainClass>com.example.springbootadktemplate.SpringBootAdkTemplateApplication</exec.mainClass>
33+
</properties>
34+
35+
<dependencies>
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter</artifactId>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-starter-web</artifactId>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.google.adk</groupId>
46+
<artifactId>google-adk-spring-boot-starter</artifactId>
47+
<version>${project.version}</version>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.springframework.boot</groupId>
51+
<artifactId>spring-boot-starter-test</artifactId>
52+
<scope>test</scope>
53+
</dependency>
54+
</dependencies>
55+
56+
<build>
57+
<plugins>
58+
<plugin>
59+
<groupId>org.springframework.boot</groupId>
60+
<artifactId>spring-boot-maven-plugin</artifactId>
61+
<configuration>
62+
<mainClass>${exec.mainClass}</mainClass>
63+
</configuration>
64+
</plugin>
65+
</plugins>
66+
</build>
67+
</project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.example.springbootadktemplate;
2+
3+
import com.google.adk.agents.LlmAgent;
4+
import com.google.adk.runner.Runner;
5+
import org.springframework.stereotype.Service;
6+
7+
@Service
8+
public class AgentService {
9+
10+
private final Runner runner;
11+
private final LlmAgent agent;
12+
13+
public AgentService(Runner runner, LlmAgent agent) {
14+
this.runner = runner;
15+
this.agent = agent;
16+
}
17+
18+
public String getAgentInfo() {
19+
return "Agent created: "
20+
+ agent.getClass().getSimpleName()
21+
+ ", Runner: "
22+
+ runner.getClass().getSimpleName();
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2026 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+
package com.example.springbootadktemplate;
11+
12+
import org.springframework.boot.SpringApplication;
13+
import org.springframework.boot.autoconfigure.SpringBootApplication;
14+
15+
@SpringBootApplication
16+
public class SpringBootAdkTemplateApplication {
17+
18+
public static void main(String[] args) {
19+
SpringApplication.run(SpringBootAdkTemplateApplication.class, args);
20+
}
21+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2026 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+
package com.example.springbootadktemplate.config;
11+
12+
import com.google.adk.agents.LlmAgent;
13+
import com.google.adk.apps.App;
14+
import org.springframework.beans.factory.annotation.Value;
15+
import org.springframework.context.annotation.Bean;
16+
import org.springframework.context.annotation.Configuration;
17+
18+
/**
19+
* Sample agent topology — defines a root LlmAgent and packages it into an App.
20+
*
21+
* <p>The starter provides {@code Runner}, {@code BaseSessionService}, {@code BaseArtifactService},
22+
* and {@code RunConfig} automatically — this configuration only declares the user-specific agent
23+
* topology.
24+
*/
25+
@Configuration
26+
public class AgentConfig {
27+
28+
@Bean
29+
public LlmAgent rootAgent() {
30+
return LlmAgent.builder()
31+
.name("root_agent")
32+
.description("Sample assistant agent.")
33+
.model("gemini-2.5-flash")
34+
.instruction("Answer user questions to the best of your knowledge.")
35+
.build();
36+
}
37+
38+
@Bean
39+
public App app(LlmAgent rootAgent, @Value("${spring.application.name}") String appName) {
40+
return App.builder().name(appName).rootAgent(rootAgent).build();
41+
}
42+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
spring:
2+
application:
3+
name: spring_boot_adk_template # must be a valid identifier (App#validateAppName regex)
4+
5+
# Defaults — services are in-memory unless these are uncommented.
6+
# adk:
7+
# artifacts:
8+
# gcs-enabled: false
9+
# # bucket-name: my-bucket
10+
# session:
11+
# type: IN_MEMORY # IN_MEMORY | VERTEX_AI | FIRESTORE
12+
# # project-id: my-project
13+
# # location: us-central1
14+
# memory:
15+
# type: IN_MEMORY # IN_MEMORY | FIRESTORE
16+
# run-config:
17+
# streaming-mode: NONE # NONE | SSE | BIDI
18+
# max-llm-calls: 500
19+
# tool-execution-mode: NONE # NONE | SEQUENTIAL | PARALLEL | PARALLEL_SUBSCRIBE
20+
# save-input-blobs-as-artifacts: false
21+
# auto-create-session: true
22+
# firestore:
23+
# # project-id: my-gcp-project
24+
# # database-id: "(default)"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2026 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+
package com.example.springbootadktemplate;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
14+
import com.google.adk.agents.LlmAgent;
15+
import com.google.adk.agents.RunConfig;
16+
import com.google.adk.apps.App;
17+
import com.google.adk.artifacts.BaseArtifactService;
18+
import com.google.adk.runner.Runner;
19+
import com.google.adk.sessions.BaseSessionService;
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.boot.test.context.SpringBootTest;
22+
import org.springframework.context.ApplicationContext;
23+
24+
@SpringBootTest
25+
class SpringBootAdkTemplateApplicationTest {
26+
27+
@Test
28+
void contextLoadsAndStarterBeansArePresent(ApplicationContext ctx) {
29+
assertThat(ctx.getBean(LlmAgent.class)).isNotNull();
30+
assertThat(ctx.getBean(App.class).name()).isEqualTo("spring_boot_adk_template");
31+
assertThat(ctx.getBean(BaseArtifactService.class)).isNotNull();
32+
assertThat(ctx.getBean(BaseSessionService.class)).isNotNull();
33+
assertThat(ctx.getBean(RunConfig.class)).isNotNull();
34+
assertThat(ctx.getBean(Runner.class).appName()).isEqualTo("spring_boot_adk_template");
35+
}
36+
}

0 commit comments

Comments
 (0)