Skip to content

Commit 75afbdc

Browse files
committed
Refactor: Rename context error state to maxContextError
Feature: Implement client-side maximum context length check
1 parent 4f8bd9b commit 75afbdc

File tree

3 files changed

+61
-52
lines changed

3 files changed

+61
-52
lines changed
Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
<script lang="ts">
22
import * as AlertDialog from '$lib/components/ui/alert-dialog';
33
import { AlertTriangle } from '@lucide/svelte';
4-
import { contextError, clearContextError } from '$lib/stores/chat.svelte';
4+
import { maxContextError, clearMaxContextError } from '$lib/stores/chat.svelte';
55
</script>
66

7-
<!-- Context Length Error Alert Dialog -->
87
<AlertDialog.Root
9-
open={contextError() !== null}
10-
onOpenChange={(open) => !open && clearContextError()}
8+
open={maxContextError() !== null}
9+
onOpenChange={(open) => !open && clearMaxContextError()}
1110
>
1211
<AlertDialog.Content>
1312
<AlertDialog.Header>
@@ -20,31 +19,37 @@
2019
</AlertDialog.Description>
2120
</AlertDialog.Header>
2221

23-
{#if contextError()}
22+
{#if maxContextError()}
2423
<div class="space-y-3 text-sm">
2524
<div class="bg-muted rounded-lg p-3">
2625
<div class="mb-2 font-medium">Token Usage:</div>
2726
<div class="text-muted-foreground space-y-1">
2827
<div>
29-
Estimated tokens: <span class="font-mono"
30-
>{contextError()?.estimatedTokens.toLocaleString()}</span
31-
>
28+
Estimated tokens:
29+
<span class="font-mono">
30+
{maxContextError()?.estimatedTokens.toLocaleString()}
31+
</span>
3232
</div>
33+
3334
<div>
34-
Maximum allowed: <span class="font-mono"
35-
>{contextError()?.maxAllowed.toLocaleString()}</span
36-
>
35+
Maximum allowed:
36+
<span class="font-mono">
37+
{maxContextError()?.maxAllowed.toLocaleString()}
38+
</span>
3739
</div>
40+
3841
<div>
39-
Context window: <span class="font-mono"
40-
>{contextError()?.maxContext.toLocaleString()}</span
41-
>
42+
Context window:
43+
<span class="font-mono">
44+
{maxContextError()?.maxContext.toLocaleString()}
45+
</span>
4246
</div>
4347
</div>
4448
</div>
4549

4650
<div>
4751
<div class="mb-2 font-medium">Suggestions:</div>
52+
4853
<ul class="text-muted-foreground list-inside list-disc space-y-1">
4954
<li>Shorten your message</li>
5055
<li>Remove some file attachments</li>
@@ -55,7 +60,7 @@
5560
{/if}
5661

5762
<AlertDialog.Footer>
58-
<AlertDialog.Action onclick={() => clearContextError()}>Got it</AlertDialog.Action>
63+
<AlertDialog.Action onclick={() => clearMaxContextError()}>Got it</AlertDialog.Action>
5964
</AlertDialog.Footer>
6065
</AlertDialog.Content>
6166
</AlertDialog.Root>

tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
activeConversation,
99
isLoading,
1010
sendMessage,
11-
stopGeneration
11+
stopGeneration,
12+
setMaxContextError
1213
} from '$lib/stores/chat.svelte';
14+
import { wouldExceedContextLength } from '$lib/utils/token-estimation';
1315
import { fade, fly, slide } from 'svelte/transition';
1416
import { AUTO_SCROLL_THRESHOLD } from '$lib/constants/auto-scroll';
1517
import { navigating } from '$app/state';
@@ -83,6 +85,30 @@
8385
files?: ChatUploadedFile[]
8486
): Promise<boolean> {
8587
const extras = files ? await parseFilesToMessageExtras(files) : undefined;
88+
const maxContextLength = serverStore.serverProps?.default_generation_settings.n_ctx;
89+
90+
if (maxContextLength) {
91+
const contextCheck = wouldExceedContextLength(
92+
activeMessages(),
93+
message,
94+
extras,
95+
maxContextLength
96+
);
97+
98+
if (contextCheck.wouldExceed) {
99+
const errorMessage = `Message too long for context window. Estimated tokens: ${contextCheck.estimatedTokens.toLocaleString()}, Maximum allowed: ${contextCheck.maxAllowed.toLocaleString()} (Context: ${maxContextLength.toLocaleString()})`;
100+
101+
setMaxContextError({
102+
message: errorMessage,
103+
estimatedTokens: contextCheck.estimatedTokens,
104+
maxAllowed: contextCheck.maxAllowed,
105+
maxContext: maxContextLength
106+
});
107+
108+
return false;
109+
}
110+
}
111+
86112
await sendMessage(message, extras);
87113
scrollChatToBottom();
88114
@@ -147,12 +173,12 @@
147173
<div class="conversation-chat-form rounded-t-3xl pb-4">
148174
<ChatForm
149175
isLoading={isLoading()}
150-
showHelperText={false}
176+
onFileRemove={handleFileRemove}
177+
onFileUpload={handleFileUpload}
151178
onSend={handleSendMessage}
152179
onStop={() => stopGeneration()}
180+
showHelperText={false}
153181
bind:uploadedFiles
154-
onFileUpload={handleFileUpload}
155-
onFileRemove={handleFileRemove}
156182
/>
157183
</div>
158184
</div>

tools/server/webui/src/lib/stores/chat.svelte.ts

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { DatabaseService } from '$lib/services';
33
import { goto } from '$app/navigation';
44
import { browser } from '$app/environment';
55
import { extractPartialThinking } from '$lib/utils/thinking';
6-
import { wouldExceedContextLength } from '$lib/utils/token-estimation';
7-
import { serverStore } from '$lib/stores/server.svelte';
86
import { config } from '$lib/stores/settings.svelte';
97

108
class ChatStore {
@@ -14,7 +12,7 @@ class ChatStore {
1412
currentResponse = $state('');
1513
isInitialized = $state(false);
1614
isLoading = $state(false);
17-
contextError = $state<{ message: string; estimatedTokens: number; maxAllowed: number; maxContext: number } | null>(null);
15+
maxContextError = $state<{ message: string; estimatedTokens: number; maxAllowed: number; maxContext: number } | null>(null);
1816
private chatService = new ChatService();
1917

2018
constructor() {
@@ -242,32 +240,6 @@ class ChatStore {
242240
async sendMessage(content: string, extras?: DatabaseMessageExtra[]): Promise<void> {
243241
if (!content.trim() || this.isLoading) return;
244242

245-
// Check context length BEFORE creating conversation or processing anything
246-
const maxContextLength = serverStore.serverProps?.default_generation_settings.n_ctx;
247-
if (maxContextLength) {
248-
const contextCheck = wouldExceedContextLength(
249-
this.activeMessages,
250-
content,
251-
extras,
252-
maxContextLength
253-
);
254-
255-
if (contextCheck.wouldExceed) {
256-
const errorMessage = `Message too long for context window. Estimated tokens: ${contextCheck.estimatedTokens.toLocaleString()}, Maximum allowed: ${contextCheck.maxAllowed.toLocaleString()} (Context: ${maxContextLength.toLocaleString()})`;
257-
console.error('Context length exceeded:', errorMessage);
258-
259-
// Set context error state for UI to display alert dialog
260-
this.contextError = {
261-
message: errorMessage,
262-
estimatedTokens: contextCheck.estimatedTokens,
263-
maxAllowed: contextCheck.maxAllowed,
264-
maxContext: maxContextLength
265-
};
266-
// Early return - prevent any conversation creation or message processing
267-
return;
268-
}
269-
}
270-
271243
let isNewConversation = false;
272244

273245
if (!this.activeConversation) {
@@ -340,8 +312,13 @@ class ChatStore {
340312
/**
341313
* Clear context error state
342314
*/
343-
clearContextError(): void {
344-
this.contextError = null;
315+
clearMaxContextError(): void {
316+
this.maxContextError = null;
317+
}
318+
319+
// Allow external modules to set context error without importing heavy utils here
320+
setMaxContextError(error: { message: string; estimatedTokens: number; maxAllowed: number; maxContext: number } | null): void {
321+
this.maxContextError = error;
345322
}
346323

347324
private async savePartialResponseIfNeeded() {
@@ -573,7 +550,7 @@ export const activeMessages = () => chatStore.activeMessages;
573550
export const isLoading = () => chatStore.isLoading;
574551
export const currentResponse = () => chatStore.currentResponse;
575552
export const isInitialized = () => chatStore.isInitialized;
576-
export const contextError = () => chatStore.contextError;
553+
export const maxContextError = () => chatStore.maxContextError;
577554

578555
export const createConversation = chatStore.createConversation.bind(chatStore);
579556
export const loadConversation = chatStore.loadConversation.bind(chatStore);
@@ -584,7 +561,8 @@ export const updateConversationName = chatStore.updateConversationName.bind(chat
584561
export const deleteConversation = chatStore.deleteConversation.bind(chatStore);
585562
export const clearActiveConversation = chatStore.clearActiveConversation.bind(chatStore);
586563
export const gracefulStop = chatStore.gracefulStop.bind(chatStore);
587-
export const clearContextError = chatStore.clearContextError.bind(chatStore);
564+
export const clearMaxContextError = chatStore.clearMaxContextError.bind(chatStore);
565+
export const setMaxContextError = chatStore.setMaxContextError.bind(chatStore);
588566

589567
export function stopGeneration() {
590568
chatStore.stopGeneration();

0 commit comments

Comments
 (0)