clay-server 2.10.0 → 2.11.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +157 -1
- package/lib/daemon.js +341 -2
- package/lib/dm.js +135 -0
- package/lib/os-users.js +301 -0
- package/lib/pages.js +36 -0
- package/lib/project.js +386 -67
- package/lib/public/app.js +675 -17
- package/lib/public/css/admin.css +99 -10
- package/lib/public/css/filebrowser.css +22 -0
- package/lib/public/css/icon-strip.css +162 -1
- package/lib/public/css/menus.css +23 -0
- package/lib/public/css/messages.css +245 -0
- package/lib/public/css/overlays.css +88 -0
- package/lib/public/css/server-settings.css +30 -2
- package/lib/public/css/sidebar.css +4 -0
- package/lib/public/index.html +140 -66
- package/lib/public/modules/admin.js +179 -12
- package/lib/public/modules/input.js +13 -2
- package/lib/public/modules/notifications.js +3 -1
- package/lib/public/modules/project-settings.js +154 -168
- package/lib/public/modules/server-settings.js +78 -189
- package/lib/public/modules/settings-defaults.js +243 -0
- package/lib/public/modules/sidebar.js +112 -6
- package/lib/public/modules/terminal.js +48 -10
- package/lib/public/modules/tools.js +214 -1
- package/lib/sdk-bridge.js +634 -6
- package/lib/sdk-worker.js +446 -0
- package/lib/server.js +335 -3
- package/lib/sessions.js +26 -0
- package/lib/terminal-manager.js +2 -2
- package/lib/terminal.js +20 -4
- package/lib/updater.js +38 -11
- package/lib/users.js +79 -0
- package/package.json +2 -2
|
@@ -3,6 +3,8 @@ import { refreshIcons } from './icons.js';
|
|
|
3
3
|
import { showToast, copyToClipboard } from './utils.js';
|
|
4
4
|
import { parseEnvString, looksLikeEnv } from './project-settings.js';
|
|
5
5
|
import { checkAdminAccess, loadAdminSection } from './admin.js';
|
|
6
|
+
import { closeFileViewer } from './filebrowser.js';
|
|
7
|
+
import { renderModelList, renderModeList, renderEffortBar, renderThinkingBar, renderBetaCard, isSonnetModel } from './settings-defaults.js';
|
|
6
8
|
|
|
7
9
|
var ctx = null;
|
|
8
10
|
var settingsEl = null;
|
|
@@ -12,26 +14,6 @@ var navItems = null;
|
|
|
12
14
|
var sections = null;
|
|
13
15
|
var statsTimer = null;
|
|
14
16
|
|
|
15
|
-
var SS_MODE_OPTIONS = [
|
|
16
|
-
{ value: "default", label: "Default", desc: "Claude asks for permission before running tools and editing files." },
|
|
17
|
-
{ value: "plan", label: "Plan", desc: "Claude creates a plan first and asks for approval before making changes." },
|
|
18
|
-
{ value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically. Claude still asks before running commands." },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
var SS_EFFORT_LEVELS = [
|
|
22
|
-
{ value: "low", desc: "Quick, concise responses. Best for simple questions." },
|
|
23
|
-
{ value: "medium", desc: "Balanced responses with moderate reasoning. Good for most tasks." },
|
|
24
|
-
{ value: "high", desc: "Thorough responses with deeper analysis. Good for complex tasks." },
|
|
25
|
-
{ value: "max", desc: "Maximum reasoning depth. Best for the most difficult problems." },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
var SS_MODEL_DESCRIPTIONS = {
|
|
29
|
-
"default": "Automatically selects the best model for the task.",
|
|
30
|
-
"sonnet": "Fast and capable. Great balance of speed and intelligence.",
|
|
31
|
-
"haiku": "Fastest model. Best for quick tasks and simple questions.",
|
|
32
|
-
"opus": "Most powerful model. Best for complex reasoning and analysis.",
|
|
33
|
-
};
|
|
34
|
-
|
|
35
17
|
export function initServerSettings(appCtx) {
|
|
36
18
|
ctx = appCtx;
|
|
37
19
|
settingsEl = document.getElementById("server-settings");
|
|
@@ -257,6 +239,7 @@ function switchSection(sectionName) {
|
|
|
257
239
|
}
|
|
258
240
|
|
|
259
241
|
function openSettings() {
|
|
242
|
+
closeFileViewer();
|
|
260
243
|
settingsEl.classList.remove("hidden");
|
|
261
244
|
settingsBtn.classList.add("active");
|
|
262
245
|
refreshIcons(settingsEl);
|
|
@@ -281,7 +264,7 @@ function openSettings() {
|
|
|
281
264
|
function resetRestartButton() {
|
|
282
265
|
var btn = document.getElementById("settings-restart-btn");
|
|
283
266
|
var errorEl = document.getElementById("settings-restart-error");
|
|
284
|
-
if (btn) { btn.disabled = false; btn.innerHTML = '<i data-lucide="refresh-cw" style="width:14px;height:14px;vertical-align:-2px;margin-right:4px;"></i>Restart
|
|
267
|
+
if (btn) { btn.disabled = false; btn.innerHTML = '<i data-lucide="refresh-cw" style="width:14px;height:14px;vertical-align:-2px;margin-right:4px;"></i>Restart'; }
|
|
285
268
|
if (errorEl) errorEl.classList.add("hidden");
|
|
286
269
|
}
|
|
287
270
|
|
|
@@ -315,19 +298,14 @@ function requestStats() {
|
|
|
315
298
|
}
|
|
316
299
|
|
|
317
300
|
function populateSettings() {
|
|
318
|
-
// Server name
|
|
319
301
|
var nameEl = document.getElementById("settings-server-name");
|
|
320
|
-
var projNameEl = document.getElementById("settings-project-name");
|
|
321
|
-
var cwdEl = document.getElementById("settings-project-cwd");
|
|
322
302
|
var versionEl = document.getElementById("settings-server-version");
|
|
323
303
|
var slugEl = document.getElementById("settings-project-slug");
|
|
324
304
|
var wsPathEl = document.getElementById("settings-ws-path");
|
|
325
305
|
var skipPermsEl = document.getElementById("settings-skip-perms");
|
|
326
306
|
|
|
327
|
-
|
|
328
|
-
if (nameEl) nameEl.textContent =
|
|
329
|
-
if (projNameEl) projNameEl.textContent = projectName;
|
|
330
|
-
if (cwdEl) cwdEl.textContent = ctx.projectName || "-";
|
|
307
|
+
// Nav header defaults to hostname (updated by updateDaemonConfig)
|
|
308
|
+
if (nameEl && !nameEl.textContent) nameEl.textContent = "Server";
|
|
331
309
|
|
|
332
310
|
var footerVersion = document.getElementById("footer-version");
|
|
333
311
|
if (versionEl && footerVersion) {
|
|
@@ -352,6 +330,7 @@ function populateSettings() {
|
|
|
352
330
|
updateModelList();
|
|
353
331
|
updateModeList();
|
|
354
332
|
updateEffortBar();
|
|
333
|
+
updateThinkingBar();
|
|
355
334
|
updateSsBetaCard();
|
|
356
335
|
}
|
|
357
336
|
|
|
@@ -368,174 +347,49 @@ function syncNotifToggles() {
|
|
|
368
347
|
}
|
|
369
348
|
}
|
|
370
349
|
|
|
371
|
-
function
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
350
|
+
function ssSendMsg(type, data) {
|
|
351
|
+
var ws = ctx.ws;
|
|
352
|
+
if (ws && ws.readyState === 1) {
|
|
353
|
+
var msg = Object.assign({ type: type }, data);
|
|
354
|
+
ws.send(JSON.stringify(msg));
|
|
376
355
|
}
|
|
377
|
-
return "";
|
|
378
356
|
}
|
|
379
357
|
|
|
380
|
-
function
|
|
381
|
-
|
|
382
|
-
|
|
358
|
+
function ssDefaultsOpts() {
|
|
359
|
+
return {
|
|
360
|
+
models: ctx.currentModels || [],
|
|
361
|
+
currentModel: ctx.currentModel || ctx._currentModelValue || "",
|
|
362
|
+
currentMode: ctx.currentMode || "default",
|
|
363
|
+
currentEffort: ctx.currentEffort || "medium",
|
|
364
|
+
currentThinking: ctx.currentThinking || "adaptive",
|
|
365
|
+
currentThinkingBudget: ctx.currentThinkingBudget || 10000,
|
|
366
|
+
currentBetas: ctx.currentBetas || [],
|
|
367
|
+
sendMsg: ssSendMsg,
|
|
368
|
+
modelMsgType: "set_model",
|
|
369
|
+
modeMsgType: "set_server_default_mode",
|
|
370
|
+
effortMsgType: "set_server_default_effort",
|
|
371
|
+
onModelSelect: function (model) { updateSsBetaCard(model); },
|
|
372
|
+
};
|
|
383
373
|
}
|
|
384
374
|
|
|
385
375
|
function updateModelList() {
|
|
386
|
-
|
|
387
|
-
if (!listEl) return;
|
|
388
|
-
|
|
389
|
-
var models = ctx.currentModels || [];
|
|
390
|
-
var currentModel = ctx.currentModel || ctx._currentModelValue || "";
|
|
391
|
-
|
|
392
|
-
listEl.innerHTML = "";
|
|
393
|
-
if (models.length === 0) {
|
|
394
|
-
listEl.innerHTML = '<div style="font-size:13px;color:var(--text-dimmer);">No models available</div>';
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
for (var i = 0; i < models.length; i++) {
|
|
399
|
-
(function (m) {
|
|
400
|
-
var value = m.value || "";
|
|
401
|
-
var label = m.displayName || value;
|
|
402
|
-
var item = document.createElement("div");
|
|
403
|
-
item.className = "settings-model-item";
|
|
404
|
-
if (value === currentModel) item.classList.add("active");
|
|
405
|
-
item.dataset.model = value;
|
|
406
|
-
|
|
407
|
-
var nameSpan = document.createElement("span");
|
|
408
|
-
nameSpan.className = "settings-model-name";
|
|
409
|
-
nameSpan.textContent = label;
|
|
410
|
-
item.appendChild(nameSpan);
|
|
411
|
-
|
|
412
|
-
var desc = ssGetModelDesc(value);
|
|
413
|
-
if (desc) {
|
|
414
|
-
var descSpan = document.createElement("span");
|
|
415
|
-
descSpan.className = "settings-model-desc";
|
|
416
|
-
descSpan.textContent = desc;
|
|
417
|
-
item.appendChild(descSpan);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
item.addEventListener("click", function () {
|
|
421
|
-
var ws = ctx.ws;
|
|
422
|
-
if (ws && ws.readyState === 1) {
|
|
423
|
-
ws.send(JSON.stringify({ type: "set_model", model: value }));
|
|
424
|
-
}
|
|
425
|
-
var items = listEl.querySelectorAll(".settings-model-item");
|
|
426
|
-
for (var j = 0; j < items.length; j++) items[j].classList.remove("active");
|
|
427
|
-
item.classList.add("active");
|
|
428
|
-
updateSsBetaCard(value);
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
listEl.appendChild(item);
|
|
432
|
-
})(models[i]);
|
|
433
|
-
}
|
|
376
|
+
renderModelList("ss", ssDefaultsOpts());
|
|
434
377
|
}
|
|
435
378
|
|
|
436
379
|
function updateModeList() {
|
|
437
|
-
|
|
438
|
-
if (!listEl) return;
|
|
439
|
-
|
|
440
|
-
var currentMode = ctx.currentMode || "default";
|
|
441
|
-
listEl.innerHTML = "";
|
|
442
|
-
|
|
443
|
-
for (var i = 0; i < SS_MODE_OPTIONS.length; i++) {
|
|
444
|
-
(function (opt) {
|
|
445
|
-
var item = document.createElement("div");
|
|
446
|
-
item.className = "settings-model-item" + (opt.value === currentMode ? " active" : "");
|
|
447
|
-
|
|
448
|
-
var nameSpan = document.createElement("span");
|
|
449
|
-
nameSpan.className = "settings-model-name";
|
|
450
|
-
nameSpan.textContent = opt.label;
|
|
451
|
-
item.appendChild(nameSpan);
|
|
452
|
-
|
|
453
|
-
var descSpan = document.createElement("span");
|
|
454
|
-
descSpan.className = "settings-model-desc";
|
|
455
|
-
descSpan.textContent = opt.desc;
|
|
456
|
-
item.appendChild(descSpan);
|
|
457
|
-
|
|
458
|
-
item.addEventListener("click", function () {
|
|
459
|
-
var ws = ctx.ws;
|
|
460
|
-
if (ws && ws.readyState === 1) {
|
|
461
|
-
ws.send(JSON.stringify({ type: "set_server_default_mode", mode: opt.value }));
|
|
462
|
-
}
|
|
463
|
-
var items = listEl.querySelectorAll(".settings-model-item");
|
|
464
|
-
for (var j = 0; j < items.length; j++) items[j].classList.remove("active");
|
|
465
|
-
item.classList.add("active");
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
listEl.appendChild(item);
|
|
469
|
-
})(SS_MODE_OPTIONS[i]);
|
|
470
|
-
}
|
|
380
|
+
renderModeList("ss", ssDefaultsOpts());
|
|
471
381
|
}
|
|
472
382
|
|
|
473
383
|
function updateEffortBar() {
|
|
474
|
-
|
|
475
|
-
if (!bar) return;
|
|
476
|
-
|
|
477
|
-
var currentEffort = ctx.currentEffort || "medium";
|
|
478
|
-
bar.innerHTML = "";
|
|
479
|
-
|
|
480
|
-
for (var i = 0; i < SS_EFFORT_LEVELS.length; i++) {
|
|
481
|
-
(function (lvl) {
|
|
482
|
-
var btn = document.createElement("button");
|
|
483
|
-
btn.className = "settings-btn-option" + (lvl.value === currentEffort ? " active" : "");
|
|
484
|
-
btn.textContent = lvl.value.charAt(0).toUpperCase() + lvl.value.slice(1);
|
|
485
|
-
btn.title = lvl.desc;
|
|
486
|
-
btn.addEventListener("click", function () {
|
|
487
|
-
var ws = ctx.ws;
|
|
488
|
-
if (ws && ws.readyState === 1) {
|
|
489
|
-
ws.send(JSON.stringify({ type: "set_server_default_effort", effort: lvl.value }));
|
|
490
|
-
}
|
|
491
|
-
var btns = bar.querySelectorAll(".settings-btn-option");
|
|
492
|
-
for (var j = 0; j < btns.length; j++) btns[j].classList.remove("active");
|
|
493
|
-
btn.classList.add("active");
|
|
494
|
-
});
|
|
495
|
-
bar.appendChild(btn);
|
|
496
|
-
})(SS_EFFORT_LEVELS[i]);
|
|
497
|
-
}
|
|
384
|
+
renderEffortBar("ss", ssDefaultsOpts());
|
|
498
385
|
}
|
|
499
386
|
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
var card = document.getElementById("ss-beta-card");
|
|
503
|
-
if (card) {
|
|
504
|
-
card.style.display = ssIsSonnetModel(model) ? "" : "none";
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
var toggle = document.getElementById("ss-beta-1m");
|
|
508
|
-
if (toggle) {
|
|
509
|
-
var betas = ctx.currentBetas || [];
|
|
510
|
-
var hasBeta = false;
|
|
511
|
-
for (var i = 0; i < betas.length; i++) {
|
|
512
|
-
if (betas[i].indexOf("context-1m") !== -1) { hasBeta = true; break; }
|
|
513
|
-
}
|
|
514
|
-
toggle.checked = hasBeta;
|
|
515
|
-
toggle.onchange = function () {
|
|
516
|
-
ssToggleBeta1m(this.checked);
|
|
517
|
-
};
|
|
518
|
-
}
|
|
387
|
+
function updateThinkingBar() {
|
|
388
|
+
renderThinkingBar("ss", ssDefaultsOpts());
|
|
519
389
|
}
|
|
520
390
|
|
|
521
|
-
function
|
|
522
|
-
|
|
523
|
-
var newBetas;
|
|
524
|
-
if (enable) {
|
|
525
|
-
newBetas = betas.slice();
|
|
526
|
-
newBetas.push("context-1m-2025-08-07");
|
|
527
|
-
} else {
|
|
528
|
-
newBetas = [];
|
|
529
|
-
for (var i = 0; i < betas.length; i++) {
|
|
530
|
-
if (betas[i].indexOf("context-1m") === -1) {
|
|
531
|
-
newBetas.push(betas[i]);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
var ws = ctx.ws;
|
|
536
|
-
if (ws && ws.readyState === 1) {
|
|
537
|
-
ws.send(JSON.stringify({ type: "set_betas", betas: newBetas }));
|
|
538
|
-
}
|
|
391
|
+
function updateSsBetaCard(overrideModel) {
|
|
392
|
+
renderBetaCard("ss", Object.assign(ssDefaultsOpts(), { overrideModel: overrideModel }));
|
|
539
393
|
}
|
|
540
394
|
|
|
541
395
|
export function updateSettingsStats(data) {
|
|
@@ -561,6 +415,7 @@ export function updateSettingsModels(current, models) {
|
|
|
561
415
|
updateModelList();
|
|
562
416
|
updateModeList();
|
|
563
417
|
updateEffortBar();
|
|
418
|
+
updateThinkingBar();
|
|
564
419
|
updateSsBetaCard();
|
|
565
420
|
}
|
|
566
421
|
}
|
|
@@ -574,6 +429,20 @@ function requestDaemonConfig() {
|
|
|
574
429
|
}
|
|
575
430
|
|
|
576
431
|
export function updateDaemonConfig(config) {
|
|
432
|
+
// Nav header: show hostname (strip .local suffix, lowercase)
|
|
433
|
+
var nameEl = document.getElementById("settings-server-name");
|
|
434
|
+
if (nameEl && config.hostname) {
|
|
435
|
+
var displayHost = config.hostname.replace(/\.local$/i, "").toLowerCase();
|
|
436
|
+
nameEl.textContent = displayHost;
|
|
437
|
+
nameEl.title = config.hostname;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Host
|
|
441
|
+
var hostnameEl = document.getElementById("settings-hostname");
|
|
442
|
+
var lanIpEl = document.getElementById("settings-lan-ip");
|
|
443
|
+
if (hostnameEl) hostnameEl.textContent = config.hostname || "-";
|
|
444
|
+
if (lanIpEl) lanIpEl.textContent = config.lanIp || "";
|
|
445
|
+
|
|
577
446
|
// Port
|
|
578
447
|
var portEl = document.getElementById("settings-port");
|
|
579
448
|
if (portEl) portEl.textContent = String(config.port || "-");
|
|
@@ -599,14 +468,34 @@ export function updateDaemonConfig(config) {
|
|
|
599
468
|
var keepAwakeToggle = document.getElementById("settings-keep-awake");
|
|
600
469
|
if (keepAwakeToggle) keepAwakeToggle.checked = !!config.keepAwake;
|
|
601
470
|
|
|
602
|
-
//
|
|
603
|
-
var
|
|
604
|
-
if (
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
471
|
+
// Early Access toggle
|
|
472
|
+
var channelToggle = document.getElementById("settings-update-channel");
|
|
473
|
+
if (channelToggle) {
|
|
474
|
+
channelToggle.checked = (config.updateChannel === "beta");
|
|
475
|
+
channelToggle.onchange = function () {
|
|
476
|
+
var channel = channelToggle.checked ? "beta" : "stable";
|
|
477
|
+
if (ctx.ws && ctx.ws.readyState === 1) {
|
|
478
|
+
ctx.ws.send(JSON.stringify({ type: "set_update_channel", channel: channel }));
|
|
479
|
+
// Auto-trigger update check after channel change
|
|
480
|
+
setTimeout(function () {
|
|
481
|
+
ctx.ws.send(JSON.stringify({ type: "check_update" }));
|
|
482
|
+
}, 200);
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Show keep awake section/nav only on macOS
|
|
488
|
+
var keepAwakeSection = document.getElementById("settings-keep-awake-section");
|
|
489
|
+
var keepAwakeNav = document.getElementById("settings-keep-awake-nav");
|
|
490
|
+
var keepAwakeOpt = document.getElementById("settings-keep-awake-opt");
|
|
491
|
+
if (config.platform === "darwin") {
|
|
492
|
+
if (keepAwakeSection) keepAwakeSection.classList.remove("hidden");
|
|
493
|
+
if (keepAwakeNav) keepAwakeNav.classList.remove("hidden");
|
|
494
|
+
if (keepAwakeOpt) keepAwakeOpt.classList.remove("hidden");
|
|
495
|
+
} else {
|
|
496
|
+
if (keepAwakeSection) keepAwakeSection.classList.add("hidden");
|
|
497
|
+
if (keepAwakeNav) keepAwakeNav.classList.add("hidden");
|
|
498
|
+
if (keepAwakeOpt) keepAwakeOpt.classList.add("hidden");
|
|
610
499
|
}
|
|
611
500
|
}
|
|
612
501
|
|
|
@@ -632,7 +521,7 @@ export function handleRestartResult(msg) {
|
|
|
632
521
|
showToast("Server is restarting...");
|
|
633
522
|
} else {
|
|
634
523
|
if (restartBtn) {
|
|
635
|
-
restartBtn.textContent = "Restart
|
|
524
|
+
restartBtn.textContent = "Restart";
|
|
636
525
|
restartBtn.disabled = false;
|
|
637
526
|
}
|
|
638
527
|
if (errorEl) {
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// settings-defaults.js — Shared rendering for model/mode/effort/thinking controls
|
|
2
|
+
// Used by both server-settings.js and project-settings.js
|
|
3
|
+
|
|
4
|
+
export var MODE_OPTIONS = [
|
|
5
|
+
{ value: "default", label: "Default", desc: "Claude asks for permission before running tools and editing files." },
|
|
6
|
+
{ value: "plan", label: "Plan", desc: "Claude creates a plan first and asks for approval before making changes." },
|
|
7
|
+
{ value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically. Claude still asks before running commands." },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
export var EFFORT_LEVELS = [
|
|
11
|
+
{ value: "low", desc: "Quick, concise responses. Best for simple questions." },
|
|
12
|
+
{ value: "medium", desc: "Balanced responses with moderate reasoning. Good for most tasks." },
|
|
13
|
+
{ value: "high", desc: "Thorough responses with deeper analysis. Good for complex tasks." },
|
|
14
|
+
{ value: "max", desc: "Maximum reasoning depth. Best for the most difficult problems." },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export var THINKING_OPTIONS = [
|
|
18
|
+
{ value: "disabled", label: "Off", desc: "Disable extended thinking." },
|
|
19
|
+
{ value: "adaptive", label: "Adaptive", desc: "Claude decides when to use extended thinking." },
|
|
20
|
+
{ value: "budget", label: "Budget", desc: "Set a token budget for extended thinking." },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export var MODEL_DESCRIPTIONS = {
|
|
24
|
+
"default": "Automatically selects the best model for the task.",
|
|
25
|
+
"sonnet": "Fast and capable. Great balance of speed and intelligence.",
|
|
26
|
+
"haiku": "Fastest model. Best for quick tasks and simple questions.",
|
|
27
|
+
"opus": "Most powerful model. Best for complex reasoning and analysis.",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function getModelDesc(model) {
|
|
31
|
+
if (!model) return "";
|
|
32
|
+
var lower = (model.value || model).toLowerCase();
|
|
33
|
+
for (var key in MODEL_DESCRIPTIONS) {
|
|
34
|
+
if (lower.indexOf(key) !== -1) return MODEL_DESCRIPTIONS[key];
|
|
35
|
+
}
|
|
36
|
+
return "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isSonnetModel(model) {
|
|
40
|
+
if (!model) return false;
|
|
41
|
+
return model.toLowerCase().indexOf("sonnet") !== -1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// --- Render functions ---
|
|
45
|
+
// Each takes an element ID prefix (e.g. "ss" or "ps"), a send function, and state getters.
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Render model list into `${prefix}-model-list`
|
|
49
|
+
* @param {string} prefix - Element ID prefix
|
|
50
|
+
* @param {object} opts - { models, currentModel, sendMsg, onModelSelect }
|
|
51
|
+
*/
|
|
52
|
+
export function renderModelList(prefix, opts) {
|
|
53
|
+
var listEl = document.getElementById(prefix + "-model-list");
|
|
54
|
+
if (!listEl) return;
|
|
55
|
+
|
|
56
|
+
var models = opts.models || [];
|
|
57
|
+
var currentModel = opts.currentModel || "";
|
|
58
|
+
|
|
59
|
+
listEl.innerHTML = "";
|
|
60
|
+
if (models.length === 0) {
|
|
61
|
+
listEl.innerHTML = '<div style="font-size:13px;color:var(--text-dimmer);">No models available</div>';
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (var i = 0; i < models.length; i++) {
|
|
66
|
+
(function (m) {
|
|
67
|
+
var value = m.value || "";
|
|
68
|
+
var label = m.displayName || value;
|
|
69
|
+
var item = document.createElement("div");
|
|
70
|
+
item.className = "settings-model-item" + (value === currentModel ? " active" : "");
|
|
71
|
+
item.dataset.model = value;
|
|
72
|
+
|
|
73
|
+
var nameSpan = document.createElement("span");
|
|
74
|
+
nameSpan.className = "settings-model-name";
|
|
75
|
+
nameSpan.textContent = label;
|
|
76
|
+
item.appendChild(nameSpan);
|
|
77
|
+
|
|
78
|
+
var desc = getModelDesc(value);
|
|
79
|
+
if (desc) {
|
|
80
|
+
var descSpan = document.createElement("span");
|
|
81
|
+
descSpan.className = "settings-model-desc";
|
|
82
|
+
descSpan.textContent = desc;
|
|
83
|
+
item.appendChild(descSpan);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
item.addEventListener("click", function () {
|
|
87
|
+
opts.sendMsg(opts.modelMsgType, { model: value });
|
|
88
|
+
var items = listEl.querySelectorAll(".settings-model-item");
|
|
89
|
+
for (var j = 0; j < items.length; j++) items[j].classList.remove("active");
|
|
90
|
+
item.classList.add("active");
|
|
91
|
+
if (opts.onModelSelect) opts.onModelSelect(value);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
listEl.appendChild(item);
|
|
95
|
+
})(models[i]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Render mode list into `${prefix}-mode-list`
|
|
101
|
+
*/
|
|
102
|
+
export function renderModeList(prefix, opts) {
|
|
103
|
+
var listEl = document.getElementById(prefix + "-mode-list");
|
|
104
|
+
if (!listEl) return;
|
|
105
|
+
|
|
106
|
+
var currentMode = opts.currentMode || "default";
|
|
107
|
+
listEl.innerHTML = "";
|
|
108
|
+
|
|
109
|
+
for (var i = 0; i < MODE_OPTIONS.length; i++) {
|
|
110
|
+
(function (opt) {
|
|
111
|
+
var item = document.createElement("div");
|
|
112
|
+
item.className = "settings-model-item" + (opt.value === currentMode ? " active" : "");
|
|
113
|
+
|
|
114
|
+
var nameSpan = document.createElement("span");
|
|
115
|
+
nameSpan.className = "settings-model-name";
|
|
116
|
+
nameSpan.textContent = opt.label;
|
|
117
|
+
item.appendChild(nameSpan);
|
|
118
|
+
|
|
119
|
+
var descSpan = document.createElement("span");
|
|
120
|
+
descSpan.className = "settings-model-desc";
|
|
121
|
+
descSpan.textContent = opt.desc;
|
|
122
|
+
item.appendChild(descSpan);
|
|
123
|
+
|
|
124
|
+
item.addEventListener("click", function () {
|
|
125
|
+
opts.sendMsg(opts.modeMsgType, { mode: opt.value });
|
|
126
|
+
var items = listEl.querySelectorAll(".settings-model-item");
|
|
127
|
+
for (var j = 0; j < items.length; j++) items[j].classList.remove("active");
|
|
128
|
+
item.classList.add("active");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
listEl.appendChild(item);
|
|
132
|
+
})(MODE_OPTIONS[i]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Render effort bar into `${prefix}-effort-bar`
|
|
138
|
+
*/
|
|
139
|
+
export function renderEffortBar(prefix, opts) {
|
|
140
|
+
var bar = document.getElementById(prefix + "-effort-bar");
|
|
141
|
+
if (!bar) return;
|
|
142
|
+
|
|
143
|
+
var currentEffort = opts.currentEffort || "medium";
|
|
144
|
+
bar.innerHTML = "";
|
|
145
|
+
|
|
146
|
+
for (var i = 0; i < EFFORT_LEVELS.length; i++) {
|
|
147
|
+
(function (lvl) {
|
|
148
|
+
var btn = document.createElement("button");
|
|
149
|
+
btn.className = "settings-btn-option" + (lvl.value === currentEffort ? " active" : "");
|
|
150
|
+
btn.textContent = lvl.value.charAt(0).toUpperCase() + lvl.value.slice(1);
|
|
151
|
+
btn.title = lvl.desc;
|
|
152
|
+
btn.addEventListener("click", function () {
|
|
153
|
+
opts.sendMsg(opts.effortMsgType, { effort: lvl.value });
|
|
154
|
+
var btns = bar.querySelectorAll(".settings-btn-option");
|
|
155
|
+
for (var j = 0; j < btns.length; j++) btns[j].classList.remove("active");
|
|
156
|
+
btn.classList.add("active");
|
|
157
|
+
});
|
|
158
|
+
bar.appendChild(btn);
|
|
159
|
+
})(EFFORT_LEVELS[i]);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Render thinking bar into `${prefix}-thinking-bar`
|
|
165
|
+
*/
|
|
166
|
+
export function renderThinkingBar(prefix, opts) {
|
|
167
|
+
var bar = document.getElementById(prefix + "-thinking-bar");
|
|
168
|
+
if (!bar) return;
|
|
169
|
+
|
|
170
|
+
var currentThinking = opts.currentThinking || "adaptive";
|
|
171
|
+
var currentBudget = opts.currentThinkingBudget || 10000;
|
|
172
|
+
var budgetRow = document.getElementById(prefix + "-thinking-budget-row");
|
|
173
|
+
var budgetInput = document.getElementById(prefix + "-thinking-budget");
|
|
174
|
+
bar.innerHTML = "";
|
|
175
|
+
|
|
176
|
+
for (var i = 0; i < THINKING_OPTIONS.length; i++) {
|
|
177
|
+
(function (opt) {
|
|
178
|
+
var btn = document.createElement("button");
|
|
179
|
+
btn.className = "settings-btn-option" + (opt.value === currentThinking ? " active" : "");
|
|
180
|
+
btn.textContent = opt.label;
|
|
181
|
+
btn.title = opt.desc;
|
|
182
|
+
btn.addEventListener("click", function () {
|
|
183
|
+
var msg = { thinking: opt.value };
|
|
184
|
+
if (opt.value === "budget") {
|
|
185
|
+
msg.budgetTokens = budgetInput ? parseInt(budgetInput.value, 10) || 10000 : 10000;
|
|
186
|
+
}
|
|
187
|
+
opts.sendMsg("set_thinking", msg);
|
|
188
|
+
var btns = bar.querySelectorAll(".settings-btn-option");
|
|
189
|
+
for (var j = 0; j < btns.length; j++) btns[j].classList.remove("active");
|
|
190
|
+
btn.classList.add("active");
|
|
191
|
+
if (budgetRow) budgetRow.style.display = opt.value === "budget" ? "" : "none";
|
|
192
|
+
});
|
|
193
|
+
bar.appendChild(btn);
|
|
194
|
+
})(THINKING_OPTIONS[i]);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (budgetRow) budgetRow.style.display = currentThinking === "budget" ? "" : "none";
|
|
198
|
+
if (budgetInput) {
|
|
199
|
+
budgetInput.value = currentBudget;
|
|
200
|
+
budgetInput.addEventListener("change", function () {
|
|
201
|
+
var val = Math.max(1024, Math.min(128000, parseInt(this.value, 10) || 10000));
|
|
202
|
+
this.value = val;
|
|
203
|
+
opts.sendMsg("set_thinking", { thinking: "budget", budgetTokens: val });
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Update beta card visibility and bind toggle
|
|
210
|
+
*/
|
|
211
|
+
export function renderBetaCard(prefix, opts) {
|
|
212
|
+
var model = opts.overrideModel || opts.currentModel || "";
|
|
213
|
+
var card = document.getElementById(prefix + "-beta-card");
|
|
214
|
+
if (card) {
|
|
215
|
+
card.style.display = isSonnetModel(model) ? "" : "none";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
var toggle = document.getElementById(prefix + "-beta-1m");
|
|
219
|
+
if (toggle) {
|
|
220
|
+
var betas = opts.currentBetas || [];
|
|
221
|
+
var hasBeta = false;
|
|
222
|
+
for (var i = 0; i < betas.length; i++) {
|
|
223
|
+
if (betas[i].indexOf("context-1m") !== -1) { hasBeta = true; break; }
|
|
224
|
+
}
|
|
225
|
+
toggle.checked = hasBeta;
|
|
226
|
+
toggle.onchange = function () {
|
|
227
|
+
var currentBetas = opts.currentBetas || [];
|
|
228
|
+
var newBetas;
|
|
229
|
+
if (this.checked) {
|
|
230
|
+
newBetas = currentBetas.slice();
|
|
231
|
+
newBetas.push("context-1m-2025-08-07");
|
|
232
|
+
} else {
|
|
233
|
+
newBetas = [];
|
|
234
|
+
for (var j = 0; j < currentBetas.length; j++) {
|
|
235
|
+
if (currentBetas[j].indexOf("context-1m") === -1) {
|
|
236
|
+
newBetas.push(currentBetas[j]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
opts.sendMsg("set_betas", { betas: newBetas });
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|