114 lines
3.5 KiB
Svelte
114 lines
3.5 KiB
Svelte
<script lang="ts">
|
|
import { models } from '$lib/stores';
|
|
import WorkspaceFiles from './WorkspaceFiles.svelte';
|
|
|
|
export let selectedModels = [''];
|
|
export let disabled = false;
|
|
export let showSetDefault = true;
|
|
let showWorkspace = false;
|
|
|
|
const strengths = [
|
|
{ key: 'light', label: '轻度' },
|
|
{ key: 'medium', label: '中' },
|
|
{ key: 'high', label: '高' },
|
|
{ key: 'extreme', label: '极高' }
|
|
];
|
|
|
|
const allowed = new Set([
|
|
'chat-light',
|
|
'chat-medium',
|
|
'chat-high',
|
|
'chat-extreme',
|
|
'work-light',
|
|
'work-medium',
|
|
'work-high',
|
|
'work-extreme'
|
|
]);
|
|
|
|
$: selected = allowed.has(selectedModels?.[0]) ? selectedModels[0] : 'chat-medium';
|
|
$: mode = selected.startsWith('work-') ? 'work' : 'chat';
|
|
$: strength = selected.split('-')[1] ?? 'medium';
|
|
$: availableIds = new Set($models.map((model) => model.id));
|
|
|
|
$: if ($models.length > 0 && !availableIds.has(selectedModels?.[0])) {
|
|
const fallback = availableIds.has('chat-medium')
|
|
? 'chat-medium'
|
|
: [...allowed].find((id) => availableIds.has(id));
|
|
if (fallback) selectedModels = [fallback];
|
|
}
|
|
|
|
const chooseMode = (nextMode: 'chat' | 'work') => {
|
|
if (disabled || (mode === 'work' && nextMode === 'chat')) return;
|
|
const next = `${nextMode}-${strength}`;
|
|
if (availableIds.has(next)) selectedModels = [next];
|
|
};
|
|
|
|
const chooseStrength = (nextStrength: string) => {
|
|
if (disabled) return;
|
|
const next = `${mode}-${nextStrength}`;
|
|
if (availableIds.has(next)) selectedModels = [next];
|
|
};
|
|
</script>
|
|
|
|
<div class="flex max-w-fit items-center gap-2 select-none">
|
|
<div
|
|
class="flex items-center rounded-xl bg-gray-100/90 p-1 text-sm dark:bg-gray-800/90"
|
|
aria-label="Agent mode"
|
|
>
|
|
<button
|
|
type="button"
|
|
class="rounded-lg px-3 py-1.5 font-medium transition {mode === 'chat'
|
|
? 'bg-white text-gray-900 shadow-sm dark:bg-gray-700 dark:text-white'
|
|
: 'text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200'}"
|
|
on:click={() => chooseMode('chat')}
|
|
disabled={disabled || mode === 'work'}
|
|
title={mode === 'work' ? '此对话已升级为 Work,不能返回 Chat' : '快速对话'}
|
|
>
|
|
Chat
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rounded-lg px-3 py-1.5 font-medium transition {mode === 'work'
|
|
? 'bg-white text-gray-900 shadow-sm dark:bg-gray-700 dark:text-white'
|
|
: 'text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200'}"
|
|
on:click={() => chooseMode('work')}
|
|
{disabled}
|
|
title="长链路、多步骤工作"
|
|
>
|
|
Work
|
|
</button>
|
|
</div>
|
|
|
|
<div
|
|
class="flex items-center rounded-xl border border-gray-200/80 p-1 text-xs dark:border-gray-700/80"
|
|
aria-label="Inference strength"
|
|
>
|
|
{#each strengths as item}
|
|
<button
|
|
type="button"
|
|
class="rounded-lg px-2.5 py-1.5 transition {strength === item.key
|
|
? 'bg-gray-900 text-white dark:bg-white dark:text-gray-900'
|
|
: 'text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800'}"
|
|
on:click={() => chooseStrength(item.key)}
|
|
{disabled}
|
|
>
|
|
{item.label}
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
class="rounded-xl border border-gray-200/80 p-2 text-gray-500 transition hover:bg-gray-100 hover:text-gray-900 dark:border-gray-700/80 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white"
|
|
on:click={() => (showWorkspace = true)}
|
|
title="工作区文件"
|
|
aria-label="工作区文件"
|
|
>
|
|
<svg viewBox="0 0 24 24" class="size-4" fill="none" stroke="currentColor" stroke-width="1.8">
|
|
<path d="M3.5 6.5h6l2 2h9v10h-17z" stroke-linejoin="round" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<WorkspaceFiles bind:show={showWorkspace} />
|