Public Preview integration for Spring AI 2.0.x and Spring Boot 4. Model calls execute as Temporal Activities; Activity, Nexus, side-effect, and deterministic tools execute through the ChatClient tool-calling advisor on the workflow thread.
The new coordinate is io.temporal:spring-ai on
Maven Central.
CI tests Java 17 and 25; published bytecode targets Java 17.
- Java 17 or later.
- Spring AI 2.0.1 and Spring Boot 4.0.8; Boot 4.1.1 is also tested.
- Temporal Java SDK and
temporal-spring-boot-starter1.40.0 or later. - A Spring AI provider starter for your chosen model. This integration supplies no provider.
Install the standalone integration:
implementation 'io.temporal:spring-ai:0.1.0'
implementation 'io.temporal:temporal-spring-boot-starter:1.40.0'
implementation 'io.temporal:temporal-sdk:1.40.0'Inside a workflow, construct the client with TemporalChatClient.builder(ActivityChatModel.forDefault())
and register tools with defaultTools(...). The entry points TemporalChatClient,
ActivityChatModel, and Temporal tool annotations retain their names and packages.
Model calls run as Activities; tool calls remain durable Temporal operations.
io.temporal:spring-ai:0.1.0 targets Spring AI 2 / Boot 4 exclusively. Spring AI 1 /
Boot 3 applications remain on io.temporal:temporal-spring-ai:1.40.x. Align your application with the Spring AI 2
and Boot 4 BOMs; Spring AI 2 uses immutable options and Jackson 3. Pass option builders
to ChatClient, for example .defaultOptions(OpenAiChatOptions.builder().reasoningEffort("high")).
ActivityChatModel.call(...) returns a raw model response; use ChatClient's advisor
loop to execute tools. The removed internalToolExecutionEnabled flag is unnecessary.
Do not move in-flight Spring AI 1 workflows onto these workers: the upgrade does not provide replay compatibility with Spring AI 1 histories. Use separate worker deployments or complete the existing executions before switching versions.
Streaming and tool context remain unsupported. Provider-specific options survive Activity serialization through their public builders; callbacks are transported as definitions and execute only in the workflow. Retry, per-model Activity options, response metadata, and media-size guards retain their behavior. Optional vector-store, embedding, and MCP modules are detected through Spring auto-configuration.
For OpenAI chat Activities, native OpenAI HTTP errors retain their status, error
body, and diagnostic response headers (retry-after, retry-after-ms,
x-request-id, x-ratelimit-*, and x-should-retry) in ApplicationFailure
details. insufficient_quota responses are always non-retryable. Otherwise,
X-Should-Retry: true or false overrides the HTTP status. Without a recognized
directive, rate limits (429), request timeouts (408), conflicts (409), and server
errors are retryable; other HTTP client errors are non-retryable.
Retry-After (seconds or an HTTP date) and retry-after-ms set Temporal's next
retry delay; missing or invalid delays leave the Activity's configured backoff
in effect. A positive provider delay overrides maximumInterval, which does
not cap it. Maximum attempts and schedule-to-close timeouts still apply. To
exclude additional errors with RetryOptions.Builder.setDoNotRetry(...), use
the exact failure type, such as com.openai.errors.RateLimitException.
Disable provider SDK retries on models registered with Temporal so each Activity
attempt makes one provider request. For a manually constructed OpenAI model, use
OpenAiChatOptions.builder().maxRetries(0) when building the worker's model.
For Spring Boot's OpenAI chat model:
spring.ai.openai.chat.max-retries=0These options configure the provider client at construction time; setting them on a workflow prompt does not disable retries on an existing client. Keep a separate model/client if calls outside Temporal need SDK retries. Without this configuration, Spring AI 2.0.1's three internal OpenAI retries can produce twelve requests across the default three Activity attempts.
./gradlew spotlessCheck test stageDistThe full Java/OS matrix runs for each supported Boot version, using committed locks.
Deliberately update locks with ./gradlew resolveAndLockAll --write-locks
(and -PspringBootVersion=4.1.1 for that compatibility lane).
Nightly CI and manual runs with latest-deps=true test stable releases in Temporal
1.x, Spring AI 2.x, and Spring Boot 4.x.
To run that check locally:
./gradlew -PdependencyMode=latest resolveAndLockAll --write-locks --refresh-dependencies
./gradlew -PdependencyMode=latest spotlessCheck test stageDistLatest mode writes a separate ignored lockfile and reuses its selected versions through testing and building. Ordinary CI uses the committed locks.
The implementation and tests use the repository's MIT license.
