{% extends "base.html" %} {% from 'partials/toggle.html' import toggle %} {%
block content %}
<div class="settings-container">
    <div class="settings-header">
        <h2>⚙️ System Settings</h2>
    </div>

    <div class="settings-tabs">
        <button class="tab-btn active" onclick="showTab('general')">
            General
        </button>
        <button class="tab-btn" onclick="showTab('tools')">Tools</button>
        <button class="tab-btn" onclick="showTab('models')">Models</button>
        <button class="tab-btn" onclick="showTab('hmads')">HMADS</button>
        <button class="tab-btn" onclick="showTab('logs')">Logs</button>
    </div>

    <!-- General Tab -->
    <div id="general-tab" class="tab-content active">
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Agent Timeout Retries
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Number of automatic retries when the LLM times out
                        mid-reasoning during chat. Set to 0 to disable
                        auto-retry.
                    </div>
                </div>
                <input
                    type="number"
                    id="agent-timeout-retries-input"
                    min="0"
                    max="10"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        LLM Max Retries
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Maximum retry attempts on transient LLM errors (timeout,
                        5xx). Uses exponential backoff (2s, 4s, 8s…). Set to 0
                        to disable.
                    </div>
                </div>
                <input
                    type="number"
                    id="llm-max-retries-input"
                    min="0"
                    max="20"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Max Concurrent Turns per Agent
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Maximum parallel queries per agent (from different
                        sessions). 0 = unlimited.
                    </div>
                </div>
                <input
                    type="number"
                    id="max-concurrent-per-agent-input"
                    min="0"
                    max="20"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Max Concurrent Turns per Model
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Global default for all models (when a model's own limit
                        is 0). 0 = unlimited.
                    </div>
                </div>
                <input
                    type="number"
                    id="max-concurrent-per-model-input"
                    min="0"
                    max="20"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Max Concurrent LLM (Global)
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Hard cap on simultaneous LLM calls <em>across all</em>
                        agents and models. 1 = serialised (default, safest for
                        shared API keys). Increase only if your provider allows
                        concurrent calls.
                    </div>
                </div>
                <input
                    type="number"
                    id="max-concurrent-llm-global-input"
                    min="1"
                    max="20"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Agent Queue Workers
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Number of worker threads processing agent messages.
                        Increase takes effect immediately; decrease requires
                        restart.
                    </div>
                </div>
                <input
                    type="number"
                    id="agent-queue-workers-input"
                    min="1"
                    max="32"
                    oninput="markDirty()"
                    class="ml-4 w-16 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Public History
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Allow unauthenticated users to view the history and
                        detail pages (read-only).
                    </div>
                </div>
                {{ toggle(id='public-history-toggle',
                onchange='togglePublicHistory(this.checked)',
                extra_class='flex-shrink-0 ml-4') }}
            </div>
            <!-- Max Tool Iterations -->
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Max Tool Iterations
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Maximum number of tool-call iterations allowed per agent
                        turn and per evaluation. Prevents infinite loops in
                        multi-step reasoning. Range: 1–1000.
                    </div>
                </div>
                <input
                    type="number"
                    id="max-tool-iterations-input"
                    min="1"
                    max="1000"
                    oninput="markDirty()"
                    class="ml-4 w-20 border border-gray-300 rounded-md px-2 py-1 text-sm text-center focus:outline-none focus:ring-2 focus:ring-indigo-400"
                />
            </div>
            <!-- Task Classifier -->
            <div
                class="p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div class="flex items-center justify-between mb-3">
                    <div>
                        <div class="font-medium text-gray-800 dark:text-gray-100">
                            Task Classifier
                        </div>
                        <div class="text-sm text-gray-500 mt-0.5">
                            Automatically classify tasks as trivial or complex.
                            Trivial tasks skip planning and execute directly.
                        </div>
                    </div>
                    {{ toggle(id='task-classifier-toggle',
                    onchange='saveTaskClassifier()',
                    extra_class='flex-shrink-0 ml-4') }}
                </div>
                <div class="flex flex-col sm:flex-row items-center gap-3">
                    <select
                        id="task-classifier-model-select"
                        class="w-full sm:flex-1 border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-400"
                    >
                        <option value="">Use default model</option>
                    </select>
                    <button
                        onclick="saveTaskClassifier()"
                        class="btn-primary px-4 py-2 text-sm w-full sm:w-auto"
                    >
                        Save
                    </button>
                </div>
                <div
                    id="task-classifier-status"
                    class="mt-2 text-sm hidden"
                ></div>
            </div>
            <!-- Default LLM Model -->
            <div
                class="p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div class="flex items-center justify-between mb-3">
                    <div>
                        <div
                            class="font-medium text-gray-800 dark:text-gray-100"
                        >
                            Default LLM Model
                        </div>
                        <div class="text-sm text-gray-500 mt-0.5">
                            Select the global default model for all agents and
                            evaluations.
                        </div>
                    </div>
                </div>
                <div class="flex flex-col sm:flex-row items-center gap-3">
                    <select
                        id="default-model-select"
                        class="w-full sm:flex-1 border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-400"
                    >
                        <option value="">Loading models...</option>
                    </select>
                    <button
                        onclick="saveDefaultModel()"
                        class="btn-primary px-4 py-2 text-sm w-full sm:w-auto"
                    >
                        Set Default
                    </button>
                </div>
                <div
                    id="default-model-status"
                    class="mt-2 text-sm hidden"
                ></div>
            </div>
            <!-- Theme -->
            <div
                class="flex items-center justify-between p-4 bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-600"
            >
                <div>
                    <div class="font-medium text-gray-800 dark:text-gray-100">
                        Theme
                    </div>
                    <div class="text-sm text-gray-500 mt-0.5">
                        Choose between light, dark, or system-preferred
                        appearance.
                    </div>
                </div>
                <div class="flex items-center gap-2 ml-4">
                    <button
                        id="theme-btn-light"
                        onclick="setTheme('light')"
                        class="theme-btn px-3 py-1.5 rounded-md text-sm font-medium border border-gray-300 text-gray-600 hover:border-indigo-400 transition-colors"
                        title="Light"
                    >
                        ☀️ Light
                    </button>
                    <button
                        id="theme-btn-system"
                        onclick="setTheme('system')"
                        class="theme-btn px-3 py-1.5 rounded-md text-sm font-medium border border-gray-300 text-gray-600 hover:border-indigo-400 transition-colors"
                        title="System"
                    >
                        💻 System
                    </button>
                    <button
                        id="theme-btn-dark"
                        onclick="setTheme('dark')"
                        class="theme-btn px-3 py-1.5 rounded-md text-sm font-medium border border-gray-300 text-gray-600 hover:border-indigo-400 transition-colors"
                        title="Dark"
                    >
                        🌙 Dark
                    </button>
                </div>
            </div>
            <!-- Save Changes -->
            <div class="md:col-span-2 flex justify-end pt-2">
                <button
                    id="save-general-btn"
                    onclick="saveAllSettings()"
                    disabled
                    class="btn-primary px-6 py-2 text-sm opacity-50 cursor-not-allowed"
                >
                    Save Changes
                </button>
            </div>
        </div>
    </div>

    <!-- Tools Tab -->
    <div id="tools-tab" class="tab-content">
        <div class="flex flex-col md:grid md:grid-cols-2">
            <div>
                <div class="flex items-center gap-3 mb-4">
                    <input
                        id="tools-filter"
                        type="text"
                        placeholder="Filter tools..."
                        oninput="onToolsFilter()"
                        class="flex-1 border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-emerald-400"
                    />
                    <span
                        id="tools-count"
                        class="text-xs text-gray-400 whitespace-nowrap"
                    ></span>
                </div>

                <div id="tools-list">
                    <!-- Tools will be loaded here -->
                </div>
            </div>
        </div>
        <div
            id="tools-pagination"
            class="flex items-center justify-center gap-2 mt-4 hidden"
        >
            <button
                onclick="toolsGoPage(toolsPage - 1)"
                id="tools-prev"
                class="px-3 py-1.5 rounded-md text-sm border border-gray-300 text-gray-600 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed"
            >
                ← Prev
            </button>
            <span id="tools-page-info" class="text-sm text-gray-500"></span>
            <button
                onclick="toolsGoPage(toolsPage + 1)"
                id="tools-next"
                class="px-3 py-1.5 rounded-md text-sm border border-gray-300 text-gray-600 hover:bg-gray-50 disabled:opacity-40 disabled:cursor-not-allowed"
            >
                Next →
            </button>
        </div>
        <button
            onclick="showAddToolModal()"
            class="mt-5 bg-emerald-500 hover:bg-emerald-600 text-white border-none px-6 py-3 rounded-md cursor-pointer text-sm"
        >
            + Add Tool
        </button>
    </div>

    <!-- Models Tab -->
    <div id="models-tab" class="tab-content">
        <div class="space-y-4">
            <div class="flex items-center justify-between">
                <div>
                    <h3 class="font-medium text-gray-800 dark:text-gray-100">
                        LLM Models
                    </h3>
                    <p class="text-sm text-gray-500">
                        Manage LLM models and per-agent model assignments
                    </p>
                </div>
                <button onclick="showAddModelModal()" class="btn-primary">
                    + Add Model
                </button>
            </div>

            <!-- Search Bar -->
            <div class="relative">
                <input
                    type="text"
                    id="model-search-input"
                    placeholder="Search models..."
                    oninput="filterModels()"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg pl-10 pr-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                />
                <svg
                    class="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400"
                    fill="none"
                    stroke="currentColor"
                    viewBox="0 0 24 24"
                >
                    <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
                    />
                </svg>
            </div>

            <!-- All Models Grid -->
            <div id="models-list" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
                <p class="text-gray-500 text-center py-4 col-span-full">Loading models...</p>
            </div>
        </div>
    </div>

    <!-- Logs Tab -->
    <div id="logs-tab" class="tab-content">
        {% include 'partials/logs_tab.html' %}
    </div>

    <!-- HMADS Tab -->
    <div id="hmads-tab" class="tab-content">
        {% include 'partials/hmads.html' %}
    </div>
</div>

<!-- Model Modal -->
<div id="model-modal" class="modal">
    <div
        class="bg-white dark:bg-gray-800 rounded-xl shadow-2xl w-full max-w-lg mx-4 flex flex-col max-h-[90vh]"
    >
        <div
            class="flex items-center justify-between px-6 pt-5 pb-4 border-b border-gray-100 dark:border-gray-700 flex-shrink-0"
        >
            <h3
                id="modal-title"
                class="text-lg font-semibold text-gray-900 dark:text-gray-100"
            >
                Add Model
            </h3>
            <button
                onclick="closeModal('model-modal')"
                class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 text-xl leading-none"
            >
                &times;
            </button>
        </div>
        <form
            id="model-form"
            onsubmit="saveModel(event)"
            class="overflow-y-auto p-6 flex-1"
        >
            <input type="hidden" id="model-id" />

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-name"
                    >Model Name *</label
                >
                <input
                    type="text"
                    id="model-name"
                    required
                    placeholder="e.g., Claude Sonnet"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                />
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-type"
                    >Type *</label
                >
                <select
                    id="model-type"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    onchange="toggleModelFields()"
                >
                    <option value="remote">Remote</option>
                    <option value="local">Local</option>
                </select>
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-provider"
                    >Provider *</label
                >
                <select
                    id="model-provider"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                >
                    <option value="openrouter">OpenRouter</option>
                    <option value="togetherai">TogetherAI</option>
                    <option value="ollama">Ollama</option>
                    <option value="ollama_cloud">Ollama Cloud</option>
                    <option value="opencode_zen">OpenCode Zen</option>
                    <option value="opencode_go">OpenCode Go</option>
                    <option value="deepseek">DeepSeek</option>
                    <option value="llama.cpp">llama.cpp</option>
                    <option value="custom">Custom</option>
                </select>
            </div>

            <div class="mb-4" id="base-url-group">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-base-url"
                    >Base URL *</label
                >
                <input
                    type="url"
                    id="model-base-url"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    placeholder="https://openrouter.ai/api/v1"
                />
            </div>

            <div class="mb-4" id="api-key-group">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-api-key"
                    >API Key</label
                >
                <input
                    type="password"
                    id="model-api-key"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    placeholder="sk-or-..."
                />
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-name-param"
                    >Model ID *</label
                >
                <input
                    type="text"
                    id="model-name-param"
                    required
                    placeholder="anthropic/claude-3.5-sonnet"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                />
                <p
                    id="model-id-hint"
                    class="text-xs text-gray-400 dark:text-gray-500 mt-1"
                >
                    The exact ID format depends on the provider. Browse the
                    catalog at
                    <a
                        href="https://models.dev/"
                        target="_blank"
                        rel="noopener noreferrer"
                        class="text-indigo-600 hover:text-indigo-700 dark:text-indigo-400 dark:hover:text-indigo-300 underline"
                        >models.dev</a
                    >.
                </p>
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-max-tokens"
                    >Max Tokens</label
                >
                <input
                    type="number"
                    id="model-max-tokens"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    value="32768"
                    min="1"
                />
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-timeout"
                    >Timeout (seconds)</label
                >
                <input
                    type="number"
                    id="model-timeout"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    value="60"
                    min="1"
                />
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-max-concurrent"
                    >Max Concurrent Turns</label
                >
                <input
                    type="number"
                    id="model-max-concurrent"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    value="1"
                    min="0"
                />
                <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
                    Limit parallel agent turns using this model. 0 = use the
                    global per-model setting from General Settings.
                </p>
            </div>

            <div class="mb-4">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-temperature"
                    >Temperature</label
                >
                <input
                    type="number"
                    id="model-temperature"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    placeholder="e.g. 0.7"
                    step="0.1"
                    min="0"
                    max="2"
                />
                <p class="text-xs text-gray-400 dark:text-gray-500 mt-1">
                    Leave empty for server default.
                </p>
            </div>

            <div class="mb-4">
                <label
                    class="inline-flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-gray-300"
                >
                    <input
                        type="checkbox"
                        id="model-thinking"
                        checked
                        class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                    />
                    Enable Thinking Mode
                </label>
            </div>

            <div class="mb-4" id="thinking-budget-group">
                <label
                    class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
                    for="model-thinking-budget"
                    >Thinking Budget (tokens, 0 = default)</label
                >
                <input
                    type="number"
                    id="model-thinking-budget"
                    class="w-full border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-300 focus:border-indigo-400 dark:bg-gray-700 dark:text-gray-100"
                    value="0"
                    min="0"
                />
            </div>

            <div class="mb-4">
                <label
                    class="inline-flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-gray-300"
                >
                    <input
                        type="checkbox"
                        id="model-enabled"
                        checked
                        class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                    />
                    Enabled
                </label>
            </div>

            <div class="mb-4">
                <label
                    class="inline-flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-gray-300"
                >
                    <input
                        type="checkbox"
                        id="model-is-default"
                        class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                    />
                    Set as Global Default
                </label>
            </div>

            <div class="mb-4">
                <label
                    class="inline-flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-gray-300"
                >
                    <input
                        type="checkbox"
                        id="model-vision-supported"
                        class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                    />
                    Vision Supported (model can process images)
                </label>
            </div>

            <div class="mb-4">
                <label
                    class="inline-flex items-center gap-2 text-sm font-medium text-gray-700 dark:text-gray-300"
                >
                    <input
                        type="checkbox"
                        id="model-attachments-supported"
                        class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
                    />
                    Attachments Supported (model can handle file attachments)
                </label>
            </div>
        </form>
        <div
            class="flex justify-end gap-2 px-6 pb-5 pt-4 border-t border-gray-100 dark:border-gray-700 flex-shrink-0"
        >
            <button
                type="button"
                onclick="closeModal('model-modal')"
                class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 dark:bg-gray-600 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-500 transition"
            >
                Cancel
            </button>
            <button
                type="submit"
                form="model-form"
                class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 transition"
            >
                Save Model
            </button>
        </div>
    </div>

<!-- Test Connection Modal (model endpoint test) -->
<div id="connection-test-modal" class="modal">
    <div
        class="bg-white dark:bg-gray-800 rounded-xl w-[90%] max-w-[500px] max-h-[90vh] overflow-y-auto shadow-xl"
    >
        <div
            class="flex justify-between items-center p-5 border-b border-gray-200 dark:border-gray-600"
        >
            <h3 id="connection-test-title" class="m-0 text-gray-800 dark:text-gray-100">
                Test Connection
            </h3>
            <button
                onclick="closeTestModal()"
                class="bg-transparent border-none text-gray-500 text-2xl cursor-pointer hover:text-gray-800 dark:hover:text-gray-300"
            >
                &times;
            </button>
        </div>
        <div id="connection-test-status" class="p-5">
            <!-- Dynamically populated: loading / success / error -->
        </div>
        <div id="connection-test-footer" class="hidden px-5 pb-5 flex justify-end">
            <button
                onclick="closeTestModal()"
                class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 transition-colors"
            >
                Close
            </button>
        </div>
    </div>
</div>

<!-- Domain/Evaluator modals moved to /evaluate/domains and /evaluate/evaluators -->

<!-- Tool Modal -->
<div id="tool-modal" class="modal">
    <div
        class="bg-white dark:bg-gray-800 rounded-xl w-[90%] max-w-[760px] shadow-xl flex flex-col"
        style="max-height: 90vh"
    >
        <div
            class="flex justify-between items-center p-5 border-b border-gray-200 flex-shrink-0"
        >
            <h3
                id="tool-modal-title"
                class="m-0 text-gray-800 dark:text-gray-100"
            >
                Add Tool
            </h3>
            <button
                onclick="closeModal('tool-modal')"
                class="bg-transparent border-none text-gray-500 text-2xl cursor-pointer hover:text-gray-800"
            >
                &times;
            </button>
        </div>
        <!-- Main Tab Bar -->
        <div class="flex border-b border-gray-200 flex-shrink-0 px-5">
            <button
                id="tool-main-tab-btn-info"
                onclick="switchToolModalTab('info')"
                class="px-4 py-3 text-sm font-medium border-b-2 border-blue-500 text-blue-600 -mb-px"
            >
                Info
            </button>
            <button
                id="tool-main-tab-btn-operation"
                onclick="switchToolModalTab('operation')"
                class="px-4 py-3 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700 -mb-px"
            >
                Operation
            </button>
        </div>
        <div class="flex-1 overflow-y-auto">
            <form id="tool-form">
                <input type="hidden" id="tool-edit-id" />
                <!-- Info Tab -->
                <div id="tool-main-tab-info" class="p-5 space-y-4">
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >ID</label
                        >
                        <input
                            type="text"
                            id="tool-id-input"
                            placeholder="Auto-generated from name if empty"
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        />
                    </div>
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >Name *</label
                        >
                        <input
                            type="text"
                            id="tool-name"
                            required
                            placeholder="e.g., Get Weather"
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        />
                    </div>
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >Description</label
                        >
                        <input
                            type="text"
                            id="tool-description"
                            placeholder="Brief description of the tool"
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        />
                    </div>
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >Function Name *</label
                        >
                        <input
                            type="text"
                            id="tool-func-name"
                            required
                            placeholder="e.g., get_weather"
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        />
                        <small class="text-gray-500 text-xs"
                            >The function name used in OpenAI tool calling
                            format</small
                        >
                    </div>
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >Function Description</label
                        >
                        <textarea
                            id="tool-func-description"
                            rows="2"
                            placeholder="Description shown to the LLM"
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        ></textarea>
                    </div>
                    <div>
                        <label
                            class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                            >Parameters (JSON)</label
                        >
                        <textarea
                            id="tool-parameters"
                            rows="7"
                            placeholder='{"type": "object", "properties": {"location": {"type": "string", "description": "City name"}}, "required": ["location"]}'
                            class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm font-mono focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                        ></textarea>
                        <small class="text-gray-500 text-xs"
                            >OpenAI function parameters schema (JSON
                            object)</small
                        >
                    </div>
                    <div
                        class="flex items-center justify-between p-3 bg-amber-50 border border-amber-200 rounded-md"
                    >
                        <div>
                            <label
                                for="tool-no-mock"
                                class="text-sm font-medium text-gray-800 cursor-pointer"
                                >Use Real Backend (no mock)</label
                            >
                            <p class="text-xs text-gray-500 mt-0.5">
                                When enabled, evaluation will call the real
                                backend implementation instead of mock
                                responses. Fails if no backend exists.
                            </p>
                        </div>
                        <input
                            type="checkbox"
                            id="tool-no-mock"
                            class="w-4 h-4 text-blue-600 rounded cursor-pointer ml-4 flex-shrink-0"
                        />
                    </div>
                </div>
                <!-- Operation Tab -->
                <div id="tool-main-tab-operation" class="hidden p-5">
                    <!-- Operation Sub-tab Bar -->
                    <div class="flex border-b border-gray-200 mb-4">
                        <button
                            type="button"
                            id="tool-op-tab-btn-prod"
                            onclick="switchToolModalOpTab('prod')"
                            class="px-4 py-2 text-sm font-medium border-b-2 border-indigo-500 text-indigo-600 -mb-px"
                        >
                            Prod
                        </button>
                        <button
                            type="button"
                            id="tool-op-tab-btn-mock"
                            onclick="switchToolModalOpTab('mock')"
                            class="px-4 py-2 text-sm font-medium border-b-2 border-transparent text-gray-500 hover:text-gray-700 -mb-px"
                        >
                            Mock
                        </button>
                    </div>
                    <!-- Prod Sub-tab -->
                    <div id="tool-op-tab-prod">
                        <label
                            class="text-xs uppercase tracking-wide text-gray-400 font-semibold"
                            >Backend Code (Python)</label
                        >
                        <textarea
                            id="tool-backend-code"
                            class="w-full font-mono text-xs bg-gray-900 text-gray-100 border border-gray-700 rounded-md p-3 mt-2 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
                            rows="14"
                            spellcheck="false"
                            style="resize: vertical; tab-size: 4"
                            onkeydown="
                                if (event.key === 'Tab') {
                                    event.preventDefault();
                                    const s = this.selectionStart,
                                        e = this.selectionEnd;
                                    this.value =
                                        this.value.substring(0, s) +
                                        '    ' +
                                        this.value.substring(e);
                                    this.selectionStart = this.selectionEnd =
                                        s + 4;
                                }
                            "
                        ></textarea>
                        <div class="flex items-center gap-3 mt-2">
                            <button
                                type="button"
                                onclick="saveToolBackendCode()"
                                class="px-4 py-2 bg-indigo-500 text-white rounded-md text-sm hover:bg-indigo-600 transition-colors"
                            >
                                Save
                            </button>
                            <span
                                id="tool-backend-save-status"
                                class="text-sm text-green-600 hidden"
                                >Saved!</span
                            >
                        </div>
                        <!-- Test section (Prod) -->
                        <div class="mt-4 border-t border-gray-200 pt-4">
                            <label
                                class="text-xs uppercase tracking-wide text-gray-400 font-semibold"
                                >Test</label
                            >
                            <textarea
                                id="tool-test-args-real"
                                class="w-full font-mono text-xs bg-gray-50 border border-gray-200 rounded-md p-2 mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
                                rows="3"
                                spellcheck="false"
                                placeholder='{"key": "value"}'
                            ></textarea>
                            <div class="flex items-center gap-3 mt-2">
                                <button
                                    type="button"
                                    onclick="testToolExecSettings('real')"
                                    class="px-4 py-2 bg-emerald-500 text-white rounded-md text-sm hover:bg-emerald-600 transition-colors"
                                >
                                    Run
                                </button>
                                <span
                                    id="tool-test-status-real"
                                    class="text-xs text-gray-400 hidden"
                                ></span>
                            </div>
                            <pre
                                id="tool-test-result-real"
                                class="hidden mt-2 bg-gray-50 border border-gray-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto"
                                style="max-height: 200px"
                            ></pre>
                        </div>
                    </div>
                    <!-- Mock Sub-tab -->
                    <div id="tool-op-tab-mock" class="hidden">
                        <div class="mb-4">
                            <label
                                class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                                >Mock Response Type</label
                            >
                            <select
                                id="tool-mock-type"
                                onchange="toggleMockResponseHelp()"
                                class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                            >
                                <option value="json">JSON Object</option>
                                <option value="javascript">JavaScript</option>
                            </select>
                        </div>
                        <div class="mb-2">
                            <label
                                class="block mb-1 text-gray-700 dark:text-gray-200 text-sm font-medium"
                                >Mock Response</label
                            >
                            <textarea
                                id="tool-mock-response"
                                rows="10"
                                placeholder='{"result": "sample data"}'
                                class="w-full p-2.5 border border-gray-300 rounded-md bg-white text-gray-800 text-sm font-mono focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/10"
                            ></textarea>
                            <small
                                id="tool-mock-help-json"
                                class="text-gray-500 text-xs"
                                >JSON object that will be returned when this
                                tool is called during evaluation</small
                            >
                            <small
                                id="tool-mock-help-js"
                                class="hidden text-gray-500 text-xs"
                                >JavaScript code. Use <code>ARGS</code> variable
                                to access tool call arguments. Output via
                                <code>console.log(JSON.stringify(result))</code
                                >.</small
                            >
                        </div>
                        <!-- Test section (Mock) -->
                        <div class="mt-4 border-t border-gray-200 pt-4">
                            <label
                                class="text-xs uppercase tracking-wide text-gray-400 font-semibold"
                                >Test</label
                            >
                            <textarea
                                id="tool-test-args-mock"
                                class="w-full font-mono text-xs bg-gray-50 border border-gray-200 rounded-md p-2 mt-1 focus:outline-none focus:ring-2 focus:ring-indigo-500/30"
                                rows="3"
                                spellcheck="false"
                                placeholder='{"key": "value"}'
                            ></textarea>
                            <div class="flex items-center gap-3 mt-2">
                                <button
                                    type="button"
                                    onclick="testToolExecSettings('mock')"
                                    class="px-4 py-2 bg-emerald-500 text-white rounded-md text-sm hover:bg-emerald-600 transition-colors"
                                >
                                    Run
                                </button>
                                <span
                                    id="tool-test-status-mock"
                                    class="text-xs text-gray-400 hidden"
                                ></span>
                            </div>
                            <pre
                                id="tool-test-result-mock"
                                class="hidden mt-2 bg-gray-50 border border-gray-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto"
                                style="max-height: 200px"
                            ></pre>
                        </div>
                    </div>
                </div>
            </form>
        </div>
        <div
            class="flex justify-end gap-2.5 p-5 border-t border-gray-200 flex-shrink-0"
        >
            <button
                onclick="closeModal('tool-modal')"
                class="bg-gray-100 text-gray-700 border border-gray-300 px-5 py-2.5 rounded-md cursor-pointer text-sm hover:bg-gray-200"
            >
                Cancel
            </button>
            <button
                onclick="saveTool()"
                class="bg-blue-500 text-white border-none px-5 py-2.5 rounded-md cursor-pointer text-sm hover:bg-blue-600"
            >
                Save Tool
            </button>
        </div>
    </div>
</div>

<style>
    .settings-container {
        margin: 0 auto;
        padding: 20px;
    }

    .settings-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20px;
        flex-wrap: wrap;
        gap: 10px;
    }

    .settings-actions {
        display: flex;
        gap: 10px;
    }

    .settings-tabs {
        display: flex;
        gap: 10px;
        margin-bottom: 20px;
        border-bottom: 2px solid #e5e7eb;
        padding-bottom: 10px;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .tab-btn {
        background: none;
        border: none;
        color: #6b7280;
        padding: 10px 20px;
        cursor: pointer;
        font-size: 16px;
        border-bottom: 2px solid transparent;
        transition: all 0.3s;
        white-space: nowrap;
        flex-shrink: 0;
    }

    .tab-btn.active {
        color: #3b82f6;
        border-bottom-color: #3b82f6;
    }

    .tab-btn:hover {
        color: #3b82f6;
    }

    .tab-content {
        display: none;
    }

    .tab-content.active {
        display: block;
    }

    /* Modal Styles */
    .modal {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        z-index: 1000;
        overflow-y: auto;
    }

    .modal.active {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 20px;
    }

    .btn-primary {
        background: #3b82f6;
        color: #fff;
        border: none;
        padding: 10px 20px;
        border-radius: 5px;
        cursor: pointer;
        font-size: 14px;
    }

    .btn-primary:hover {
        background: #2563eb;
    }

    .btn-icon {
        background: none;
        border: none;
        color: #6b7280;
        cursor: pointer;
        padding: 5px;
        font-size: 14px;
    }

    .btn-icon:hover {
        color: #1f2937;
    }

    .btn-icon.delete:hover {
        color: #ef4444;
    }

    .loading {
        text-align: center;
        padding: 40px;
        color: #6b7280;
    }

    .hidden {
        display: none !important;
    }

    /* Model card default styling now handled inline via template */
    .spinner {
        width: 24px;
        height: 24px;
        border: 2px solid #e5e7eb;
        border-top-color: #6366f1;
        border-radius: 50%;
        animation: spin 0.8s linear infinite;
        margin: 0 auto;
    }
    @keyframes spin {
        to {
            transform: rotate(360deg);
        }
    }

    /* Dark mode overrides for settings-specific styles */
    html.dark .settings-tabs {
        border-bottom-color: #334155;
    }
    html.dark .tab-btn {
        color: #94a3b8;
    }
    html.dark .tab-btn.active {
        color: #60a5fa;
        border-bottom-color: #60a5fa;
    }
    html.dark .tab-btn:hover {
        color: #60a5fa;
    }
    html.dark .btn-icon {
        color: #94a3b8;
    }
    html.dark .btn-icon:hover {
        color: #f1f5f9;
    }
    html.dark .loading {
        color: #94a3b8;
    }
    html.dark .spinner {
        border-color: #334155;
        border-top-color: #6366f1;
    }
</style>

<script src="{{ url_for('static', filename='js/toast.js') }}?v=1"></script>
<script>
    // State
    let tools = [];
    let _settingsDirty = false;

    async function loadDefaultModel() {
        const select = document.getElementById("default-model-select");
        if (!select) return;
        try {
            const response = await fetch("/api/models");
            if (!response.ok) throw new Error("HTTP " + response.status);
            const data = await response.json();
            const models = data.models || [];

            // Get current default
            let currentDefault = null;
            try {
                const defaultResponse = await fetch(
                    "/api/settings/default-model",
                );
                if (defaultResponse.ok) {
                    const defaultData = await defaultResponse.json();
                    currentDefault = defaultData.model;
                }
            } catch (e) {
                console.warn("Could not fetch default model:", e);
            }

            if (models.length === 0) {
                select.innerHTML =
                    '<option value="">No models configured — go to Models tab to add one</option>';
                return;
            }

            select.innerHTML =
                '<option value="">— Select model —</option>' +
                models
                    .map(
                        (m) =>
                            `<option value="${m.id}" ${currentDefault && currentDefault.id === m.id ? "selected" : ""}>${m.name} (${m.model_name})</option>`,
                    )
                    .join("");
        } catch (error) {
            console.error("Failed to load models:", error);
            select.innerHTML =
                '<option value="">Error: ' + error.message + "</option>";
        }
    }

    async function saveDefaultModel() {
        const select = document.getElementById("default-model-select");
        const modelId = select.value;
        if (!modelId) {
            alert("Please select a model");
            return;
        }

        try {
            const response = await fetch("/api/settings/default-model", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ model_id: modelId }),
            });
            const result = await response.json();
            const statusDiv = document.getElementById("default-model-status");

            if (result.success) {
                statusDiv.className = "mt-2 text-sm text-green-600";
                statusDiv.textContent = "Default model saved successfully!";
                statusDiv.classList.remove("hidden");
                setTimeout(() => statusDiv.classList.add("hidden"), 3000);
            } else {
                statusDiv.className = "mt-2 text-sm text-red-600";
                statusDiv.textContent =
                    "Error: " + (result.error || "Failed to save");
                statusDiv.classList.remove("hidden");
            }
        } catch (error) {
            console.error("Failed to save default model:", error);
            const statusDiv = document.getElementById("default-model-status");
            statusDiv.className = "mt-2 text-sm text-red-600";
            statusDiv.textContent = "Error: " + error.message;
            statusDiv.classList.remove("hidden");
        }
    }

    async function loadTaskClassifier() {
        const select = document.getElementById("task-classifier-model-select");
        const toggle = document.getElementById("task-classifier-toggle");
        if (!select) return;

        try {
            // Load available models
            const response = await fetch("/api/models");
            if (!response.ok) throw new Error("HTTP " + response.status);
            const data = await response.json();
            const models = data.models || [];

            // Load current classifier settings
            let currentModelId = null;
            let enabled = true;
            try {
                const classifierResponse = await fetch("/api/settings/task-classifier");
                if (classifierResponse.ok) {
                    const classifierData = await classifierResponse.json();
                    currentModelId = classifierData.model_id;
                    enabled = classifierData.enabled;
                }
            } catch (e) {
                console.warn("Could not fetch task classifier settings:", e);
            }

            // Set toggle state
            if (toggle) toggle.checked = enabled;

            // Populate model dropdown
            if (models.length === 0) {
                select.innerHTML = '<option value="">No models configured — go to Models tab to add one</option>';
                return;
            }

            select.innerHTML =
                '<option value="">Use default model</option>' +
                models
                    .map(
                        (m) =>
                            `<option value="${m.id}" ${currentModelId && currentModelId === m.id ? "selected" : ""}>${m.name} (${m.model_name})</option>`,
                    )
                    .join("");
        } catch (error) {
            console.error("Failed to load task classifier:", error);
            select.innerHTML = '<option value="">Error: ' + error.message + "</option>";
        }
    }

    async function saveTaskClassifier() {
        const select = document.getElementById("task-classifier-model-select");
        const toggle = document.getElementById("task-classifier-toggle");
        const statusDiv = document.getElementById("task-classifier-status");

        const enabled = toggle ? toggle.checked : true;
        const modelId = select ? select.value : "";

        try {
            const response = await fetch("/api/settings/task-classifier", {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ enabled, model_id: modelId }),
            });
            const result = await response.json();

            if (result.success) {
                statusDiv.className = "mt-2 text-sm text-green-600";
                statusDiv.textContent = "Task classifier settings saved!";
                statusDiv.classList.remove("hidden");
                setTimeout(() => statusDiv.classList.add("hidden"), 3000);
            } else {
                statusDiv.className = "mt-2 text-sm text-red-600";
                statusDiv.textContent = "Error: " + (result.error || "Failed to save");
                statusDiv.classList.remove("hidden");
            }
        } catch (error) {
            console.error("Failed to save task classifier:", error);
            statusDiv.className = "mt-2 text-sm text-red-600";
            statusDiv.textContent = "Error: " + error.message;
            statusDiv.classList.remove("hidden");
        }
    }
    // Tab Management
    function showTab(tabName) {
        document
            .querySelectorAll(".tab-content")
            .forEach((tab) => tab.classList.remove("active"));
        document
            .querySelectorAll(".tab-btn")
            .forEach((btn) => btn.classList.remove("active"));

        document.getElementById(`${tabName}-tab`).classList.add("active");
        document
            .querySelector(`[onclick="showTab('${tabName}')"]`)
            .classList.add("active");
        location.hash = tabName;

        // Tab-specific initialization
        if (tabName === "general") {
            loadDefaultModel();
        } else if (tabName === "models") {
            loadModels();
        } else if (tabName === "logs") {
            if (window.logViewer) {
                logViewer.init();
            }
        } else if (tabName === "hmads") {
            if (window.hmads) {
                hmads.init();
            }
        }
    }

    // Initialize
    document.addEventListener("DOMContentLoaded", () => {
        loadGeneralSettings();
        loadTools();
        loadDefaultModel();
    });

    async function loadGeneralSettings() {
        let s;
        try {
            s = await apiGet("/api/settings/general");
        } catch (e) {
            console.error("loadGeneralSettings: fetch failed", e);
            return;
        }
        if (!s || s.error) {
            console.error("loadGeneralSettings: unexpected response", s);
            return;
        }
        document.getElementById("public-history-toggle").checked = s.public_history;
        document.getElementById("agent-timeout-retries-input").value = s.agent_timeout_retries;
        document.getElementById("llm-max-retries-input").value = s.llm_max_retries;
        document.getElementById("max-concurrent-per-agent-input").value = s.max_concurrent_llm_per_agent;
        document.getElementById("max-concurrent-per-model-input").value = s.max_concurrent_llm_per_model;
        document.getElementById("max-concurrent-llm-global-input").value = s.max_concurrent_llm_global;
        document.getElementById("agent-queue-workers-input").value = s.agent_queue_workers;
        document.getElementById("max-tool-iterations-input").value = s.max_tool_iterations;
        updateThemeButtons(s.theme);
        await loadTaskClassifier();
    }

    async function togglePublicHistory(enabled) {
        await apiPut("/api/settings/public-history", { enabled });
    }

    function updateThemeButtons(theme) {
        document.querySelectorAll(".theme-btn").forEach((btn) => {
            btn.style.borderColor = "";
            btn.style.background = "";
            btn.style.color = "";
        });
        const active = document.getElementById("theme-btn-" + theme);
        if (active) {
            active.style.borderColor = "#6366f1";
            active.style.background = "#eef2ff";
            active.style.color = "#4338ca";
        }
    }

    let systemSchemeListener = null;

    async function setTheme(theme) {
        // Remove existing system listener
        if (systemSchemeListener) {
            systemSchemeListener.removeEventListener(
                "change",
                applySystemTheme,
            );
            systemSchemeListener = null;
        }

        // Apply immediately
        const html = document.documentElement;
        if (theme === "dark") {
            html.classList.add("dark");
        } else if (theme === "light") {
            html.classList.remove("dark");
        } else {
            applySystemTheme();
            if (window.matchMedia) {
                systemSchemeListener = window.matchMedia(
                    "(prefers-color-scheme: dark)",
                );
                systemSchemeListener.addEventListener(
                    "change",
                    applySystemTheme,
                );
            }
        }
        localStorage.setItem("evonic-theme", theme);
        updateThemeButtons(theme);
        // Persist theme immediately on the server
        try {
            await apiPut("/api/settings/theme", { theme });
            markClean();
        } catch (e) {
            markDirty();
        }
    }

    function applySystemTheme() {
        const html = document.documentElement;
        if (
            window.matchMedia &&
            window.matchMedia("(prefers-color-scheme: dark)").matches
        ) {
            html.classList.add("dark");
        } else {
            html.classList.remove("dark");
        }
    }

    function markDirty() {
        if (_settingsDirty) return;
        _settingsDirty = true;
        const btn = document.getElementById("save-general-btn");
        if (btn) {
            btn.disabled = false;
            btn.classList.remove("opacity-50", "cursor-not-allowed");
        }
    }

    function markClean() {
        _settingsDirty = false;
        const btn = document.getElementById("save-general-btn");
        if (btn) {
            btn.disabled = true;
            btn.classList.add("opacity-50", "cursor-not-allowed");
        }
    }

    async function saveAllSettings() {
        const btn = document.getElementById("save-general-btn");
        const origText = btn.textContent;
        btn.disabled = true;
        btn.textContent = "Saving…";

        const theme = localStorage.getItem("evonic-theme") || "system";
        const payload = {
            settings: {
                agent_timeout_retries: parseInt(document.getElementById("agent-timeout-retries-input").value, 10),
                llm_max_retries: parseInt(document.getElementById("llm-max-retries-input").value, 10),
                max_concurrent_llm_per_agent: parseInt(document.getElementById("max-concurrent-per-agent-input").value, 10),
                max_concurrent_llm_per_model: parseInt(document.getElementById("max-concurrent-per-model-input").value, 10),
                max_concurrent_llm_global: parseInt(document.getElementById("max-concurrent-llm-global-input").value, 10),
                agent_queue_workers: parseInt(document.getElementById("agent-queue-workers-input").value, 10),
                max_tool_iterations: parseInt(document.getElementById("max-tool-iterations-input").value, 10),
                theme,
            }
        };

        try {
            const res = await apiPost("/api/settings/batch", payload);
            if (res && res.success) {
                markClean();
                btn.textContent = origText;
                if (window.toast) toast.show("Settings saved", "success");
            } else {
                btn.disabled = false;
                btn.textContent = origText;
                const msg = (res && res.errors) ? res.errors.join(", ") : "Save failed";
                if (window.toast) toast.show(msg, "error");
            }
        } catch (e) {
            btn.disabled = false;
            btn.textContent = origText;
            if (window.toast) toast.show("Save failed: " + e.message, "error");
        }
    }

    // Restore tab from URL hash on page load
    (function () {
        const valid = ["general", "tools", "models", "logs", "hmads"];
        const hash = location.hash.replace("#", "");
        if (valid.includes(hash)) {
            document.addEventListener("DOMContentLoaded", () => showTab(hash));
        }
    })();

    // Modal Management
    function openModal(modalId) {
        document.getElementById(modalId).classList.add("active");
    }

    function closeModal(modalId) {
        document.getElementById(modalId).classList.remove("active");
    }

    // API Calls
    async function apiGet(url) {
        const response = await fetch(url);
        return response.json();
    }

    async function apiPost(url, data) {
        const response = await fetch(url, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data),
        });
        return response.json();
    }

    async function apiPut(url, data) {
        const response = await fetch(url, {
            method: "PUT",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data),
        });
        return response.json();
    }

    async function apiDelete(url) {
        const response = await fetch(url, { method: "DELETE" });
        return response.json();
    }

    async function loadTools() {
        try {
            const data = await apiGet("/api/settings/tools");
            tools = data.tools || [];
            toolsPage = 1;
            renderTools();
        } catch (error) {
            console.error("Error loading tools:", error);
        }
    }

    // ==================== Tool Functions ====================

    const TOOLS_PAGE_SIZE = 10;
    let toolsPage = 1;
    let toolsFilter = "";

    function onToolsFilter() {
        toolsFilter = document
            .getElementById("tools-filter")
            .value.toLowerCase();
        toolsPage = 1;
        renderTools();
    }

    function toolsGoPage(page) {
        const filtered = _toolsFiltered();
        const totalPages = Math.max(
            1,
            Math.ceil(filtered.length / TOOLS_PAGE_SIZE),
        );
        toolsPage = Math.max(1, Math.min(page, totalPages));
        renderTools();
    }

    function _toolsFiltered() {
        if (!toolsFilter) return tools;
        return tools.filter(
            (t) =>
                (t.name || "").toLowerCase().includes(toolsFilter) ||
                (t.description || "").toLowerCase().includes(toolsFilter) ||
                (t.function &&
                    (t.function.name || "")
                        .toLowerCase()
                        .includes(toolsFilter)) ||
                (t.id || "").toLowerCase().includes(toolsFilter),
        );
    }

    function renderTools() {
        const container = document.getElementById("tools-list");
        const filtered = _toolsFiltered();
        const totalPages = Math.max(
            1,
            Math.ceil(filtered.length / TOOLS_PAGE_SIZE),
        );
        if (toolsPage > totalPages) toolsPage = totalPages;

        const start = (toolsPage - 1) * TOOLS_PAGE_SIZE;
        const page = filtered.slice(start, start + TOOLS_PAGE_SIZE);

        // Count label
        const countEl = document.getElementById("tools-count");
        if (countEl) {
            countEl.textContent = toolsFilter
                ? `${filtered.length} of ${tools.length} tools`
                : `${tools.length} tool${tools.length !== 1 ? "s" : ""}`;
        }

        // Pagination controls
        const paginationEl = document.getElementById("tools-pagination");
        const pageInfoEl = document.getElementById("tools-page-info");
        const prevBtn = document.getElementById("tools-prev");
        const nextBtn = document.getElementById("tools-next");
        if (paginationEl) {
            if (totalPages > 1) {
                paginationEl.classList.remove("hidden");
                pageInfoEl.textContent = `Page ${toolsPage} of ${totalPages}`;
                prevBtn.disabled = toolsPage <= 1;
                nextBtn.disabled = toolsPage >= totalPages;
            } else {
                paginationEl.classList.add("hidden");
            }
        }

        if (tools.length === 0) {
            container.innerHTML =
                '<div class="text-center py-10 text-gray-500">No tools found. Click "+ Add Tool" to create one.</div>';
            return;
        }
        if (filtered.length === 0) {
            container.innerHTML = `<div class="text-center py-10 text-gray-500">No tools match "<strong>${toolsFilter}</strong>".</div>`;
            return;
        }

        container.innerHTML = page
            .map(
                (tool) => `
        <div class="bg-white dark:bg-gray-800 dark:text-white rounded-lg p-5 mb-3 shadow-sm border border-gray-200 dark:border-gray-700 flex justify-between items-center cursor-pointer hover:border-blue-300 hover:shadow-md transition-all"
             onclick="editTool('${tool.id}')">
            <div class="flex-1 pointer-events-none">
                <h4 class="m-0 text-gray-800 text-base dark:text-gray-100">
                    ${tool.name}
                    <span class="inline-block px-2 py-0.5 rounded text-xs ml-2 ${tool.mock_response_type === "javascript" ? "bg-amber-100 text-amber-700" : "bg-blue-100 text-blue-700"}">
                        ${tool.mock_response_type === "javascript" ? "JS" : "JSON"}
                    </span>
                    ${tool.no_mock ? '<span class="inline-block px-2 py-0.5 rounded text-xs ml-1 bg-green-100 text-green-700">real backend</span>' : ""}
                </h4>
                <p class="mt-1 mb-0 text-gray-500 text-sm dark:text-gray-400">${tool.description || "No description"}</p>
                <code class="text-xs text-gray-400 mt-1 block">${tool.function ? tool.function.name : tool.id}</code>
            </div>
            <div class="flex gap-2">
                <button class="btn-icon delete" onclick="event.stopPropagation(); deleteTool('${tool.id}')">🗑️</button>
            </div>
        </div>
    `,
            )
            .join("");
    }

    function showAddToolModal() {
        $("#tool-modal-title").text("Add Tool");
        $("#tool-form")[0].reset();
        $("#tool-edit-id").val("");
        $("#tool-mock-type").val("json");
        document.getElementById("tool-no-mock").checked = false;
        $("#tool-backend-code").val("");
        $("#tool-test-args-real").val("{}");
        $("#tool-test-args-mock").val("{}");
        $("#tool-test-result-real, #tool-test-result-mock").addClass("hidden");
        $("#tool-test-status-real, #tool-test-status-mock").addClass("hidden");
        $("#tool-backend-save-status").addClass("hidden");
        toggleMockResponseHelp();
        switchToolModalTab("info");
        switchToolModalOpTab("prod");
        openModal("tool-modal");
    }

    async function editTool(toolId) {
        try {
            const tool = await apiGet(`/api/settings/tools/${toolId}`);

            $("#tool-modal-title").text("Edit Tool");
            $("#tool-edit-id").val(tool.id);
            $("#tool-id-input").val(tool.id);
            $("#tool-name").val(tool.name || "");
            $("#tool-description").val(tool.description || "");
            $("#tool-func-name").val(tool.function ? tool.function.name : "");
            $("#tool-func-description").val(
                tool.function ? tool.function.description || "" : "",
            );
            $("#tool-parameters").val(
                tool.function && tool.function.parameters
                    ? JSON.stringify(tool.function.parameters, null, 2)
                    : "",
            );
            $("#tool-mock-type").val(tool.mock_response_type || "json");
            document.getElementById("tool-no-mock").checked = !!tool.no_mock;

            // Mock response
            if (tool.mock_response_type === "javascript") {
                $("#tool-mock-response").val(tool.mock_response || "");
            } else {
                $("#tool-mock-response").val(
                    typeof tool.mock_response === "object"
                        ? JSON.stringify(tool.mock_response, null, 2)
                        : tool.mock_response || "",
                );
            }

            // Pre-fill test args from parameter schema
            let sampleArgs = "{}";
            const params =
                tool.function &&
                tool.function.parameters &&
                tool.function.parameters.properties;
            if (params) {
                const sample = {};
                for (const [k, v] of Object.entries(params)) {
                    sample[k] =
                        v.type === "number" || v.type === "integer"
                            ? 0
                            : v.type === "boolean"
                              ? false
                              : "";
                }
                sampleArgs = JSON.stringify(sample, null, 2);
            }
            $("#tool-test-args-real").val(sampleArgs);
            $("#tool-test-args-mock").val(sampleArgs);
            $("#tool-test-result-real, #tool-test-result-mock").addClass(
                "hidden",
            );
            $("#tool-test-status-real, #tool-test-status-mock").addClass(
                "hidden",
            );
            $("#tool-backend-save-status").addClass("hidden");

            // Fetch backend Python code
            const fnName = (tool.function && tool.function.name) || tool.id;
            try {
                const backend = await apiGet(
                    `/api/settings/tools/${encodeURIComponent(fnName)}/backend`,
                );
                if (backend.exists) {
                    $("#tool-backend-code").val(backend.code);
                } else {
                    $("#tool-backend-code").val(
                        `"""Backend implementation for the ${fnName} tool."""\n\n\ndef execute(agent, args: dict) -> dict:\n    # agent: dict with agent_id, agent_name, user_id, channel_id, session_id\n    # args: dict of arguments passed by the LLM\n    return {"result": "not implemented"}\n`,
                    );
                }
            } catch (e) {
                $("#tool-backend-code").val(
                    `"""Backend implementation for the ${fnName} tool."""\n\n\ndef execute(agent, args: dict) -> dict:\n    return {"result": "not implemented"}\n`,
                );
            }

            toggleMockResponseHelp();
            switchToolModalTab("info");
            switchToolModalOpTab("prod");
            openModal("tool-modal");
        } catch (error) {
            alert("Error loading tool: " + error);
        }
    }

    async function saveTool() {
        const toolId = document.getElementById("tool-edit-id").value || null;

        // Build function definition
        let parameters = null;
        const paramsText = document
            .getElementById("tool-parameters")
            .value.trim();
        if (paramsText) {
            try {
                parameters = JSON.parse(paramsText);
            } catch (e) {
                alert("Invalid JSON in Parameters field");
                return;
            }
        }

        const mockType = document.getElementById("tool-mock-type").value;
        let mockResponse = document
            .getElementById("tool-mock-response")
            .value.trim();

        if (mockType === "json" && mockResponse) {
            try {
                mockResponse = JSON.parse(mockResponse);
            } catch (e) {
                alert("Invalid JSON in Mock Response field");
                return;
            }
        }

        const funcDef = {
            name: document.getElementById("tool-func-name").value,
            description:
                document.getElementById("tool-func-description").value || "",
            parameters: parameters || {
                type: "object",
                properties: {},
                required: [],
            },
        };

        const data = {
            id: document.getElementById("tool-id-input").value || undefined,
            name: document.getElementById("tool-name").value,
            description: document.getElementById("tool-description").value,
            function: funcDef,
            mock_response: mockResponse || null,
            mock_response_type: mockType,
            no_mock: document.getElementById("tool-no-mock").checked,
        };

        try {
            let result;
            if (toolId) {
                result = await apiPut(`/api/settings/tools/${toolId}`, data);
            } else {
                result = await apiPost("/api/settings/tools", data);
            }

            if (result.success) {
                closeModal("tool-modal");
                loadTools();
            } else {
                alert("Error: " + result.error);
            }
        } catch (error) {
            alert("Error saving tool: " + error);
        }
    }

    async function deleteTool(toolId) {
        if (
            !(await showConfirm({
                title: "Delete Tool",
                message: "Delete this tool? This cannot be undone.",
                confirmText: "Delete",
            }))
        )
            return;

        try {
            const result = await apiDelete(`/api/settings/tools/${toolId}`);
            if (result.success) {
                loadTools();
            }
        } catch (error) {
            alert("Error deleting tool: " + error);
        }
    }

    function toggleMockResponseHelp() {
        const type = $("#tool-mock-type").val();
        if (type === "javascript") {
            $("#tool-mock-help-json").addClass("hidden");
            $("#tool-mock-help-js").removeClass("hidden");
            $("#tool-mock-response").attr(
                "placeholder",
                'const args = JSON.parse(ARGS);\n// process args\nconsole.log(JSON.stringify({result: "value"}));',
            );
        } else {
            $("#tool-mock-help-json").removeClass("hidden");
            $("#tool-mock-help-js").addClass("hidden");
            $("#tool-mock-response").attr(
                "placeholder",
                '{"result": "sample data"}',
            );
        }
    }

    function switchToolModalTab(tab) {
        const tabs = ["info", "operation"];
        tabs.forEach((t) => {
            $(`#tool-main-tab-${t}`).toggleClass("hidden", t !== tab);
            const $btn = $(`#tool-main-tab-btn-${t}`);
            $btn.toggleClass("border-blue-500 text-blue-600", t === tab);
            $btn.toggleClass("border-transparent text-gray-500", t !== tab);
        });
    }

    function switchToolModalOpTab(tab) {
        const tabs = ["prod", "mock"];
        tabs.forEach((t) => {
            $(`#tool-op-tab-${t}`).toggleClass("hidden", t !== tab);
            const $btn = $(`#tool-op-tab-btn-${t}`);
            $btn.toggleClass("border-indigo-500 text-indigo-600", t === tab);
            $btn.toggleClass("border-transparent text-gray-500", t !== tab);
        });
    }

    async function saveToolBackendCode() {
        const toolId = $("#tool-edit-id").val();
        if (!toolId) return;
        const code = $("#tool-backend-code").val();
        try {
            const res = await fetch(
                `/api/settings/tools/${encodeURIComponent(toolId)}/backend`,
                {
                    method: "PUT",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ code }),
                },
            );
            const data = await res.json();
            const $st = $("#tool-backend-save-status");
            if (data.success) {
                $st.text("Saved!")
                    .removeClass("hidden text-red-600")
                    .addClass("text-green-600");
            } else {
                $st.text(data.error || "Save failed")
                    .removeClass("hidden text-green-600")
                    .addClass("text-red-600");
            }
            setTimeout(() => $st.addClass("hidden"), 2000);
        } catch (e) {
            const $st = $("#tool-backend-save-status");
            $st.text("Network error")
                .removeClass("hidden text-green-600")
                .addClass("text-red-600");
            setTimeout(() => $st.addClass("hidden"), 2000);
        }
    }

    async function testToolExecSettings(mode) {
        const toolId = $("#tool-edit-id").val();
        if (!toolId) return;

        const $argsEl = $(`#tool-test-args-${mode}`);
        const $resultEl = $(`#tool-test-result-${mode}`);
        const $statusEl = $(`#tool-test-status-${mode}`);

        let args = {};
        const raw = $argsEl.val().trim();
        if (raw) {
            try {
                args = JSON.parse(raw);
            } catch (e) {
                $resultEl
                    .text("Invalid JSON: " + e.message)
                    .removeClass("hidden text-gray-700 border-gray-200")
                    .addClass("text-red-600 border-red-200")
                    .css("max-height", "200px");
                return;
            }
        }

        $statusEl.text("Running...").removeClass("hidden");
        $resultEl.addClass("hidden");

        // Mock mode: run client-side
        if (mode === "mock") {
            const tool = tools.find((t) => t.id === toolId);
            $statusEl.addClass("hidden");
            if (!tool || tool.mock_response == null) {
                $resultEl
                    .text("Error: No mock response defined for this tool")
                    .attr(
                        "class",
                        "mt-2 bg-red-50 border border-red-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-red-700",
                    )
                    .removeClass("hidden")
                    .css("max-height", "200px");
                return;
            }
            try {
                let result;
                if (tool.mock_response_type === "javascript") {
                    const lines = [];
                    const mockFn = new Function(
                        "ARGS",
                        "console",
                        tool.mock_response,
                    );
                    const fakeConsole = {
                        log: (...a) => lines.push(a.map(String).join(" ")),
                    };
                    const retVal = mockFn(args, fakeConsole);
                    if (lines.length > 0) {
                        result = lines.join("\n");
                    } else if (retVal !== undefined) {
                        result = retVal;
                    } else {
                        result = "(no output)";
                    }
                } else {
                    result = tool.mock_response;
                }
                $resultEl
                    .text(
                        typeof result === "string"
                            ? result
                            : JSON.stringify(result, null, 2),
                    )
                    .attr(
                        "class",
                        "mt-2 bg-gray-50 border border-gray-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-gray-700",
                    );
            } catch (e) {
                $resultEl
                    .text("Error: " + e.message)
                    .attr(
                        "class",
                        "mt-2 bg-red-50 border border-red-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-red-700",
                    );
            }
            $resultEl.removeClass("hidden").css("max-height", "200px");
            return;
        }

        // Real mode: server-side
        try {
            const res = await fetch(
                `/api/settings/tools/${encodeURIComponent(toolId)}/test`,
                {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ args, mode }),
                },
            );
            const data = await res.json();
            $statusEl.addClass("hidden");
            if (data.error) {
                $resultEl
                    .text("Error: " + data.error)
                    .attr(
                        "class",
                        "mt-2 bg-red-50 border border-red-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-red-700",
                    );
            } else {
                $resultEl
                    .text(JSON.stringify(data.result, null, 2))
                    .attr(
                        "class",
                        "mt-2 bg-gray-50 border border-gray-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-gray-700",
                    );
            }
            $resultEl.removeClass("hidden").css("max-height", "200px");
        } catch (e) {
            $statusEl.addClass("hidden");
            $resultEl
                .text("Network error: " + e.message)
                .attr(
                    "class",
                    "mt-2 bg-red-50 border border-red-200 rounded-md p-3 text-xs font-mono whitespace-pre-wrap overflow-x-auto text-red-700",
                )
                .removeClass("hidden")
                .css("max-height", "200px");
        }
    }

    // ==================== Models Tab ====================
    let allModels = [];
    let allAgents = [];
    let modelSearchQuery = "";

    async function loadModels() {
        try {
            const response = await fetch("/api/models");
            const data = await response.json();
            allModels = data.models || [];
            renderModels();
        } catch (error) {
            console.error("Failed to load models:", error);
        }
    }

    function renderModels() {
        const modelsList = document.getElementById("models-list");
        const q = modelSearchQuery.toLowerCase().trim();
        const filtered = q
            ? allModels.filter(
                  (m) =>
                      (m.name || "").toLowerCase().includes(q) ||
                      (m.provider || "").toLowerCase().includes(q) ||
                      (m.model_name || "").toLowerCase().includes(q) ||
                      (m.type || "").toLowerCase().includes(q),
              )
            : allModels;

        if (filtered.length === 0) {
            modelsList.innerHTML =
                '<p class="text-gray-500 text-center py-4 col-span-full">No models match your search.</p>';
            return;
        }

        modelsList.innerHTML = filtered
            .map(
                (model) => {
                    const typeColors = model.type === "remote"
                        ? "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
                        : "bg-green-100 text-green-700 dark:bg-green-900/50 dark:text-green-300";
                    const enabledColors = model.enabled
                        ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300"
                        : "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300";
                    const defaultBorder = model.is_default ? "border-indigo-400 dark:border-indigo-500 ring-1 ring-indigo-200 dark:ring-indigo-800" : "border-gray-200 dark:border-gray-700";
                    return `
        <div class="model-card bg-white dark:bg-gray-800 rounded-lg border ${defaultBorder} p-3 hover:shadow-sm transition-shadow flex items-start justify-between gap-2">
            <!-- Left content area -->
            <div class="flex-1 min-w-0">
                <!-- Top row: name + default badge -->
                <div class="flex items-start justify-between gap-2 mb-2">
                    <div class="flex-1 min-w-0">
                        <h4 class="font-semibold text-sm text-gray-900 dark:text-gray-100 truncate">${model.name}</h4>
                    </div>
                    ${model.is_default ? '<span class="shrink-0 bg-indigo-600 text-white px-1.5 py-0.5 rounded text-[10px] font-semibold leading-none">Default</span>' : ""}
                </div>

                <!-- Badges row -->
                <div class="flex flex-wrap items-center gap-1.5 mb-2">
                    <span class="inline-block px-1.5 py-0.5 rounded text-[11px] font-medium ${typeColors}">${model.type}</span>
                    <span class="inline-block px-1.5 py-0.5 rounded text-[11px] font-medium ${enabledColors}">${model.enabled ? "On" : "Off"}</span>
                    ${model.thinking ? '<span class="inline-block px-1.5 py-0.5 rounded text-[11px] font-medium bg-yellow-100 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-300">Thinking</span>' : ""}
                </div>

                <!-- Provider / model info -->
                <div class="text-[11px] text-gray-500 dark:text-gray-400 truncate">
                    ${model.provider} · ${model.model_name}
                </div>
            </div>

            <!-- Action buttons (right side, horizontal) -->
            <div class="flex flex-row items-center gap-1.5 shrink-0 self-end">
                ${!model.is_default ? `<button class="p-1 rounded border border-amber-400 dark:border-amber-500 text-amber-500 dark:text-amber-400 bg-transparent cursor-pointer hover:bg-amber-50 dark:hover:bg-amber-950/50 transition-colors" onclick="setDefaultModel('${model.id}')" title="Set Default"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"/></svg></button>` : ""}
                <button class="p-1 rounded border border-gray-300 dark:border-gray-600 bg-transparent cursor-pointer text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors" onclick="testConnection('${model.id}')" title="Test"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg></button>
                <button class="p-1 rounded border border-indigo-400 dark:border-indigo-500 text-indigo-500 dark:text-indigo-400 bg-transparent cursor-pointer hover:bg-indigo-50 dark:hover:bg-indigo-950/50 transition-colors" onclick="editModel('${model.id}')" title="Edit"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg></button>
                <button class="p-1 rounded border border-emerald-400 dark:border-emerald-500 text-emerald-500 dark:text-emerald-400 bg-transparent cursor-pointer hover:bg-emerald-50 dark:hover:bg-emerald-950/50 transition-colors" onclick="cloneModel('${model.id}')" title="Clone"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><rect x="9" y="9" width="13" height="13" rx="2" stroke-width="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" stroke-width="2" stroke-linecap="round"/></svg></button>
                <button class="p-1 rounded border border-red-400 dark:border-red-500 text-red-400 dark:text-red-400 bg-transparent cursor-pointer hover:bg-red-50 dark:hover:bg-red-950/50 transition-colors" onclick="deleteModel('${model.id}')" title="Delete"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/></svg></button>
            </div>
        </div>
    `;
                },
            )
            .join("");
    }

    function filterModels() {
        modelSearchQuery = document.getElementById("model-search-input").value;
        renderModels();
    }

    async function showAddModelModal() {
        document.getElementById("modal-title").textContent = "Add Model";
        document.getElementById("model-form").reset();
        document.getElementById("model-id").value = "";
        $("#model-modal").addClass("active");
    }

    function editModel(modelId) {
        const model = allModels.find((m) => m.id === modelId);
        if (!model) return;

        document.getElementById("modal-title").textContent = "Edit Model";
        document.getElementById("model-id").value = model.id;
        document.getElementById("model-name").value = model.name || "";
        document.getElementById("model-type").value = model.type || "remote";
        document.getElementById("model-provider").value =
            model.provider || "custom";
        document.getElementById("model-base-url").value = model.base_url || "";
        document.getElementById("model-api-key").value = model.api_key || "";
        document.getElementById("model-name-param").value =
            model.model_name || "";
        document.getElementById("model-max-tokens").value =
            model.max_tokens || 32768;
        document.getElementById("model-timeout").value = model.timeout || 60;
        document.getElementById("model-max-concurrent").value =
            model.model_max_concurrent != null ? model.model_max_concurrent : 1;
        document.getElementById("model-temperature").value =
            model.temperature != null ? model.temperature : "";
        document.getElementById("model-thinking").checked = !!model.thinking;
        document.getElementById("model-thinking-budget").value =
            model.thinking_budget || 0;
        document.getElementById("model-enabled").checked = !!model.enabled;
        document.getElementById("model-is-default").checked =
            !!model.is_default;
        document.getElementById("model-vision-supported").checked =
            !!model.vision_supported;
        document.getElementById("model-attachments-supported").checked =
            !!model.attachments_supported;

        toggleModelFields();
        $("#model-modal").addClass("active");
    }

    function toggleModelFields() {
        const type = document.getElementById("model-type").value;
        const provider = document.getElementById("model-provider").value;
        const apiKeyGroup = document.getElementById("api-key-group");
        if (
            type === "local" &&
            (provider === "ollama" || provider === "llama.cpp")
        ) {
            apiKeyGroup.style.display = "none";
        } else {
            apiKeyGroup.style.display = "block";
        }
        const idHint = document.getElementById("model-id-hint");
        if (idHint) {
            idHint.style.display = type === "remote" ? "block" : "none";
        }
    }

    async function saveModel(event) {
        event.preventDefault();

        const modelId = document.getElementById("model-id").value;
        const modelData = {
            name: document.getElementById("model-name").value,
            type: document.getElementById("model-type").value,
            provider: document.getElementById("model-provider").value,
            base_url: document.getElementById("model-base-url").value,
            api_key: document.getElementById("model-api-key").value,
            model_name: document.getElementById("model-name-param").value,
            max_tokens:
                parseInt(document.getElementById("model-max-tokens").value) ||
                32768,
            timeout:
                parseInt(document.getElementById("model-timeout").value) || 60,
            model_max_concurrent:
                parseInt(
                    document.getElementById("model-max-concurrent").value,
                ) || 0,
            temperature:
                document.getElementById("model-temperature").value !== ""
                    ? parseFloat(
                          document.getElementById("model-temperature").value,
                      )
                    : null,
            thinking: document.getElementById("model-thinking").checked ? 1 : 0,
            thinking_budget:
                parseInt(
                    document.getElementById("model-thinking-budget").value,
                ) || 0,
            enabled: document.getElementById("model-enabled").checked ? 1 : 0,
            is_default: document.getElementById("model-is-default").checked
                ? 1
                : 0,
            vision_supported: document.getElementById("model-vision-supported").checked ? 1 : 0,
            attachments_supported: document.getElementById("model-attachments-supported").checked ? 1 : 0,
        };

        try {
            let response;
            if (modelId) {
                response = await fetch("/api/models/" + modelId, {
                    method: "PUT",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify(modelData),
                });
            } else {
                response = await fetch("/api/models", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify(modelData),
                });
            }

            const result = await response.json();
            if (result.success) {
                closeModal("model-modal");
                await loadModels();
            } else {
                alert("Error: " + (result.error || "Failed to save model"));
            }
        } catch (error) {
            console.error("Failed to save model:", error);
            alert("Failed to save model: " + error.message);
        }
    }

    async function setDefaultModel(modelId) {
        try {
            const response = await fetch(
                "/api/models/" + modelId + "/set-default",
                {
                    method: "POST",
                },
            );
            const result = await response.json();
            if (result.success) {
                await loadModels();
            } else {
                alert("Error: " + (result.error || "Failed to set default"));
            }
        } catch (error) {
            console.error("Failed to set default:", error);
        }
    }

    async function deleteModel(modelId) {
        if (!confirm("Are you sure you want to delete this model?")) return;

        try {
            const response = await fetch("/api/models/" + modelId, {
                method: "DELETE",
            });
            const result = await response.json();
            if (result.success) {
                await loadModels();
            } else {
                alert("Error: " + (result.error || "Failed to delete model"));
            }
        } catch (error) {
            console.error("Failed to delete model:", error);
        }
    }

    async function cloneModel(modelId) {
        try {
            const response = await fetch("/api/models/" + modelId + "/clone", {
                method: "POST",
            });
            const result = await response.json();
            if (result.success) {
                await loadModels();
                // Open edit modal for the new clone so user can reconfigure
                editModel(result.model_id);
            } else {
                alert("Error: " + (result.error || "Failed to clone model"));
            }
        } catch (error) {
            console.error("Failed to clone model:", error);
            alert("Failed to clone model: " + error.message);
        }
    }

    // Track which model is currently being tested (for button re-enable on close)
    let _currentTestModelId = null;

    async function testConnection(modelId) {
        const testStatus = document.getElementById("connection-test-status");
        const footer = document.getElementById("connection-test-footer");
        const title = document.getElementById("connection-test-title");

        // Disable the test button for this specific model card
        _currentTestModelId = modelId;
        const testBtn = document.querySelector(`button[onclick*="testConnection('${modelId}')"]`);
        if (testBtn) {
            testBtn.disabled = true;
            testBtn.classList.add("opacity-50", "cursor-not-allowed");
        }

        // Show loading state
        title.textContent = "Test Connection";
        title.className = "m-0 text-gray-800 dark:text-gray-100";
        $("#connection-test-modal").addClass("active");
        testStatus.innerHTML =
            '<div class="text-center py-6"><div class="spinner"></div><p class="mt-3 text-gray-600 dark:text-gray-400">Testing connection...</p></div>';
        footer.classList.add("hidden");

        try {
            const response = await fetch("/api/models/" + modelId + "/test", {
                method: "POST",
            });
            const result = await response.json();

            if (result.success) {
                title.textContent = "Connection Successful";
                title.className = "m-0 text-green-700 dark:text-green-400";
                testStatus.innerHTML =
                    '<div class="p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-700 rounded-lg">' +
                    '<div class="flex items-center gap-2 mb-2"><svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>' +
                    '<span class="text-green-800 dark:text-green-300 font-medium">Model is reachable</span></div>' +
                    '<div class="text-green-700 dark:text-green-400 text-sm">' + result.message + '</div>' +
                    '<div class="text-green-600 dark:text-green-500 text-sm mt-1">Available models: ' + result.available_models + '</div>' +
                    "</div>";
            } else {
                title.textContent = "Connection Failed";
                title.className = "m-0 text-red-700 dark:text-red-400";
                testStatus.innerHTML =
                    '<div class="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-700 rounded-lg">' +
                    '<div class="flex items-center gap-2 mb-2"><svg class="w-5 h-5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>' +
                    '<span class="text-red-800 dark:text-red-300 font-medium">' + result.error + '</span></div>' +
                    (result.status_code ? '<div class="text-red-600 dark:text-red-500 text-sm">HTTP Status: ' + result.status_code + "</div>" : "") +
                    "</div>";
            }
        } catch (error) {
            title.textContent = "Connection Failed";
            title.className = "m-0 text-red-700 dark:text-red-400";
            testStatus.innerHTML =
                '<div class="p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-700 rounded-lg">' +
                '<div class="flex items-center gap-2 mb-2"><svg class="w-5 h-5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>' +
                '<span class="text-red-800 dark:text-red-300 font-medium">' + (error.message || "Network error") + '</span></div>' +
                "</div>";
        }

        // Show Close button in footer
        footer.classList.remove("hidden");
    }

    function closeTestModal() {
        closeModal("connection-test-modal");

        // Re-enable the test button for the previously tested model
        if (_currentTestModelId) {
            const testBtn = document.querySelector(`button[onclick*="testConnection('${_currentTestModelId}')"]`);
            if (testBtn) {
                testBtn.disabled = false;
                testBtn.classList.remove("opacity-50", "cursor-not-allowed");
            }
            _currentTestModelId = null;
        }
    }

    // ---- Default Model ----
</script>
{% endblock %}
