feat(assistant): add multi-dialog UX, task-aware llm settings, and i18n cleanup

This commit is contained in:
2026-02-23 23:45:01 +03:00
parent ab1c87ffba
commit 7df7b4f98c
30 changed files with 1145 additions and 221 deletions

View File

@@ -28,6 +28,11 @@
git_commit_prompt:
"Generate a concise and professional git commit message based on the following diff and recent history.\\nUse Conventional Commits format (e.g., feat: ..., fix: ..., docs: ...).\\n\\nRecent History:\\n{history}\\n\\nDiff:\\n{diff}\\n\\nCommit Message:",
};
const DEFAULT_LLM_PROVIDER_BINDINGS = {
dashboard_validation: "",
documentation: "",
git_commit: "",
};
// State
let activeTab = "environments";
@@ -77,15 +82,50 @@
providers: [],
default_provider: "",
prompts: { ...DEFAULT_LLM_PROMPTS },
provider_bindings: { ...DEFAULT_LLM_PROVIDER_BINDINGS },
assistant_planner_provider: "",
assistant_planner_model: "",
...(llm || {}),
};
normalized.prompts = {
...DEFAULT_LLM_PROMPTS,
...(llm?.prompts || {}),
};
normalized.provider_bindings = {
...DEFAULT_LLM_PROVIDER_BINDINGS,
...(llm?.provider_bindings || {}),
};
normalized.assistant_planner_provider = llm?.assistant_planner_provider || "";
normalized.assistant_planner_model = llm?.assistant_planner_model || "";
return normalized;
}
function isMultimodalModel(modelName) {
const token = (modelName || "").toLowerCase();
if (!token) return false;
return (
token.includes("gpt-4o") ||
token.includes("gpt-4.1") ||
token.includes("vision") ||
token.includes("vl") ||
token.includes("gemini") ||
token.includes("claude-3") ||
token.includes("claude-sonnet-4")
);
}
function getProviderById(providerId) {
if (!providerId) return null;
return (settings?.llm_providers || []).find((p) => p.id === providerId) || null;
}
function isDashboardValidationBindingValid() {
const providerId = settings?.llm?.provider_bindings?.dashboard_validation;
if (!providerId) return true;
const provider = getProviderById(providerId);
return provider ? isMultimodalModel(provider.default_model) : true;
}
// Handle tab change
function handleTabChange(tab) {
activeTab = tab;
@@ -670,6 +710,121 @@
onSave={loadSettings}
/>
<div class="mt-6 rounded-lg border border-gray-200 bg-white p-4">
<h3 class="text-base font-semibold text-gray-900">
{$t.settings?.llm_chatbot_settings_title || "Chatbot Planner Settings"}
</h3>
<p class="mt-1 text-sm text-gray-600">
{$t.settings?.llm_chatbot_settings_description ||
"Select provider and optional model override for assistant intent planning."}
</p>
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label for="planner-provider" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_chatbot_provider || "Chatbot Provider"}
</label>
<select
id="planner-provider"
bind:value={settings.llm.assistant_planner_provider}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
</option>
{/each}
</select>
</div>
<div>
<label for="planner-model" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_chatbot_model || "Chatbot Model Override"}
</label>
<input
id="planner-model"
type="text"
bind:value={settings.llm.assistant_planner_model}
placeholder={$t.settings?.llm_chatbot_model_placeholder || "Optional, e.g. gpt-4.1-mini"}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
/>
</div>
</div>
</div>
<div class="mt-6 rounded-lg border border-gray-200 bg-white p-4">
<h3 class="text-base font-semibold text-gray-900">
{$t.settings?.llm_provider_bindings_title || "Provider Bindings by Task"}
</h3>
<p class="mt-1 text-sm text-gray-600">
{$t.settings?.llm_provider_bindings_description ||
"Select which provider is used by default for each LLM task."}
</p>
<div class="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<label for="binding-dashboard-validation" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_binding_dashboard_validation || "Dashboard Validation Provider"}
</label>
<select
id="binding-dashboard-validation"
bind:value={settings.llm.provider_bindings.dashboard_validation}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
</option>
{/each}
</select>
{#if !isDashboardValidationBindingValid()}
<p class="mt-1 text-xs text-amber-700">
{$t.settings?.llm_multimodal_warning ||
"Dashboard validation requires a multimodal model (image input)."}
</p>
{/if}
</div>
<div>
<label for="binding-documentation" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_binding_documentation || "Documentation Provider"}
</label>
<select
id="binding-documentation"
bind:value={settings.llm.provider_bindings.documentation}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
</option>
{/each}
</select>
</div>
<div class="md:col-span-2">
<label for="binding-git-commit" class="block text-sm font-medium text-gray-700">
{$t.settings?.llm_binding_git_commit || "Git Commit Provider"}
</label>
<select
id="binding-git-commit"
bind:value={settings.llm.provider_bindings.git_commit}
class="mt-1 block w-full rounded-md border border-gray-300 p-2 text-sm"
>
<option value="">{$t.dashboard?.use_default || "Use Default"}</option>
{#each settings.llm_providers || [] as provider}
<option value={provider.id}>
{provider.name} ({provider.default_model})
</option>
{/each}
</select>
</div>
</div>
</div>
<div class="mt-6 rounded-lg border border-gray-200 bg-gray-50 p-4">
<h3 class="text-base font-semibold text-gray-900">
{$t.settings?.llm_prompts_title || "LLM Prompt Templates"}