spring-projects / spring-projects/spring-ai

Support persisting tool_calls in JdbcChatMemoryRepository

Open
#3,342 0 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 10h
Merged PRs (30d)
5

Description

Expected Behavior

JdbcChatMemoryRepository should persist and restore the tool_calls field for AssistantMessages that use tool calling (i.e., function-calling).

Specifically:

  • Add a tool_calls TEXT NULL column to the schema
  • Serialize the list of ToolCall objects to JSON on insert
  • Deserialize and rehydrate AssistantMessage(null, toolCalls) when loading from the database

This ensures that responses such as:

new AssistantMessage(null, toolCalls)

...can be stored and later reused without violating OpenAI's API requirements.


Current Behavior

Currently, JdbcChatMemoryRepository only stores the content field. When an AssistantMessage has content = null and non-empty toolCalls, the following happens:

  • The toolCalls are silently discarded during persistence
  • Upon loading, the message becomes: content = null, toolCalls = []
  • This leads to a malformed payload when used in a follow-up prompt:
{ "role": "assistant", "content": null }

Which violates the OpenAI API spec:

If content is null, a non-empty tool_calls array must be present

Resulting in:

  "error": {
    "message": "Invalid value for 'content': expected a string, got null.",
    "type": "invalid_request_error",
    "param": "messages.[3].content",
    "code": null
  }

Context

Tool calling is a core feature of OpenAI and Azure OpenAI LLMs. Without persisting tool_calls, JDBC-based chat memory implementations cannot reconstruct valid assistant messages, causing:

  • 400 API errors
  • Broken multi-turn flows
  • Prompt history loss

This makes JdbcChatMemoryRepository incompatible with modern LLM usage patterns.


Alternatives considered

  • In-memory chat memory works correctly (retains toolCalls)
  • Custom JDBC memory with JSON serialization (invasive)
  • Skipping such messages entirely (causes context loss)

Workaround

Avoid using JdbcChatMemoryRepository when tool calling is enabled. Use in-memory fallback instead.


Related

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at JdbcChatMemoryRepository and its schema definition, then trace the insert and load paths for AssistantMessage. Verify coverage for null content with non-empty toolCalls, including the schema change, JSON round trip, and restoration of the tool calls.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
database
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.