Conversation history

Persist a conversation with its design and resume it later.

A conversation with the assistant has a name, its messages, and the design it worked on. You can keep it in your own database and open it again later, with the design as the conversation left it.

Storage

Pass a name for the conversation as chatSessionId, and two functions: onSaveChatSession stores the record, and onGetChatSession returns it:

import { VideoEditor, type ChatSession } from '@layermetry/media-editor/react';

// Your backend stores one record per conversation. This example keeps them in localStorage.
async function saveChatSession(session: ChatSession) {
  localStorage.setItem(`chat:${session.id}`, JSON.stringify(session));
  console.log(`Saved ${session.id}: ${session.messages.length} messages, design ${session.draft ? 'included' : 'none'}`);
}

async function getChatSession(sessionId: string): Promise<ChatSession | null> {
  const stored = localStorage.getItem(`chat:${sessionId}`);
  console.log(`Loaded ${sessionId}: ${stored ? 'found' : 'new conversation'}`);
  return stored ? JSON.parse(stored) : null;
}

export default function App() {
  return (
    <div style={{ position: 'fixed', inset: 0 }}>
      <VideoEditor
        licenseKey="YOUR_LICENSE_KEY"
        onClose={() => console.log('The editor was closed')}
        mediaApiUrl="https://media.example.com"
        chatSessionId="campaign-42"
        onSaveChatSession={saveChatSession}
        onGetChatSession={getChatSession}
      />
    </div>
  );
}

The editor calls onSaveChatSession:

  • when the user opens a conversation that your database does not have yet, so it has a record before the first message;
  • at the end of every request;
  • for both conversations when the user presses New chat;
  • once more, without waiting, when the editor closes.

The record has these fields:

FieldTypeDescription
idstringThe name of the conversation, the same as chatSessionId.
schemaVersionnumberThe version of the record format. It is 1.
messagesarrayThe messages, in the format that the chat service reads.
draftobjectThe design, as a template record. See Saving and loading.
lastTurnIdstring or nullThe last request that the editor's panel ran.
createdAt, updatedAtstringDates in ISO 8601 format.

The editor waits for the Promise of onSaveChatSession. If it rejects, or takes longer than 30 seconds, the panel shows "Not saved — retry" with a button.

When you pass chatSessionId or onSaveChatSession, the editor stops keeping the conversation in the browser. Your database then holds the only copy.

Pass onUploadAsset too. The design in each record is built like a saved template, so without it every picture from the user's computer is stored inside the record, on every save.

Default: without these props, the editor names each conversation itself and keeps it in the browser only. The console says so once.

Resuming a conversation

Pass the same chatSessionId again. When the assistant panel opens, the editor calls onGetChatSession. The record you return brings back the messages and the design:

What your function returns decides what happens:

Return valueWhat happens
A record with draftThe messages and the design open. The design wins over defaultTemplate.
A record without draftThe messages open. The canvas keeps defaultTemplate, or stays empty.
A record with an empty messages listThe conversation exists and is new.
nullYour database does not know the name. The editor starts an empty conversation with that name, and saves it.

Without onGetChatSession, pass the stored messages as initialMessages instead. That restores the messages only, not the design.

A design whose pictures are no longer in your storage still opens. The console names each missing item, and the rest is drawn.

To follow the conversation as it happens, use onChatEvent. See Custom chat UI.

Additional resources

On this page