feat(history): add configurable chat history storage with MySQL persistence#334
feat(history): add configurable chat history storage with MySQL persistence#334moyiliyi wants to merge 1 commit into
Conversation
101ec47 to
3d4441e
Compare
|
@moyiliyi can you rebase your branch, it seems to show more changes than expected in the diffs. couple of comments.
@pjdoland could you also review? |
d6a7d60 to
4122265
Compare
4122265 to
3fb644f
Compare
|
Hi @mbektas , Thanks for the review. I rebased this branch and also refactored the implementation. I think my previous PR description caused confusion, let me claifiy it : History mode semanticsBefore PR, the system had some short-lived runtime history during an active session, but chat history was still mostly implicit and weakly defined:
This PR makes those semantics explicit, so users and the codebase can reason about them consistently. The history modes in this PR are:
Mode comparison
For your comments
Not exactly. The previous default behavior was a bit of a hybrid. Before this change, there was still a short in-memory history during the current live session. From the user's point of view after a browser refresh, the old behavior was much closer to what I now call In this PR, the default is now
During the active session, messages are still accumulated in runtime history and sent back as context for later turns.
That is a very good point, and I agree. Based on that feedback, I refactored the history persistence layer so it is no longer MySQL-specific. The user-facing concept is now a
The abstraction lives in:
The settings UI is driven from backend metadata, so it should be possible to add others later if that would be useful. Implementation Details1. Session modelThe user-visible chat session in the sidebar is identified by
This is the primary session boundary from the user's point of view. Switching history storage starts a new 2. Storage & SanitizationI distinguish between three layers:
Runtime historyRuntime history is the live in-process history used while the current app/server process is alive.
Persisted historyWhen
The currently implemented backends are:
History is also scoped by resolved Model context and UI replayThe replay transcript and the provider input history are intentionally not the same thing.
but sanitizes history before provider reuse:
That is the role of FutureA natural next step after this PR would be user-facing conversation management, such as browsing, resuming, and eventually deleting past chat sessions. @mbektas @pjdoland I'd be grateful for any thoughts or feedback. |
| if reasoning is not None: | ||
| reasoning = str(reasoning) | ||
|
|
||
| tool_calls = None |
There was a problem hiding this comment.
I am not clear why this is still shown in this diff. it is from another commit. was the rebase done properly?
|
I don't think we should ship sqlite and mysql persistence implementations. they should be implemented in separate extensions. @pjdoland thoughts? |

Summary
This PR adds configurable chat history modes to Notebook Intelligence.
It introduces three explicit history modes:
nonefor ephemeral sessions with no restored history after refreshlocalfor local history with a configurable message limitmysqlfor persistent server-side historyIt also adds MySQL-backed storage for conversations, chat messages, and tool execution records, along with backend and frontend support for restoring history and listing recent conversations.
What changed
nonelocalmysqluser_id,chat_id,chat_mode, andconversation_idJUPYTERHUB_USERwhen available so persisted history can be scoped per user in JupyterHub-style deploymentsaskandagentflows can continue from the same conversation historyWhy
Before this change, chat history was effectively ephemeral: users could see messages in the current UI session, but history was lost on refresh.
This PR formalizes that behavior as
nonemode and adds two additional options:localfor lightweight history restorationmysqlfor persistent, user-scoped history storageIf users do not configure MySQL, they can still use
noneorlocalmode.The default mode is
local.If MySQL mode is selected but validation fails, the configuration is downgraded to
none, and the user is notified in the settings UI.Relation to #116
This PR mainly addresses the conversation storage and history persistence part of that discussion.
In MySQL mode, persisted conversations are associated with a user identity, using
JUPYTERHUB_USERwhen available and otherwise falling back to the authenticated server user. That makes the storage model more suitable for multi-user JupyterHub environments than the previous ephemeral behavior.UI Settings
nonemode:localmode:mysqlmode: