add generation cancellation middleware and refactor chat/message workflows to support HTTP client disconnections
This commit is contained in:
+34
-11
@@ -201,6 +201,7 @@ export function createRepositories(db, config) {
|
||||
updateChatMessageDelivery: db.prepare("UPDATE chat_messages SET delivery_status = ?, error_message = ? WHERE id = ? AND chat_id = ?"),
|
||||
updateChatMessageSources: db.prepare("UPDATE chat_messages SET sources = ? WHERE id = ? AND chat_id = ?"),
|
||||
updateChatMessageThinking: db.prepare("UPDATE chat_messages SET thinking = ? WHERE id = ? AND chat_id = ?"),
|
||||
updateChatMessageLinks: db.prepare("UPDATE chat_messages SET parent_message_id = ?, retry_prompt_message_id = ? WHERE id = ? AND chat_id = ?"),
|
||||
getChatMessages: db.prepare(`
|
||||
SELECT thinking, sources, id, role, content, model_name, retry_variants, retry_active_index, retry_retries_used, retry_prompt_message_id, delivery_status, error_message, parent_message_id, created_at
|
||||
FROM chat_messages
|
||||
@@ -821,6 +822,8 @@ export function createRepositories(db, config) {
|
||||
|
||||
const importWorkspaceTransaction = db.transaction((username, workspace) => {
|
||||
const imported = {personas: 0, chats: 0, templates: 0};
|
||||
const personaIds = new Map();
|
||||
const importedChats = [];
|
||||
for (const persona of workspace.personas || []) {
|
||||
const personaId = statements.insertPersona.run(
|
||||
username,
|
||||
@@ -832,14 +835,15 @@ export function createRepositories(db, config) {
|
||||
persona.example_dialogues ?? null,
|
||||
persona.persona_type || "assistant"
|
||||
).lastInsertRowid;
|
||||
statements.insertPersonaVersion.run(personaId, username, 1, JSON.stringify(persona));
|
||||
if (persona.sourceId != null) personaIds.set(persona.sourceId, Number(personaId));
|
||||
statements.insertPersonaVersion.run(personaId, username, 1, buildPersonaSnapshot(statements.getPersona.get(personaId, username)));
|
||||
imported.personas += 1;
|
||||
}
|
||||
|
||||
for (const template of workspace.templates || []) {
|
||||
statements.insertPromptTemplate.run(
|
||||
username,
|
||||
null,
|
||||
personaIds.get(template.persona_id) ?? null,
|
||||
template.name,
|
||||
template.description ?? null,
|
||||
template.category ?? null,
|
||||
@@ -851,11 +855,13 @@ export function createRepositories(db, config) {
|
||||
}
|
||||
|
||||
for (const chat of workspace.chats || []) {
|
||||
const assistantPersonaId = personaIds.get(chat.assistant_persona_id) ?? null;
|
||||
const userPersonaId = personaIds.get(chat.user_persona_id) ?? null;
|
||||
const chatId = statements.insertChatSession.run(
|
||||
username,
|
||||
chat.stored_title || chat.title || "Imported chat",
|
||||
null,
|
||||
null,
|
||||
assistantPersonaId,
|
||||
userPersonaId,
|
||||
chat.folder_name ?? null,
|
||||
chat.is_pinned ? 1 : 0,
|
||||
chat.archived_at ?? null,
|
||||
@@ -863,9 +869,8 @@ export function createRepositories(db, config) {
|
||||
chat.scenario_summary ?? null
|
||||
).lastInsertRowid;
|
||||
const importedMessageIds = new Map();
|
||||
importedChats.push({chat, chatId, messageIds: importedMessageIds});
|
||||
for (const message of chat.messages || []) {
|
||||
const mappedRetryPromptId = importedMessageIds.get(message.retryPromptMessageId) ?? null;
|
||||
const mappedParentId = importedMessageIds.get(message.parentMessageId) ?? null;
|
||||
const result = statements.insertChatMessage.run(
|
||||
chatId,
|
||||
message.role,
|
||||
@@ -874,10 +879,10 @@ export function createRepositories(db, config) {
|
||||
JSON.stringify(message.retryVariants || [message.content || ""]),
|
||||
Number(message.retryActiveIndex || 0),
|
||||
Number(message.retryRetriesUsed || 0),
|
||||
mappedRetryPromptId,
|
||||
null,
|
||||
message.deliveryStatus || "complete",
|
||||
message.errorMessage || null,
|
||||
mappedParentId
|
||||
null
|
||||
);
|
||||
if (message.sourceId != null) importedMessageIds.set(message.sourceId, Number(result.lastInsertRowid));
|
||||
if (message.sources) statements.updateChatMessageSources.run(JSON.stringify(message.sources), result.lastInsertRowid, chatId);
|
||||
@@ -893,6 +898,15 @@ export function createRepositories(db, config) {
|
||||
db.prepare("UPDATE attachments SET status='attached' WHERE id=? AND username=?").run(attachment.id, username);
|
||||
}
|
||||
}
|
||||
// Resolve links after every message has an ID, including forward references.
|
||||
for (const message of chat.messages || []) {
|
||||
statements.updateChatMessageLinks.run(
|
||||
importedMessageIds.get(message.parentMessageId) ?? null,
|
||||
importedMessageIds.get(message.retryPromptMessageId) ?? null,
|
||||
importedMessageIds.get(message.sourceId),
|
||||
chatId
|
||||
);
|
||||
}
|
||||
statements.updateChatGenerationSettings.run(
|
||||
chat.preferred_model ?? null,
|
||||
chat.temperature ?? null,
|
||||
@@ -918,15 +932,17 @@ export function createRepositories(db, config) {
|
||||
for (const memory of chat.memories || []) {
|
||||
const fact = String(memory?.fact || "").trim();
|
||||
if (!fact) continue;
|
||||
statements.insertChatMemory.run(username, chatId, null, null, fact);
|
||||
statements.insertChatMemory.run(username, chatId,
|
||||
memory.assistant_persona_id === undefined ? assistantPersonaId : personaIds.get(memory.assistant_persona_id) ?? null,
|
||||
memory.user_persona_id === undefined ? userPersonaId : personaIds.get(memory.user_persona_id) ?? null, fact);
|
||||
}
|
||||
const personaState = chat.persona_state || chat.personaChatState;
|
||||
if (personaState) {
|
||||
statements.upsertPersonaChatState.run(
|
||||
username,
|
||||
chatId,
|
||||
null,
|
||||
null,
|
||||
personaIds.get(personaState.assistant_persona_id) ?? null,
|
||||
personaIds.get(personaState.user_persona_id) ?? null,
|
||||
personaState.relationship_notes ?? personaState.relationshipNotes ?? null,
|
||||
personaState.tone ?? null,
|
||||
personaState.current_location ?? personaState.currentLocation ?? null,
|
||||
@@ -938,6 +954,13 @@ export function createRepositories(db, config) {
|
||||
imported.chats += 1;
|
||||
}
|
||||
|
||||
const chatsBySourceId = new Map(importedChats.filter(({chat}) => chat.sourceId != null).map(entry => [entry.chat.sourceId, entry]));
|
||||
for (const {chat, chatId} of importedChats) {
|
||||
const sourceChat = chatsBySourceId.get(chat.source_chat_id);
|
||||
statements.updateChatBranchSource.run(sourceChat?.chatId ?? null,
|
||||
sourceChat?.messageIds.get(chat.branched_from_message_id) ?? null, chatId, username);
|
||||
}
|
||||
|
||||
return imported;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user