---
title: "Spring AI 2.1.0-RC1 and 2.0.2 Available Now - Angryecho"
description: "On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-RC1 and 2.0.2 have been released and are now avail…"
canonical_url: "https://www.angryecho.com/c/Spring/p/P2TBBjklli4dElUNzqGrc"
meta:
  "og:description": "On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-RC1 and 2.0.2 have been released and are now avail…"
  "og:image": "https://www.angryecho.com/_og/d/c_Post%2Ctitle_~5ZCQ5qe9572R%2Cdescription_~5ZCQ5qe95LiA5LiL77yM5bCx5LiK5ZCQ5qe9572R44CC%2CpostId_P2TBBjklli4dElUNzqGrc%2Crevision_~MjAyNi0xMC0yOFQwMjo1NjowMC4yNzc5NDRa%2Cp_Ii9jL1NwcmluZy9wL1AyVEJCamtsbGk0ZEVsVU56cUdyYyI%2Cs_sP-lBzBHYZKzCPRg.png"
  "og:image:height": "630"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "Spring AI 2.1.0-RC1 and 2.0.2 Available Now"
---

> Index of every page on this site: [llms.txt](https://www.angryecho.com/llms.txt)

# **Spring AI 2.1.0-RC1 and 2.0.2 Available Now**

On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-RC1 and 2.0.2 have been released and are now available from Maven Central!

[Release notes](https://github.com/spring-projects/spring-ai/releases/tag/v2.1.0-RC1) | [Upgrade notes](https://docs.spring.io/spring-ai/reference/2.1/upgrade-notes.html#upgrading-to-2-1-0) | [Reference documentation](https://docs.spring.io/spring-ai/reference/2.1/index.html)

2.1.0-RC1 builds on [2.1.0-M1](https://spring.io/blog/2026/09/25/spring-ai-2-1-0-M1-available-now) and delivers most of what we promised in its "What's next" section: message parts are now produced and consumed natively by the major chat models, and session memory arrives in Spring AI itself. It also adds tool call confirmation, and extends the pre-computed embeddings support with search by query vector.

## New in this release

**Message Parts across providers**

In M1, only `OpenAiResponsesChatModel` worked natively with `[MessagePart](https://docs.spring.io/spring-ai/reference/2.1/api/chatmodel.html#message-parts)` content. In this release the following `ChatModel` implementations produce and consume parts as well:

- OpenAI (Chat Completions)
- Anthropic
- Google GenAI
- Amazon Bedrock Converse
- Ollama
- Mistral AI
- DeepSeek

Reasoning, tool calls, and provider-specific blocks therefore keep their order and their opaque payloads, such as Anthropic thinking signatures and Gemini thought signatures, across a whole conversation. Code that uses the existing accessors (`getText()`, `getToolCalls()`, ...) keeps working. The message builders' setters now replace parts in place, so `UserMessage.builder().text(...)` followed by another call no longer leaves stale parts behind.

Two related details for OpenAI-compatible endpoints. `reasoning_content` is echoed back on assistant messages because some endpoints, such as DeepSeek in thinking mode, require it, while others, such as Groq, reject it. Replaying is now configurable with `spring.ai.openai.chat.replay-reasoning-content` (or `OpenAiChatOptions.replayReasoningContent`); it keeps sending the property by default, and `false` turns it off. And on the Responses API, the order of the parts of a user message is preserved, and file URLs are sent as `file_url`.

**Session Memory**

`ChatMemory` stores a flat list of messages per conversation id. Long-running conversations and agents need more than that, so Spring AI now includes a [session memory](https://docs.spring.io/spring-ai/reference/2.1/api/session.html), ported from the community [Spring AI Session](https://github.com/spring-ai-community/spring-ai-session) project.

A session keeps a conversation as an append-only log of events and builds the prompt from a view of that log:

- **Structured events.** Every message is a `SessionEvent`. Other event types, with names you can define yourself, can record what else happened in the same log.
- **Turn-aware compaction.** Triggers such as `TurnCountTrigger` decide when the history has grown too large, and a strategy decides what leaves the view. `WindowCompactionStrategy` keeps the last events, the last turns, or fits a token budget, and an optional `CompactionSummarizer` ( `ChatModelSummarizer`) can summarize what is dropped. A compaction always cuts on a turn boundary, so the model never sees a tool call without its result. Compaction never rewrites the log: it appends a boundary that defines the view from then on.
- **A repository SPI.** `InMemorySessionRepository` is meant for tests, and `JdbcSessionRepository` supports PostgreSQL, MySQL, MariaDB and H2, with idempotent appends and version-checked compaction. A store of your own can be verified against the contract tests in `spring-ai-test`.

To use it with a `ChatClient`, add the `spring-ai-starter-model-session-jdbc` starter, register the session advisors, and pass a session id with every call:

```
@Bean
ChatClient chatClient(ChatModel chatModel, SessionService sessionService) {
    return ChatClient.builder(chatModel)
        .defaultAdvisors(SessionAdvisors.builder(sessionService)
            .compaction(new TurnCountTrigger(20), WindowCompactionStrategy.builder().lastTurns(10).build())
            .build())
        .build();
}

String answer = chatClient.prompt()
    .user("Hello!")
    .advisors(SessionAdvisors.session("session-abc"))
    .call()
    .content();
```

A session that does not exist yet is created on first use, and the session id is required on every call: there is deliberately no default session, since a shared one would silently merge the histories of different users. The advisors keep no state of their own, so any application instance can run any turn of a session.

> `ChatMemory`, `MessageWindowChatMemory`, `ChatMemoryRepository`, `MessageChatMemoryAdvisor`, and the JDBC, Cassandra, Neo4j, MongoDB and Redis chat memory repositories are now **deprecated, for removal in 3.0.0**. Each deprecation names its replacement. Where there is no session counterpart yet (Cassandra, Neo4j, MongoDB, Redis, and the HSQLDB, Oracle, SQL Server and SQLite dialects), one is planned before 3.0.0. `VectorStoreChatMemoryAdvisor` stays, since sessions have no semantic recall counterpart yet. The advisor context key `ChatMemory.CONVERSATION_ID` now has a permanent home as `MemoryAdvisor.CONVERSATION_ID`, with the same value.

**Tool Call Confirmation**

Booking a flight, deleting a file or sending an email are actions a person may want to approve first. A tool can now ask for that:

```
class BookingTools {

    @Tool(description = "Book a flight", requiresConfirmation = true)
    String bookFlight(String flightNumber) {
        return bookingService.book(flightNumber);
    }
}
```

When the model calls such a tool, the tool-calling loop pauses before any call of the reply runs, and the reply goes back to your application listing the calls that wait for a decision. Your application collects a `ToolCallDecision` per call (allow, or deny with a message), runs the reply's calls with `ToolCallingManager.executeToolCalls(prompt, reply, decisions)`, and sends the results as its next request. A denied call answers the model with your message instead of running.

The loop keeps no state while it waits: the pause is an ordinary response and the resumption an ordinary request, so this survives restarts as long as your application keeps the conversation. Which calls need confirmation is decided by a `ToolCallConfirmationPolicy`: the default reads the tool's metadata, `forTools(...)` names tools you do not own, such as MCP tools, and a lambda can inspect the arguments, for example to confirm only transfers over a given amount. Policies can be combined with `or(...)`, and the `spring.ai.tools.confirmation.*` properties and `ToolCallConfirmationPolicy` beans are picked up by the auto-configuration. The feature is covered by integration tests against OpenAI, Gemini, Anthropic, Bedrock and Ollama. See [Tool Call Confirmation](https://docs.spring.io/spring-ai/reference/2.1/api/tools/tool-call-confirmation.html) in the reference documentation.

（节选）

> 原文： [Spring Blog｜Spring AI 2.1.0-RC1 and 2.0.2 Available Now](https://spring.io/blog/2026/10/23/spring-ai-2-1-0-RC1-available-now)，2026-10-23

排序方式 :

### **成为第一条评论！**

Nobody's responded to this post yet. Add your thoughts and get the conversation going.

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://www.angryecho.com/c/Spring/p/P2TBBjklli4dElUNzqGrc#post","@type":"DiscussionForumPosting","commentCount":0,"dateModified":"2026-10-28T02:56:00.277Z","datePublished":"2026-10-23T04:00:00.000Z","description":"On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-RC1 and 2.0.2 have been released and are now avail…","headline":"Spring AI 2.1.0-RC1 and 2.0.2 Available Now","isPartOf":"https://www.angryecho.com/c/Spring","mainEntityOfPage":"https://www.angryecho.com/c/Spring/p/P2TBBjklli4dElUNzqGrc","text":"On behalf of the Spring AI team and everyone who has contributed, I'm happy to announce that Spring AI 2.1.0-RC1 and 2.0.2 have been released and are now available from Maven Central!\n\nRelease notes | Upgrade notes | Reference documentation\n\n2.1.0-RC1 builds on 2.1.0-M1 and delivers most of what we promised in its \"What's next\" section: message parts are now produced and consumed natively by the major chat models, and session memory arrives in Spring AI itself. It also adds tool call confirmation, and extends the pre-computed embeddings support with search by query vector.\n\nNew in this release\n\nMessage Parts across providers\n\nIn M1, only OpenAiResponsesChatModel worked natively with MessagePart content. In this release the following ChatModel implementations produce and consume parts as well:\n\n\n\n\n\nOpenAI (Chat Completions)\n\n\n\nAnthropic\n\n\n\nGoogle GenAI\n\n\n\nAmazon Bedrock Converse\n\n\n\nOllama\n\n\n\nMistral AI\n\n\n\nDeepSeek\n\nReasoning, tool calls, and provider-specific blocks therefore keep their order and their opaque payloads, such as Anthropic thinking signatures and Gemini thought signatures, across a whole conversation. Code that uses the existing accessors (getText(), getToolCalls(), ...) keeps working. The message builders' setters now replace parts in place, so UserMessage.builder().text(...) followed by another call no longer leaves stale parts behind.\n\nTwo related details for OpenAI-compatible endpoints. reasoning_content is echoed back on assistant messages because some endpoints, such as DeepSeek in thinking mode, require it, while others, such as Groq, reject it. Replaying is now configurable with spring.ai.openai.chat.replay-reasoning-content (or OpenAiChatOptions.replayReasoningContent); it keeps sending the property by default, and false turns it off. And on the Responses API, the order of the parts of a user message is preserved, and file URLs are sent as file_url.\n\nSession Memory\n\nChatMemory stores a flat list of messages per conversation id. Long-running conversations and agents need more than that, so Spring AI now includes a session memory, ported from the community Spring AI Session project.\n\nA session keeps a conversation as an append-only log of events and builds the prompt from a view of that log:\n\n\n\n\n\nStructured events. Every message is a SessionEvent. Other event types, with names you can define yourself, can record what else happened in the same log.\n\n\n\nTurn-aware compaction. Triggers such as TurnCountTrigger decide when the history has grown too large, and a strategy decides what leaves the view. WindowCompactionStrategy keeps the last events, the last turns, or fits a token budget, and an optional CompactionSummarizer (ChatModelSummarizer) can summarize what is dropped. A compaction always cuts on a turn boundary, so the model never sees a tool call without its result. Compaction never rewrites the log: it appends a boundary that defines the view from then on.\n\n\n\nA repository SPI. InMemorySessionRepository is meant for tests, and JdbcSessionRepository supports PostgreSQL, MySQL, MariaDB and H2, with idempotent appends and version-checked compaction. A store of your own can be verified against the contract tests in spring-ai-test.\n\nTo use it with a ChatClient, add the spring-ai-starter-model-session-jdbc starter, register the session advisors, and pass a session id with every call:\n\n@Bean\nChatClient chatClient(ChatModel chatModel, SessionService sessionService) {\n    return ChatClient.builder(chatModel)\n        .defaultAdvisors(SessionAdvisors.builder(sessionService)\n            .compaction(new TurnCountTrigger(20), WindowCompactionStrategy.builder().lastTurns(10).build())\n            .build())\n        .build();\n}\n\nString answer = chatClient.prompt()\n    .user(\"Hello!\")\n    .advisors(SessionAdvisors.session(\"session-abc\"))\n    .call()\n    .content();\n\nA session that does not exist yet is created on first use, and the session id is required on every call: there is deliberately no default session, since a shared one would silently merge the histories of different users. The advisors keep no state of their own, so any application instance can run any turn of a session.\n\n\n\nChatMemory, MessageWindowChatMemory, ChatMemoryRepository, MessageChatMemoryAdvisor, and the JDBC, Cassandra, Neo4j, MongoDB and Redis chat memory repositories are now deprecated, for removal in 3.0.0. Each deprecation names its replacement. Where there is no session counterpart yet (Cassandra, Neo4j, MongoDB, Redis, and the HSQLDB, Oracle, SQL Server and SQLite dialects), one is planned before 3.0.0. VectorStoreChatMemoryAdvisor stays, since sessions have no semantic recall counterpart yet. The advisor context key ChatMemory.CONVERSATION_ID now has a permanent home as MemoryAdvisor.CONVERSATION_ID, with the same value.\n\nTool Call Confirmation\n\nBooking a flight, deleting a file or sending an email are actions a person may want to approve first. A tool can now ask for that:\n\nclass BookingTools {\n\n    @Tool(description = \"Book a flight\", requiresConfirmation = true)\n    String bookFlight(String flightNumber) {\n        return bookingService.book(flightNumber);\n    }\n}\n\nWhen the model calls such a tool, the tool-calling loop pauses before any call of the reply runs, and the reply goes back to your application listing the calls that wait for a decision. Your application collects a ToolCallDecision per call (allow, or deny with a message), runs the reply's calls with ToolCallingManager.executeToolCalls(prompt, reply, decisions), and sends the results as its next request. A denied call answers the model with your message instead of running.\n\nThe loop keeps no state while it waits: the pause is an ordinary response and the resumption an ordinary request, so this survives restarts as long as your application keeps the conversation. Which calls need confirmation is decided by a ToolCallConfirmationPolicy: the default reads the tool's metadata, forTools(...) names tools you do not own, such as MCP tools, and a lambda can inspect the arguments, for example to confirm only transfers over a given amount. Policies can be combined with or(...), and the spring.ai.tools.confirmation.* properties and ToolCallConfirmationPolicy beans are picked up by the auto-configuration. The feature is covered by integration tests against OpenAI, Gemini, Anthropic, Bedrock and Ollama. See Tool Call Confirmation in the reference documentation.\n\n（节选）\n\n\n\n原文：Spring Blog｜Spring AI 2.1.0-RC1 and 2.0.2 Available Now，2026-10-23","url":"https://www.angryecho.com/c/Spring/p/P2TBBjklli4dElUNzqGrc","author":{"@type":"Person","name":"Ted Broberg","url":"https://www.angryecho.com/u/P7H10343139"},"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/DislikeAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":0},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":0}]}]}
```

## Sitemap

See the full [sitemap](https://www.angryecho.com/sitemap.md) for all pages.
