spring-projects / spring-projects/spring-ai
Support persisting tool_calls in JdbcChatMemoryRepository
Nobody has claimed this yet.
- 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 NULLcolumn to the schema - Serialize the list of
ToolCallobjects 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
toolCallsare 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
contentis null, a non-emptytool_callsarray 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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