mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2026-09-20 01:31:42 +02:00
Merge branch 'upstream' into concedo_experimental
# Conflicts: # .devops/intel.Dockerfile # .github/workflows/python-type-check.yml # embd_res/templates/Qwen3.5-4B.jinja # examples/model-conversion/scripts/causal/compare-logits.py # examples/model-conversion/scripts/utils/check-nmse.py # examples/model-conversion/scripts/utils/compare_tokens.py # examples/model-conversion/scripts/utils/semantic_check.py # examples/sycl/build.sh # examples/sycl/run-llama2.sh # ggml/src/ggml-hexagon/htp/flash-attn-ops.c # ggml/src/ggml-hexagon/htp/hex-dma.h # ggml/src/ggml-hexagon/htp/rope-ops.c # scripts/gen-unicode-data.py # tests/test-chat.cpp
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
showRaw = undefined,
|
||||
aliases,
|
||||
tags,
|
||||
class: className = ''
|
||||
class: className = '',
|
||||
...rest
|
||||
}: Props = $props();
|
||||
|
||||
const badgeClass =
|
||||
@@ -36,9 +37,9 @@
|
||||
</script>
|
||||
|
||||
{#if resolvedShowRaw}
|
||||
<TruncatedText class="font-medium {className}" showTooltip={false} text={modelId} />
|
||||
<TruncatedText class="font-medium {className}" showTooltip={false} text={modelId} {...rest} />
|
||||
{:else}
|
||||
<span class="flex min-w-0 flex-wrap items-center gap-1 {className}">
|
||||
<span class="flex min-w-0 flex-wrap items-center gap-1 {className}" {...rest}>
|
||||
<span class="min-w-0 truncate font-medium">
|
||||
{#if showOrgName && parsed.orgName && !(aliases && aliases.length > 0)}{parsed.orgName}/{/if}{displayName}
|
||||
</span>
|
||||
|
||||
@@ -271,50 +271,49 @@
|
||||
{#if isRouter}
|
||||
<DropdownMenu.Root bind:open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<DropdownMenu.Trigger
|
||||
disabled={disabled || updating}
|
||||
onclick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class={cn(
|
||||
`inline-grid cursor-pointer grid-cols-[1fr_auto_1fr] items-center gap-1.5 rounded-sm bg-muted-foreground/10 px-1.5 py-1 text-xs transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60`,
|
||||
!isCurrentModelInCache
|
||||
? 'bg-red-400/10 !text-red-400 hover:bg-red-400/20 hover:text-red-400'
|
||||
: forceForegroundText
|
||||
class={cn(
|
||||
`inline-grid cursor-pointer grid-cols-[1fr_auto_1fr] items-center gap-1.5 rounded-sm bg-muted-foreground/10 px-1.5 py-1 text-xs transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-60`,
|
||||
!isCurrentModelInCache
|
||||
? 'bg-red-400/10 !text-red-400 hover:bg-red-400/20 hover:text-red-400'
|
||||
: forceForegroundText
|
||||
? 'text-foreground'
|
||||
: isHighlightedCurrentModelActive
|
||||
? 'text-foreground'
|
||||
: isHighlightedCurrentModelActive
|
||||
? 'text-foreground'
|
||||
: 'text-muted-foreground',
|
||||
isOpen ? 'text-foreground' : ''
|
||||
)}
|
||||
style="max-width: min(calc(100cqw - 9rem), 20rem)"
|
||||
disabled={disabled || updating}
|
||||
>
|
||||
<Package class="h-3.5 w-3.5" />
|
||||
: 'text-muted-foreground',
|
||||
isOpen ? 'text-foreground' : ''
|
||||
)}
|
||||
style="max-width: min(calc(100cqw - 9rem), 20rem)"
|
||||
disabled={disabled || updating}
|
||||
>
|
||||
<Package class="h-3.5 w-3.5" />
|
||||
|
||||
{#if selectedOption}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger class="min-w-0 overflow-hidden">
|
||||
<ModelId modelId={selectedOption.model} class="min-w-0" showOrgName />
|
||||
</Tooltip.Trigger>
|
||||
{#if selectedOption}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<!-- prevent another nested button element -->
|
||||
{#snippet child({ props })}
|
||||
<ModelId
|
||||
modelId={selectedOption.model}
|
||||
class="min-w-0 overflow-hidden"
|
||||
showOrgName
|
||||
{...props}
|
||||
/>
|
||||
{/snippet}
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content>
|
||||
<p class="font-mono">{selectedOption.model}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
{:else}
|
||||
<span class="min-w-0 font-medium">Select model</span>
|
||||
{/if}
|
||||
<Tooltip.Content>
|
||||
<p class="font-mono">{selectedOption.model}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
{:else}
|
||||
<span class="min-w-0 font-medium">Select model</span>
|
||||
{/if}
|
||||
|
||||
{#if updating || isLoadingModel}
|
||||
<Loader2 class="h-3 w-3.5 animate-spin" />
|
||||
{:else}
|
||||
<ChevronDown class="h-3 w-3.5" />
|
||||
{/if}
|
||||
</button>
|
||||
{#if updating || isLoadingModel}
|
||||
<Loader2 class="h-3 w-3.5 animate-spin" />
|
||||
{:else}
|
||||
<ChevronDown class="h-3 w-3.5" />
|
||||
{/if}
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content
|
||||
@@ -407,8 +406,16 @@
|
||||
|
||||
{#if selectedOption}
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger class="min-w-0 overflow-hidden">
|
||||
<ModelId modelId={selectedOption.model} class="min-w-0" showOrgName />
|
||||
<Tooltip.Trigger>
|
||||
<!-- prevent another nested button element -->
|
||||
{#snippet child({ props })}
|
||||
<ModelId
|
||||
modelId={selectedOption.model}
|
||||
class="min-w-0 overflow-hidden"
|
||||
showOrgName
|
||||
{...props}
|
||||
/>
|
||||
{/snippet}
|
||||
</Tooltip.Trigger>
|
||||
|
||||
<Tooltip.Content>
|
||||
|
||||
@@ -39,7 +39,13 @@ import type {
|
||||
MCPResourceContent,
|
||||
MCPReadResourceResult
|
||||
} from '$lib/types';
|
||||
import { buildProxiedUrl, throwIfAborted, isAbortError, createBase64DataUrl } from '$lib/utils';
|
||||
import {
|
||||
buildProxiedUrl,
|
||||
buildProxiedHeaders,
|
||||
throwIfAborted,
|
||||
isAbortError,
|
||||
createBase64DataUrl
|
||||
} from '$lib/utils';
|
||||
|
||||
interface ToolResultContentItem {
|
||||
type: string;
|
||||
@@ -118,7 +124,7 @@ export class MCPService {
|
||||
const requestInit: RequestInit = {};
|
||||
|
||||
if (config.headers) {
|
||||
requestInit.headers = config.headers;
|
||||
requestInit.headers = buildProxiedHeaders(config.headers);
|
||||
}
|
||||
|
||||
if (config.credentials) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
filterByLeafNodeId,
|
||||
findDescendantMessages,
|
||||
findLeafNode,
|
||||
findMessageById,
|
||||
isAbortError
|
||||
} from '$lib/utils';
|
||||
import {
|
||||
@@ -416,7 +417,7 @@ class ChatStore {
|
||||
if (!activeConv) return false;
|
||||
try {
|
||||
const allMessages = await conversationsStore.getConversationMessages(activeConv.id);
|
||||
const systemMessage = allMessages.find((m) => m.id === messageId);
|
||||
const systemMessage = findMessageById(allMessages, messageId);
|
||||
if (!systemMessage || systemMessage.role !== MessageRole.SYSTEM) return false;
|
||||
const rootMessage = allMessages.find((m) => m.type === 'root' && m.parent === null);
|
||||
if (!rootMessage) return false;
|
||||
@@ -878,7 +879,7 @@ class ChatStore {
|
||||
const msg = conversationsStore.activeMessages[idx];
|
||||
if (msg.role !== MessageRole.ASSISTANT) return;
|
||||
const allMessages = await conversationsStore.getConversationMessages(activeConv.id);
|
||||
const parentMessage = allMessages.find((m) => m.id === msg.parent);
|
||||
const parentMessage = findMessageById(allMessages, msg.parent);
|
||||
if (!parentMessage) return;
|
||||
this.setChatLoading(activeConv.id, true);
|
||||
this.clearChatStreaming(activeConv.id);
|
||||
@@ -928,7 +929,7 @@ class ChatStore {
|
||||
if (!activeConv)
|
||||
return { totalCount: 0, userMessages: 0, assistantMessages: 0, messageTypes: [] };
|
||||
const allMessages = await conversationsStore.getConversationMessages(activeConv.id);
|
||||
const messageToDelete = allMessages.find((m) => m.id === messageId);
|
||||
const messageToDelete = findMessageById(allMessages, messageId);
|
||||
|
||||
// For system messages, don't count descendants as they will be preserved (reparented to root)
|
||||
if (messageToDelete?.role === MessageRole.SYSTEM) {
|
||||
@@ -975,7 +976,7 @@ class ChatStore {
|
||||
if (!activeConv) return;
|
||||
try {
|
||||
const allMessages = await conversationsStore.getConversationMessages(activeConv.id);
|
||||
const messageToDelete = allMessages.find((m) => m.id === messageId);
|
||||
const messageToDelete = findMessageById(allMessages, messageId);
|
||||
|
||||
if (!messageToDelete) return;
|
||||
|
||||
@@ -1024,7 +1025,7 @@ class ChatStore {
|
||||
this.clearChatStreaming(activeConv.id);
|
||||
|
||||
const allMessages = await conversationsStore.getConversationMessages(activeConv.id);
|
||||
const dbMessage = allMessages.find((m) => m.id === messageId);
|
||||
const dbMessage = findMessageById(allMessages, messageId);
|
||||
|
||||
if (!dbMessage) {
|
||||
this.setChatLoading(activeConv.id, false);
|
||||
@@ -1280,7 +1281,10 @@ class ChatStore {
|
||||
|
||||
let messageIdForResponse: string;
|
||||
|
||||
if (msg.children.length === 0) {
|
||||
const dbMsg = findMessageById(allMessages, msg.id);
|
||||
const hasChildren = dbMsg ? dbMsg.children.length > 0 : msg.children.length > 0;
|
||||
|
||||
if (!hasChildren) {
|
||||
// No responses after this message — update in place instead of branching
|
||||
const updates: Partial<DatabaseMessage> = {
|
||||
content: newContent,
|
||||
|
||||
@@ -17,6 +17,17 @@
|
||||
|
||||
import { MessageRole } from '$lib/enums';
|
||||
|
||||
/**
|
||||
* Finds a message by its ID in the given messages array.
|
||||
*/
|
||||
export function findMessageById(
|
||||
messages: readonly DatabaseMessage[],
|
||||
id: string | null | undefined
|
||||
): DatabaseMessage | undefined {
|
||||
if (!id) return undefined;
|
||||
return messages.find((m) => m.id === id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters messages to get the conversation path from root to a specific leaf node.
|
||||
* If the leafNodeId doesn't exist, returns the path with the latest timestamp.
|
||||
|
||||
@@ -19,6 +19,21 @@ export function buildProxiedUrl(targetUrl: string): URL {
|
||||
return proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap original headers for proxying through the CORS proxy. This avoids issues with duplicated llama.cpp-specific and target headers when using the CORS proxy.
|
||||
* @param headers - The original headers to be proxied to target
|
||||
* @returns List of "wrapped" headers to be sent to the CORS proxy
|
||||
*/
|
||||
export function buildProxiedHeaders(headers: Record<string, string>): Record<string, string> {
|
||||
const proxiedHeaders: Record<string, string> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
proxiedHeaders[`X-Proxy-Header-${key}`] = value;
|
||||
}
|
||||
|
||||
return proxiedHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a proxied URL string for use in fetch requests.
|
||||
* @param targetUrl - The original URL to proxy
|
||||
|
||||
@@ -22,6 +22,7 @@ export { default as autoResizeTextarea } from './autoresize-textarea';
|
||||
// Branching utilities
|
||||
export {
|
||||
filterByLeafNodeId,
|
||||
findMessageById,
|
||||
findLeafNode,
|
||||
findDescendantMessages,
|
||||
getMessageSiblings,
|
||||
@@ -38,7 +39,7 @@ export { highlightCode, detectIncompleteCodeBlock, type IncompleteCodeBlock } fr
|
||||
export { setConfigValue, getConfigValue, configToParameterRecord } from './config-helpers';
|
||||
|
||||
// CORS Proxy
|
||||
export { buildProxiedUrl, getProxiedUrlString } from './cors-proxy';
|
||||
export { buildProxiedUrl, getProxiedUrlString, buildProxiedHeaders } from './cors-proxy';
|
||||
|
||||
// Conversation utilities
|
||||
export { createMessageCountMap, getMessageCount } from './conversation-utils';
|
||||
|
||||
Reference in New Issue
Block a user