diff --git a/docs/develop/java/integrations/spring-ai.mdx b/docs/develop/java/integrations/spring-ai.mdx index d4878aba26..73e267de9b 100644 --- a/docs/develop/java/integrations/spring-ai.mdx +++ b/docs/develop/java/integrations/spring-ai.mdx @@ -10,53 +10,46 @@ tags: - Temporal SDKs - Integrations - AI Frameworks -description: Build durable AI agents in Java with the Temporal Spring AI integration. +description: Run Spring AI agents on Temporal with durable model calls, Activity tools, and replay-safe orchestration using Spring Boot. --- import { ReleaseNoteHeader } from '@site/src/components'; [Spring AI](https://docs.spring.io/spring-ai/reference/) is an agent framework for Java applications — chat clients, tool calling, vector stores, embeddings, and MCP servers, all wired through Spring Boot. -The [Temporal Spring AI integration](https://central.sonatype.com/artifact/io.temporal/temporal-spring-ai) makes Spring AI agents durable: model calls run through Temporal Activities recorded in Event history, and tools are dispatched per their type so each kind lands in the right place in Workflow execution — Activity stubs and Nexus stubs as durable operations, `@SideEffectTool` classes wrapped in `Workflow.sideEffect`, and plain tools running directly in Workflow code. Agents retry on failure and replay deterministically without changing how you write Spring AI code. +The [Temporal Spring AI integration](https://central.sonatype.com/artifact/io.temporal/spring-ai) makes Spring AI agents durable: model calls run through Temporal Activities recorded in Event history, and tools are dispatched per their type so each kind lands in the right place in Workflow execution — Activity stubs and Nexus stubs as durable operations, `@SideEffectTool` classes wrapped in `Workflow.sideEffect`, and plain tools running directly in Workflow code. Agents retry on failure and replay deterministically without changing how you write Spring AI code. -The integration is built on the Temporal Java SDK's [Plugin system](/develop/plugins-guide) and is distributed as the `io.temporal:temporal-spring-ai` module alongside the existing [Spring Boot integration](/develop/java/integrations/spring-boot-integration). +The integration is built on the Temporal Java SDK's [Plugin system](/develop/plugins-guide) and is distributed as the standalone `io.temporal:spring-ai` module alongside the existing [Spring Boot integration](/develop/java/integrations/spring-boot-integration). ## Prerequisites -The integration requires all of the following on your application's classpath. The plugin won't auto-configure if any of these are missing or below the listed minimum: +Your application needs a Java runtime, with Spring Boot, Spring AI, and the Temporal Java SDK on its classpath. Refer to the [integration's compatibility requirements](https://github.com/temporalio/ai-integrations/tree/main/java/spring-ai#requirements-and-installation) for supported versions. -| Dependency | Minimum version | -| ----------------- | --------------- | -| Java | 17 | -| Spring Boot | 3.x | -| Spring AI | 1.1.0 | -| Temporal Java SDK | 1.35.0 | - -You also need the [`temporal-spring-boot-starter`](/develop/java/integrations/spring-boot-integration) and a Spring AI model starter (for example, `spring-ai-starter-model-openai`) — `temporal-spring-ai` does not pull in a model provider on its own. +You also need the [`temporal-spring-boot-starter`](/develop/java/integrations/spring-boot-integration) and a Spring AI model starter (for example, `spring-ai-starter-model-openai`). The integration does not pull in a model provider on its own. ## Add the dependency -Add `temporal-spring-ai` alongside `temporal-spring-boot-starter` and a Spring AI model starter (for example, `spring-ai-starter-model-openai`). +Add `io.temporal:spring-ai` alongside `temporal-spring-boot-starter` and a Spring AI model starter (for example, `spring-ai-starter-model-openai`). The Spring AI integration is versioned separately from the Temporal Java SDK. **[Apache Maven](https://maven.apache.org/):** ```xml io.temporal - temporal-spring-ai - ${temporal-sdk.version} + spring-ai + ${temporal-spring-ai.version} ``` **[Gradle Groovy DSL](https://gradle.org/):** ```groovy -implementation "io.temporal:temporal-spring-ai:${temporalSdkVersion}" +implementation "io.temporal:spring-ai:${temporalSpringAiVersion}" ``` -When `temporal-spring-ai` is on the classpath, the `SpringAiPlugin` auto-registers `ChatModelActivity` with all Temporal Workers created by the Spring Boot integration. Optional Activities are auto-configured when their dependencies are present: +When `io.temporal:spring-ai` is on the classpath, the `SpringAiPlugin` auto-registers `ChatModelActivity` with all Temporal Workers created by the Spring Boot integration. Optional Activities are auto-configured when their dependencies are present: | Feature | Dependency | Registered Activity | | ------------ | --------------- | ------------------------ | @@ -64,6 +57,14 @@ When `temporal-spring-ai` is on the classpath, the `SpringAiPlugin` auto-registe | Embeddings | `spring-ai-rag` | `EmbeddingModelActivity` | | MCP | `spring-ai-mcp` | `McpClientActivity` | +### Upgrade from Spring AI 1.x + +`io.temporal:spring-ai:0.1.0` targets Spring AI 2 and Spring Boot 4. Spring AI 1 / Spring Boot 3 applications should remain on `io.temporal:temporal-spring-ai:1.40.x`. + +Align your application's Spring AI and Spring Boot BOMs with the integration's compatibility requirements. Spring AI 2 uses Jackson 3 and immutable chat options. Pass option builders to `ChatClient`, such as `.defaultOptions(OpenAiChatOptions.builder().reasoningEffort("high"))`, or call `.mutate()` on existing options. + +Spring AI 1 Workflow histories are incompatible with this upgrade. Complete existing executions before switching versions or use separate Worker deployments for the two versions. + ## Call a chat model from a Workflow Use `ActivityChatModel` as a Spring AI `ChatModel` inside a Workflow. Every call goes through a Temporal Activity, so model responses are durable and retried per your Activity options. @@ -106,12 +107,16 @@ public ChatWorkflowImpl(String systemPrompt) { // - Activity stubs (weatherTool) become durable AI tools // - plain workflow tool classes (stringTools) execute directly in workflow // - @SideEffectTool classes (timestampTools) are wrapped in sideEffect() - // - PromptChatMemoryAdvisor maintains conversation history + // - MessageChatMemoryAdvisor maintains conversation history this.chatClient = TemporalChatClient.builder(activityChatModel) .defaultSystem(systemPrompt) .defaultTools(weatherTool, stringTools, timestampTools) - .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemory).build()) + .defaultAdvisors( + advisors -> + advisors + .advisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) + .param(ChatMemory.CONVERSATION_ID, Workflow.getInfo().getWorkflowId())) .build(); } @@ -335,6 +340,18 @@ Keys that neither match a registered `ChatModel` bean nor equal `"default"` caus `ActivityMcpClient.create()` and `create(ActivityOptions)` work the same way for MCP tool calls, with a 30-second default timeout. +### Disable provider retries + +Disable the provider SDK's retries so each Temporal Activity attempt makes one provider request. For the Spring Boot OpenAI chat model, set: + +```properties +spring.ai.openai.chat.max-retries=0 +``` + +For manually constructed OpenAI or Anthropic models, set `.maxRetries(0)` on the provider options before building the Worker's model. Setting retries on a Workflow prompt does not reconfigure an existing provider client. + +OpenAI HTTP failures retain their native exception types. The integration classifies retryable failures and honors provider retry delays; see the [provider retry reference](https://github.com/temporalio/ai-integrations/tree/main/java/spring-ai#provider-retries) for details. + ## Provider-specific chat options Provider-specific `ChatOptions` subclasses — for example, `AnthropicChatOptions` to enable extended thinking, or `OpenAiChatOptions` to set `reasoning_effort` — pass through the Activity boundary unchanged. Attach them via `ChatClient.defaultOptions(...)` and the plugin re-applies them on the Activity side before calling the underlying model: @@ -342,12 +359,8 @@ Provider-specific `ChatOptions` subclasses — for example, `AnthropicChatOption [springai/multimodel/src/main/java/io/temporal/samples/springai/multimodel/MultiModelWorkflowImpl.java](https://github.com/temporalio/samples-java/blob/main/springai/multimodel/src/main/java/io/temporal/samples/springai/multimodel/MultiModelWorkflowImpl.java) ```java -AnthropicChatOptions thinkingOptions = - AnthropicChatOptions.builder() - .thinking(AnthropicApi.ThinkingType.ENABLED, 1024) - .temperature(1.0) - .maxTokens(4096) - .build(); +AnthropicChatOptions.Builder thinkingOptions = + AnthropicChatOptions.builder().thinkingEnabled(1024).temperature(1.0).maxTokens(4096); chatClients.put( "think", TemporalChatClient.builder(anthropicModel) @@ -360,7 +373,7 @@ chatClients.put( ``` -The pass-through relies on the `ChatOptions` subclass overriding `copy()` to return its own type — every provider class shipped with Spring AI does. +Spring AI options are immutable. Pass their builder to `defaultOptions(...)`, or call `.mutate()` on an existing options object. The integration preserves provider-specific fields across the Activity boundary. ## Media in messages @@ -389,6 +402,6 @@ new McpPlugin(); ## Resources -- [`temporal-spring-ai` README](https://github.com/temporalio/sdk-java/blob/main/contrib/temporal-spring-ai/README.md) — full reference for the module +- [Temporal Spring AI README](https://github.com/temporalio/ai-integrations/tree/main/java/spring-ai) — full reference for the standalone module - [Spring Boot integration](/develop/java/integrations/spring-boot-integration) — required companion module - [Plugin system](/develop/plugins-guide) — how integrations are registered with Workers and Clients