This commit is contained in:
Timothy Jaeryang Baek
2026-06-13 13:31:20 +02:00
Unverified
parent d2d4b3dc5c
commit 641a687b2b
12 changed files with 167 additions and 12 deletions
@@ -4,6 +4,8 @@
import {
getModelConfig,
updateModelConfig,
getAdminConfig,
updateConfig,
type ModelConfigEntry
} from '$lib/apis/admin';
import { t } from '$lib/i18n';
@@ -32,6 +34,10 @@
let globalExpanded = $state(false);
let showVariables = $state(false);
// Context compaction
let compactTokenThreshold = $state(80000);
let compactDirty = $state(false);
const TEMPLATE_VARIABLES = [
{ name: 'WORKSPACE_NAME', desc: 'Workspace folder name' },
{ name: 'WORKSPACE_PATH', desc: 'Full workspace path' },
@@ -52,7 +58,7 @@ Workspace: {{WORKSPACE_NAME}}
Files:
{{FILE_TREE}}`;
let hasDirty = $derived(globalDirty || models.some((m) => m.dirty));
let hasDirty = $derived(globalDirty || compactDirty || models.some((m) => m.dirty));
function parseRows(config: ModelConfigEntry | undefined): ParamRow[] {
const rp = config?.params?.request_params;
@@ -98,6 +104,12 @@ Files:
} finally {
loading = false;
}
// Load context compaction threshold from admin config
try {
const adminCfg = await getAdminConfig();
compactTokenThreshold = Number(adminCfg['chat.compact_token_threshold']) || 80000;
} catch {}
});
async function toggleModel(e: Event, model: ModelEntry) {
@@ -145,6 +157,13 @@ Files:
await Promise.all(promises);
globalDirty = false;
models.forEach((m) => (m.dirty = false));
// Save context compaction threshold
if (compactDirty) {
await updateConfig({ 'chat.compact_token_threshold': compactTokenThreshold });
compactDirty = false;
}
toast.success($t('settings.saved'));
} catch {
toast.error($t('models.failedToSave'));
@@ -256,6 +275,24 @@ Files:
<h2 class="text-sm font-medium text-gray-900 dark:text-white mb-4">
{$t('admin.models')}
</h2>
<!-- Context compaction -->
<h3 class="text-xs text-gray-400 dark:text-gray-600 mb-2">{$t('admin.contextCompaction')}</h3>
<div class="flex flex-col gap-2.5 mb-5">
<div>
<label class="text-xs text-gray-600 dark:text-gray-400" for="compact-threshold">{$t('admin.compactTokenThreshold')}</label>
<div class="flex items-center gap-1.5 mt-1">
<input id="compact-threshold" type="number" bind:value={compactTokenThreshold}
oninput={() => (compactDirty = true)}
min="10000" max="1000000" step="10000"
class="w-24 h-7 px-2 rounded-lg text-xs bg-gray-100 dark:bg-white/6 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-white/8 outline-none focus:border-blue-400 dark:focus:border-blue-500 transition-colors" />
<span class="text-[11px] text-gray-400 dark:text-gray-600">{$t('admin.compactTokenThresholdUnit')}</span>
</div>
<p class="text-[11px] text-gray-400 dark:text-gray-600 mt-0.5">{$t('admin.compactTokenThresholdHint')}</p>
</div>
</div>
<!-- Global defaults -->
<button
class="group flex items-center gap-2 w-full h-7 text-left"
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "Neuer API-Schlüssel erstellt. Jetzt kopieren",
"admin.gateway.noKeys": "Noch keine API-Schlüssel",
"admin.gateway.title": "API-Gateway",
"chat.greeting": "Wie kann ich Ihnen helfen?"
"chat.greeting": "Wie kann ich Ihnen helfen?",
"admin.subagents": "Sub-Agenten",
"admin.subagentsEnabled": "Sub-Agenten aktivieren",
"admin.subagentsHint": "Ermöglicht der KI, Aufgaben an Sub-Agenten zu delegieren. Jeder Sub-Agent erstellt einen echten Chat mit vollem Werkzeugzugriff. Verwendet zusätzliche LLM-Aufrufe.",
"admin.subagentsMaxConcurrent": "Max. gleichzeitig",
"admin.subagentsMaxConcurrentHint": "gleichzeitige Sub-Agenten",
"admin.subagentsMaxIterations": "Max. Iterationen",
"admin.subagentsMaxIterationsHint": "Werkzeugschleifen pro Sub-Agent",
"admin.subagentsMaxOutput": "Max. Ausgabe",
"admin.subagentsSystemPrompt": "System-Prompt",
"admin.subagentsSystemPromptPlaceholder": "Du bist ein Sub-Agent...",
"admin.subagentsSystemPromptHint": "Leer lassen für den integrierten Standard."
}
+6 -1
View File
@@ -692,6 +692,11 @@
"admin.subagentsMaxOutput": "Max output",
"admin.subagentsSystemPrompt": "System prompt",
"admin.subagentsSystemPromptPlaceholder": "You are a sub-agent...",
"admin.subagentsSystemPromptHint": "Leave empty for the built-in default."
"admin.subagentsSystemPromptHint": "Leave empty for the built-in default.",
"admin.contextCompaction": "Context compaction",
"admin.compactTokenThreshold": "Token threshold",
"admin.compactTokenThresholdUnit": "tokens",
"admin.compactTokenThresholdHint": "Older messages are summarized when estimated context exceeds this limit. Default: 80,000."
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "Nueva clave API creada. Cópiala ahora",
"admin.gateway.noKeys": "Aún no hay claves API",
"admin.gateway.title": "API Gateway",
"chat.greeting": "¿En qué puedo ayudarte?"
"chat.greeting": "¿En qué puedo ayudarte?",
"admin.subagents": "Sub-agentes",
"admin.subagentsEnabled": "Habilitar sub-agentes",
"admin.subagentsHint": "Permite a la IA delegar tareas a sub-agentes. Cada sub-agente crea un chat real con acceso completo a herramientas. Usa llamadas LLM adicionales.",
"admin.subagentsMaxConcurrent": "Máx. simultáneos",
"admin.subagentsMaxConcurrentHint": "sub-agentes simultáneos",
"admin.subagentsMaxIterations": "Máx. iteraciones",
"admin.subagentsMaxIterationsHint": "bucles de herramientas por sub-agente",
"admin.subagentsMaxOutput": "Máx. salida",
"admin.subagentsSystemPrompt": "Prompt del sistema",
"admin.subagentsSystemPromptPlaceholder": "Eres un sub-agente...",
"admin.subagentsSystemPromptHint": "Dejar vacío para el valor predeterminado."
}
+13 -1
View File
@@ -568,5 +568,17 @@
"admin.gateway.newKey": "Nouvelle clé API créée. Copiez-la maintenant",
"admin.gateway.noKeys": "Aucune clé API",
"admin.gateway.title": "Passerelle API",
"chat.greeting": "Comment puis-je vous aider ?"
"chat.greeting": "Comment puis-je vous aider ?",
"admin.subagents": "Sous-agents",
"admin.subagentsEnabled": "Activer les sous-agents",
"admin.subagentsHint": "Permet à l'IA de déléguer des tâches à des sous-agents. Chaque sous-agent crée un vrai chat avec un accès complet aux outils. Utilise des appels LLM supplémentaires.",
"admin.subagentsMaxConcurrent": "Max. simultanés",
"admin.subagentsMaxConcurrentHint": "sous-agents simultanés",
"admin.subagentsMaxIterations": "Max. itérations",
"admin.subagentsMaxIterationsHint": "boucles d'outils par sous-agent",
"admin.subagentsMaxOutput": "Max. sortie",
"admin.subagentsSystemPrompt": "Prompt système",
"admin.subagentsSystemPromptPlaceholder": "Vous êtes un sous-agent...",
"admin.subagentsSystemPromptHint": "Laisser vide pour la valeur par défaut."
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "新しいAPIキーが作成されました。今すぐコピーしてください",
"admin.gateway.noKeys": "APIキーがまだありません",
"admin.gateway.title": "APIゲートウェイ",
"chat.greeting": "何かお手伝いできますか?"
"chat.greeting": "何かお手伝いできますか?",
"admin.subagents": "サブエージェント",
"admin.subagentsEnabled": "サブエージェントを有効にする",
"admin.subagentsHint": "AIがサブエージェントにタスクを委任できるようにします。各サブエージェントはフルツールアクセス付きの実際のチャットを作成します。追加のLLMコールを使用します。",
"admin.subagentsMaxConcurrent": "最大同時実行数",
"admin.subagentsMaxConcurrentHint": "同時実行サブエージェント",
"admin.subagentsMaxIterations": "最大反復回数",
"admin.subagentsMaxIterationsHint": "サブエージェントあたりのツールループ",
"admin.subagentsMaxOutput": "最大出力",
"admin.subagentsSystemPrompt": "システムプロンプト",
"admin.subagentsSystemPromptPlaceholder": "あなたはサブエージェントです...",
"admin.subagentsSystemPromptHint": "組み込みデフォルトを使用する場合は空のままにしてください。"
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "새 API 키가 생성되었습니다. 지금 복사하세요",
"admin.gateway.noKeys": "API 키가 아직 없습니다",
"admin.gateway.title": "API 게이트웨이",
"chat.greeting": "무엇을 도와드릴까요?"
"chat.greeting": "무엇을 도와드릴까요?",
"admin.subagents": "서브 에이전트",
"admin.subagentsEnabled": "서브 에이전트 활성화",
"admin.subagentsHint": "AI가 서브 에이전트에 작업을 위임할 수 있게 합니다. 각 서브 에이전트는 전체 도구 액세스 권한이 있는 실제 채팅을 생성합니다. 추가 LLM 호출을 사용합니다.",
"admin.subagentsMaxConcurrent": "최대 동시 실행",
"admin.subagentsMaxConcurrentHint": "동시 서브 에이전트",
"admin.subagentsMaxIterations": "최대 반복 횟수",
"admin.subagentsMaxIterationsHint": "서브 에이전트당 도구 루프",
"admin.subagentsMaxOutput": "최대 출력",
"admin.subagentsSystemPrompt": "시스템 프롬프트",
"admin.subagentsSystemPromptPlaceholder": "당신은 서브 에이전트입니다...",
"admin.subagentsSystemPromptHint": "기본값을 사용하려면 비워두세요."
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "Nova chave API criada. Copie-a agora",
"admin.gateway.noKeys": "Nenhuma chave API ainda",
"admin.gateway.title": "API Gateway",
"chat.greeting": "Como posso ajudar?"
"chat.greeting": "Como posso ajudar?",
"admin.subagents": "Sub-agentes",
"admin.subagentsEnabled": "Habilitar sub-agentes",
"admin.subagentsHint": "Permite que a IA delegue tarefas para sub-agentes. Cada sub-agente cria um chat real com acesso total às ferramentas. Usa chamadas LLM adicionais.",
"admin.subagentsMaxConcurrent": "Máx. simultâneos",
"admin.subagentsMaxConcurrentHint": "sub-agentes simultâneos",
"admin.subagentsMaxIterations": "Máx. iterações",
"admin.subagentsMaxIterationsHint": "loops de ferramentas por sub-agente",
"admin.subagentsMaxOutput": "Máx. saída",
"admin.subagentsSystemPrompt": "Prompt do sistema",
"admin.subagentsSystemPromptPlaceholder": "Você é um sub-agente...",
"admin.subagentsSystemPromptHint": "Deixe vazio para o padrão integrado."
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "Новый API-ключ создан. Скопируйте его сейчас",
"admin.gateway.noKeys": "API-ключей пока нет",
"admin.gateway.title": "API-шлюз",
"chat.greeting": "Чем могу помочь?"
"chat.greeting": "Чем могу помочь?",
"admin.subagents": "Суб-агенты",
"admin.subagentsEnabled": "Включить суб-агентов",
"admin.subagentsHint": "Позволяет ИИ делегировать задачи суб-агентам. Каждый суб-агент создаёт реальный чат с полным доступом к инструментам. Использует дополнительные вызовы LLM.",
"admin.subagentsMaxConcurrent": "Макс. одновременно",
"admin.subagentsMaxConcurrentHint": "одновременных суб-агентов",
"admin.subagentsMaxIterations": "Макс. итераций",
"admin.subagentsMaxIterationsHint": "циклов инструментов на суб-агента",
"admin.subagentsMaxOutput": "Макс. вывод",
"admin.subagentsSystemPrompt": "Системный промпт",
"admin.subagentsSystemPromptPlaceholder": "Вы — суб-агент...",
"admin.subagentsSystemPromptHint": "Оставьте пустым для значения по умолчанию."
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "新 API 密钥已创建。请立即复制",
"admin.gateway.noKeys": "暂无 API 密钥",
"admin.gateway.title": "API 网关",
"chat.greeting": "有什么可以帮您的?"
"chat.greeting": "有什么可以帮您的?",
"admin.subagents": "子代理",
"admin.subagentsEnabled": "启用子代理",
"admin.subagentsHint": "允许 AI 将任务委托给子代理。每个子代理会创建一个拥有完整工具访问权限的真实聊天。会使用额外的 LLM 调用。",
"admin.subagentsMaxConcurrent": "最大并发数",
"admin.subagentsMaxConcurrentHint": "个同时运行的子代理",
"admin.subagentsMaxIterations": "最大迭代次数",
"admin.subagentsMaxIterationsHint": "每个子代理的工具循环次数",
"admin.subagentsMaxOutput": "最大输出",
"admin.subagentsSystemPrompt": "系统提示词",
"admin.subagentsSystemPromptPlaceholder": "你是一个子代理...",
"admin.subagentsSystemPromptHint": "留空以使用内置默认值。"
}
+13 -1
View File
@@ -569,5 +569,17 @@
"admin.gateway.newKey": "新 API 金鑰已建立。請立即複製",
"admin.gateway.noKeys": "尚無 API 金鑰",
"admin.gateway.title": "API 閘道",
"chat.greeting": "有什麼可以幫您的?"
"chat.greeting": "有什麼可以幫您的?",
"admin.subagents": "子代理",
"admin.subagentsEnabled": "啟用子代理",
"admin.subagentsHint": "允許 AI 將任務委派給子代理。每個子代理會建立一個擁有完整工具存取權限的真實聊天。會使用額外的 LLM 呼叫。",
"admin.subagentsMaxConcurrent": "最大同時數",
"admin.subagentsMaxConcurrentHint": "個同時執行的子代理",
"admin.subagentsMaxIterations": "最大迭代次數",
"admin.subagentsMaxIterationsHint": "每個子代理的工具迴圈次數",
"admin.subagentsMaxOutput": "最大輸出",
"admin.subagentsSystemPrompt": "系統提示詞",
"admin.subagentsSystemPromptPlaceholder": "你是一個子代理...",
"admin.subagentsSystemPromptHint": "留空以使用內建預設值。"
}
+6 -1
View File
@@ -63,11 +63,16 @@ def should_compact(
def _get_threshold() -> int:
"""Read threshold: config.toml > env var/default."""
"""Read threshold: app_config (admin UI) > config.toml [chat] > env var/default."""
try:
from cptr.utils.config import load_config
config = load_config()
# Admin UI saves to [app_config] with dotted keys
val = config.get("app_config", {}).get("chat.compact_token_threshold")
if val is not None:
return int(val)
# Manual config.toml [chat] section
val = config.get("chat", {}).get("compact_token_threshold")
if val is not None:
return int(val)