Maintaining Conversation History Across Sessions
NavTalk supports maintaining conversation history across multiple sessions, allowing the digital human to remember previous conversations and maintain context continuity.
Workflow Overview
The conversation history workflow follows this sequence:
- Store messages: Save user and assistant messages as they occur during the conversation
- Send configuration: When WebSocket connection opens, send
realtime.input_config message with voice, prompt, and optionally tools (for OpenAI models only)
- Load on connection: Wait for
realtime.session.created event
- Send history: Send stored user messages using
conversation.item.create messages
- Wait for ready: After sending history, wait for
realtime.session.updated event before starting audio input
Session configuration (voice, prompt, tools) is sent via realtime.input_config message immediately after the WebSocket connection opens. The conversation.item.create messages are only used to send conversation history after receiving realtime.session.created.The tools parameter is optional and only applicable when using OpenAI models (gpt-realtime, gpt-realtime-mini). Function calling is not supported by other AI models.
Follow these steps to implement persistent conversation history:
Store Conversation History
Save each conversation message to persistent storage as it occurs:const NavTalkMessageType = Object.freeze({
REALTIME_SESSION_CREATED: "realtime.session.created",
REALTIME_SESSION_UPDATED: "realtime.session.updated",
REALTIME_CONVERSATION_ITEM_COMPLETED: "realtime.conversation.item.input_audio_transcription.completed",
REALTIME_RESPONSE_AUDIO_TRANSCRIPT_DONE: "realtime.response.audio_transcript.done",
// ... other event types
});
// Save conversation history to localStorage
async function appendRealtimeChatHistory(role, content) {
// Get existing history from storage
let history = localStorage.getItem("realtimeChatHistory");
let realtimeChatHistory = history ? JSON.parse(history) : [];
// Add new message
realtimeChatHistory.push({ role, content });
// Save back to storage
localStorage.setItem("realtimeChatHistory", JSON.stringify(realtimeChatHistory));
}
// Call this function when receiving user transcription
socket.onmessage = async (event) => {
if (typeof event.data === 'string') {
const data = JSON.parse(event.data);
const nav_data = data.data;
// Save user message when transcription completes
if (nav_data && data.type === NavTalkMessageType.REALTIME_CONVERSATION_ITEM_COMPLETED) {
const transcript = nav_data.content;
if (transcript) {
await appendRealtimeChatHistory("user", transcript);
}
}
// Save AI response when complete
if (nav_data && data.type === NavTalkMessageType.REALTIME_RESPONSE_AUDIO_TRANSCRIPT_DONE) {
const transcript = nav_data.content;
if (transcript) {
await appendRealtimeChatHistory("assistant", transcript);
}
}
}
};
Load History on Session Start
When establishing a new WebSocket connection, load the stored history and send it to the server:async function sendSessionUpdate() {
// Load conversation history from storage
const history = localStorage.getItem("realtimeChatHistory");
const conversationHistory = history ? JSON.parse(history) : [];
// Session configuration (voice, model, instructions, etc.) is passed through URL parameters
// Only send user message history
conversationHistory.forEach((msg) => {
if (msg.role === "user") {
const messageConfig = {
type: "conversation.item.create",
item: {
type: "message",
role: "user",
content: [
{
type: "input_text",
text: msg.content
}
]
}
};
try {
// Send user messages from history
socket.send(JSON.stringify(messageConfig));
console.log("Sent historical message:", msg.content);
} catch (e) {
console.error("Error sending historical message:", e);
}
}
});
}
// Call this after receiving session.created
socket.onmessage = async (event) => {
if (typeof event.data === 'string') {
const data = JSON.parse(event.data);
if (data.type === NavTalkMessageType.REALTIME_SESSION_CREATED) {
console.log("Session created, sending history.");
await sendSessionUpdate();
}
if (data.type === NavTalkMessageType.REALTIME_SESSION_UPDATED) {
console.log("Session updated. Ready to receive audio.");
// Start recording audio here
}
}
};
Restore Conversation Display
When the page loads, restore the conversation history display for the user:// Restore conversation history display on page load
async function initConversationHistory() {
// Load history from storage
const historyStr = localStorage.getItem("realtimeChatHistory");
const realtimeChatHistory = historyStr ? JSON.parse(historyStr) : [];
// Render each historical message in the UI
if (realtimeChatHistory && realtimeChatHistory.length > 0) {
realtimeChatHistory.forEach(item => {
appendMessageToUI(item.role, item.content);
});
// Scroll to bottom to show latest messages
const chatContainer = document.querySelector('.chat-container');
if (chatContainer) {
chatContainer.scrollTop = chatContainer.scrollHeight;
}
}
}
function appendMessageToUI(role, content) {
const container = document.createElement('div');
container.classList.add('message', role === 'user' ? 'message-user' : 'message-assistant');
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
contentDiv.textContent = content;
container.appendChild(contentDiv);
const chatContainer = document.querySelector('.chat-container');
if (chatContainer) {
chatContainer.appendChild(container);
}
}
// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
initConversationHistory();
});
Important Notes
When sending historical messages via conversation.item.create, only user messages can be sent. AI-generated historical messages cannot be embedded this way.