webui: Add option to pre-encode conversation for faster next turns (#21034)
This commit is contained in:
committed by
GitHub
parent
b54cb2e3d0
commit
75511a8d7e
@@ -58,6 +58,7 @@ class ChatStore {
|
||||
chatLoadingStates = new SvelteMap<string, boolean>();
|
||||
chatStreamingStates = new SvelteMap<string, { response: string; messageId: string }>();
|
||||
private abortControllers = new SvelteMap<string, AbortController>();
|
||||
private preEncodeAbortController: AbortController | null = null;
|
||||
private processingStates = new SvelteMap<string, ApiProcessingState | null>();
|
||||
private conversationStateTimestamps = new SvelteMap<string, ConversationStateEntry>();
|
||||
private activeConversationId = $state<string | null>(null);
|
||||
@@ -462,6 +463,9 @@ class ChatStore {
|
||||
const activeConv = conversationsStore.activeConversation;
|
||||
if (activeConv && this.isChatLoadingInternal(activeConv.id)) return;
|
||||
|
||||
// Cancel any in-flight pre-encode request
|
||||
this.cancelPreEncode();
|
||||
|
||||
// Consume MCP resource attachments - converts them to extras and clears the live store
|
||||
const resourceExtras = mcpStore.consumeResourceAttachmentsAsExtras();
|
||||
const allExtras = resourceExtras.length > 0 ? [...(extras || []), ...resourceExtras] : extras;
|
||||
@@ -724,6 +728,16 @@ class ChatStore {
|
||||
|
||||
if (onComplete) onComplete(streamedContent);
|
||||
if (isRouterMode()) modelsStore.fetchRouterModels().catch(console.error);
|
||||
// Pre-encode conversation in KV cache for faster next turn
|
||||
if (config().preEncodeConversation) {
|
||||
this.triggerPreEncode(
|
||||
allMessages,
|
||||
assistantMessage,
|
||||
streamedContent,
|
||||
effectiveModel,
|
||||
!!config().excludeReasoningFromContext
|
||||
);
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
this.setStreamingActive(false);
|
||||
@@ -911,6 +925,7 @@ class ChatStore {
|
||||
async regenerateMessage(messageId: string): Promise<void> {
|
||||
const activeConv = conversationsStore.activeConversation;
|
||||
if (!activeConv || this.isChatLoadingInternal(activeConv.id)) return;
|
||||
this.cancelPreEncode();
|
||||
const result = this.getMessageByIdWithRole(messageId, MessageRole.ASSISTANT);
|
||||
if (!result) return;
|
||||
const { index: messageIndex } = result;
|
||||
@@ -940,6 +955,7 @@ class ChatStore {
|
||||
async regenerateMessageWithBranching(messageId: string, modelOverride?: string): Promise<void> {
|
||||
const activeConv = conversationsStore.activeConversation;
|
||||
if (!activeConv || this.isChatLoadingInternal(activeConv.id)) return;
|
||||
this.cancelPreEncode();
|
||||
try {
|
||||
const idx = conversationsStore.findMessageIndex(messageId);
|
||||
if (idx === -1) return;
|
||||
@@ -1616,6 +1632,42 @@ class ChatStore {
|
||||
|
||||
return apiOptions;
|
||||
}
|
||||
|
||||
private cancelPreEncode(): void {
|
||||
if (this.preEncodeAbortController) {
|
||||
this.preEncodeAbortController.abort();
|
||||
this.preEncodeAbortController = null;
|
||||
}
|
||||
}
|
||||
|
||||
private async triggerPreEncode(
|
||||
allMessages: DatabaseMessage[],
|
||||
assistantMessage: DatabaseMessage,
|
||||
assistantContent: string,
|
||||
model?: string | null,
|
||||
excludeReasoning?: boolean
|
||||
): Promise<void> {
|
||||
this.cancelPreEncode();
|
||||
this.preEncodeAbortController = new AbortController();
|
||||
|
||||
const signal = this.preEncodeAbortController.signal;
|
||||
|
||||
try {
|
||||
const allIdle = await ChatService.areAllSlotsIdle(model, signal);
|
||||
if (!allIdle || signal.aborted) return;
|
||||
|
||||
const messagesWithAssistant: DatabaseMessage[] = [
|
||||
...allMessages,
|
||||
{ ...assistantMessage, content: assistantContent }
|
||||
];
|
||||
|
||||
await ChatService.preEncode(messagesWithAssistant, model, excludeReasoning, signal);
|
||||
} catch (err) {
|
||||
if (!isAbortError(err)) {
|
||||
console.warn('[ChatStore] Pre-encode failed:', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const chatStore = new ChatStore();
|
||||
|
||||
Reference in New Issue
Block a user