@danieltmn/tamnora 0.25.0 → 0.26.0
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/CHANGELOG.md +18 -0
- package/README.md +13 -25
- package/SECURITY.md +3 -4
- package/harness/packages/cli/src/cli.js +0 -3
- package/harness/packages/cli/src/commands/bridge.js +0 -1
- package/harness/packages/cli/src/commands/repl.js +20 -4
- package/harness/packages/cli/src/commands/run.js +6 -2
- package/harness/packages/cli/src/commands/server.js +1 -1
- package/harness/packages/cli/src/commands/tui.js +6 -2
- package/harness/packages/cli/src/lib/runtime.js +2 -0
- package/harness/packages/cli/src/lib/util.js +2 -2
- package/harness/packages/cli/src/tui/app.js +24 -4
- package/harness/packages/cli/src/tui/layout.js +1 -1
- package/harness/packages/cli/test/tunnel.test.js +5 -32
- package/harness/packages/core/src/agent/runAgent.js +5 -2
- package/harness/packages/core/src/agents/index.js +113 -0
- package/harness/packages/core/src/config/app.js +0 -4
- package/harness/packages/core/src/config/home.js +1 -20
- package/harness/packages/core/src/config/index.js +6 -8
- package/harness/packages/core/src/extensions/load.js +22 -0
- package/harness/packages/core/src/frontmatter.js +32 -0
- package/harness/packages/core/src/hooks/index.js +2 -16
- package/harness/packages/core/src/index.js +12 -14
- package/harness/packages/core/src/plugins/index.js +2 -16
- package/harness/packages/core/src/procs/project.js +68 -0
- package/harness/packages/core/src/procs/static.js +17 -0
- package/harness/packages/core/src/providers/index.js +3 -1
- package/harness/packages/core/src/providers/ollama.js +4 -1
- package/harness/packages/core/src/providers/openaiCompatible.js +6 -1
- package/harness/packages/core/src/providers/openrouter.js +5 -1
- package/harness/packages/core/src/providers/presets.js +4 -3
- package/harness/packages/core/src/providers/reasoning.js +58 -0
- package/harness/packages/core/src/rules/index.js +8 -27
- package/harness/packages/core/src/skills/index.js +8 -19
- package/harness/packages/core/src/storage/sqlite.js +595 -690
- package/harness/packages/core/src/tunnel.js +9 -147
- package/harness/packages/core/test/agents.test.js +111 -0
- package/harness/packages/core/test/home.test.js +2 -35
- package/harness/packages/core/test/procs.test.js +3 -64
- package/harness/packages/core/test/reasoning.test.js +43 -0
- package/harness/packages/core/test/storage.test.js +1 -12
- package/harness/packages/server/public/app.js +39 -19
- package/harness/packages/server/public/appearance.js +2 -56
- package/harness/packages/server/public/boot.js +2 -2
- package/harness/packages/server/public/cards.js +2 -21
- package/harness/packages/server/public/chat.js +1 -16
- package/harness/packages/server/public/chatFormat.js +0 -11
- package/harness/packages/server/public/chrome.js +95 -5
- package/harness/packages/server/public/commands.js +1 -2
- package/harness/packages/server/public/core.js +1 -1
- package/harness/packages/server/public/explorer.js +7 -10
- package/harness/packages/server/public/icons (1).zip +0 -0
- package/harness/packages/server/public/index.html +1228 -1237
- package/harness/packages/server/public/landing/boot.js +2 -3
- package/harness/packages/server/public/landing/index.html +3 -367
- package/harness/packages/server/public/sessions.js +1 -0
- package/harness/packages/server/public/settings.js +1255 -1155
- package/harness/packages/server/public/settingsNav.js +1 -1
- package/harness/packages/server/public/styles.css +2341 -2867
- package/harness/packages/server/public/system.js +356 -495
- package/harness/packages/server/public/voice.js +6 -22
- package/harness/packages/server/src/auth.js +4 -15
- package/harness/packages/server/src/cli.js +1 -1
- package/harness/packages/server/src/lib/agents.js +60 -0
- package/harness/packages/server/src/lib/appearance.js +3 -22
- package/harness/packages/server/src/lib/channels/telegram/commands.js +1 -1
- package/harness/packages/server/src/lib/channels/telegram/run.js +1 -0
- package/harness/packages/server/src/lib/definitions.js +40 -0
- package/harness/packages/server/src/lib/prompt.js +11 -3
- package/harness/packages/server/src/lib/scheduler.js +4 -0
- package/harness/packages/server/src/lib/sessionView.js +1 -0
- package/harness/packages/server/src/lib/skills.js +27 -21
- package/harness/packages/server/src/lib/tasks.js +71 -23
- package/harness/packages/server/src/lib/ttsSettings.js +2 -2
- package/harness/packages/server/src/lib/workspace.js +9 -11
- package/harness/packages/server/src/routes/agents.js +88 -0
- package/harness/packages/server/src/routes/chat.js +9 -44
- package/harness/packages/server/src/routes/preview.js +5 -22
- package/harness/packages/server/src/routes/procs.js +2 -4
- package/harness/packages/server/src/routes/providers.js +7 -0
- package/harness/packages/server/src/routes/sessions.js +3 -1
- package/harness/packages/server/src/routes/tts.js +1 -1
- package/harness/packages/server/src/server.js +8 -5
- package/harness/packages/server/test/agents.test.js +194 -0
- package/harness/packages/server/test/appearance-route.test.js +3 -3
- package/harness/packages/server/test/appearance.test.js +12 -38
- package/harness/packages/server/test/chatFormat.test.js +0 -8
- package/harness/packages/server/test/consoleTabs.test.js +2 -2
- package/harness/packages/server/test/ops.test.js +8 -56
- package/harness/packages/server/test/preview.test.js +2 -42
- package/harness/packages/server/test/security.test.js +194 -370
- package/harness/packages/server/test/settingsNav.test.js +2 -2
- package/harness/packages/server/test/tts.test.js +4 -4
- package/harness/tamnora.example.json +2 -1
- package/package.json +2 -2
- package/harness/packages/cli/src/commands/eval.js +0 -186
- package/harness/packages/core/src/eval/dataset.js +0 -47
- package/harness/packages/core/src/eval/judge.js +0 -39
- package/harness/packages/core/src/eval/report.js +0 -48
- package/harness/packages/core/src/eval/runTask.js +0 -62
- package/harness/packages/core/src/eval/runner.js +0 -153
- package/harness/packages/core/src/eval/scorers.js +0 -217
- package/harness/packages/core/src/eval/task.js +0 -59
- package/harness/packages/core/src/procs/detect.js +0 -149
- package/harness/packages/core/test/eval.test.js +0 -144
- package/harness/packages/server/src/lib/advisor.js +0 -198
- package/harness/packages/server/src/routes/advisor.js +0 -79
- package/harness/packages/server/src/routes/eval.js +0 -100
- package/harness/packages/server/test/advisor.test.js +0 -249
- package/harness/scripts/example-dataset.jsonl +0 -4
|
@@ -4,22 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
export const THEMES = [
|
|
6
6
|
{ id: 'paper', label: 'Papel', scheme: 'light', metaColor: '#f5efe2' },
|
|
7
|
-
{ id: 'dark', label: 'Oscuro', scheme: 'dark', metaColor: '#101107' },
|
|
8
|
-
{ id: 'midnight', label: 'Medianoche', scheme: 'dark', metaColor: '#0b1220' },
|
|
9
|
-
{ id: 'nord', label: 'Nord', scheme: 'dark', metaColor: '#2e3440' },
|
|
10
|
-
{ id: 'dracula', label: 'Dracula', scheme: 'dark', metaColor: '#282a36' },
|
|
11
|
-
{ id: 'solarized', label: 'Solarized', scheme: 'light', metaColor: '#fdf6e3' },
|
|
12
|
-
{ id: 'solarized-dark', label: 'Solarized oscuro', scheme: 'dark', metaColor: '#002b36' },
|
|
13
|
-
{ id: 'bosque', label: 'Bosque', scheme: 'light', metaColor: '#f2f4ec' },
|
|
14
|
-
{ id: 'vino', label: 'Vino', scheme: 'light', metaColor: '#f7eeee' },
|
|
15
|
-
{ id: 'arena', label: 'Arena', scheme: 'light', metaColor: '#f6efdd' },
|
|
16
|
-
{ id: 'hielo', label: 'Hielo', scheme: 'light', metaColor: '#edf3f7' },
|
|
17
|
-
{ id: 'vercel', label: 'Vercel', scheme: 'dark', metaColor: '#000000' },
|
|
18
|
-
{ id: 'dark-plus', label: 'Dark+', scheme: 'dark', metaColor: '#1e1e1e' },
|
|
19
7
|
{ id: 'github', label: 'GitHub', scheme: 'light', metaColor: '#ffffff' },
|
|
20
|
-
{ id: '
|
|
8
|
+
{ id: 'dark', label: 'Oscuro', scheme: 'dark', metaColor: '#101107' },
|
|
21
9
|
{ id: 'mocha', label: 'Mocha', scheme: 'dark', metaColor: '#211912' },
|
|
22
|
-
{ id: 'ebano', label: 'Ébano', scheme: 'dark', metaColor: '#14191f' },
|
|
23
10
|
];
|
|
24
11
|
|
|
25
12
|
export const FONT_PRESETS = [
|
|
@@ -39,46 +26,6 @@ export const FONT_PRESETS = [
|
|
|
39
26
|
mono: 'ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace',
|
|
40
27
|
google: null,
|
|
41
28
|
},
|
|
42
|
-
{
|
|
43
|
-
id: 'plex',
|
|
44
|
-
label: 'IBM Plex · Sans / Serif / Mono',
|
|
45
|
-
sans: '"IBM Plex Sans", system-ui, "Segoe UI", Arial, sans-serif',
|
|
46
|
-
serif: '"IBM Plex Serif", Georgia, "Times New Roman", serif',
|
|
47
|
-
mono: '"IBM Plex Mono", ui-monospace, Consolas, monospace',
|
|
48
|
-
google: 'family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Serif:wght@400;600',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: 'inter',
|
|
52
|
-
label: 'Inter · Inter / Newsreader / JetBrains Mono',
|
|
53
|
-
sans: 'Inter, system-ui, "Segoe UI", Arial, sans-serif',
|
|
54
|
-
serif: 'Newsreader, Georgia, "Times New Roman", serif',
|
|
55
|
-
mono: '"JetBrains Mono", ui-monospace, Consolas, monospace',
|
|
56
|
-
google: 'family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Newsreader:wght@400;600',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: 'jetbrains',
|
|
60
|
-
label: 'JetBrains Mono · código',
|
|
61
|
-
sans: '"JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
62
|
-
serif: 'Georgia, "Times New Roman", serif',
|
|
63
|
-
mono: '"JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
64
|
-
google: 'family=JetBrains+Mono:wght@400;500;700',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: 'fira',
|
|
68
|
-
label: 'Fira Code · código',
|
|
69
|
-
sans: '"Fira Code", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
70
|
-
serif: 'Georgia, "Times New Roman", serif',
|
|
71
|
-
mono: '"Fira Code", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
72
|
-
google: 'family=Fira+Code:wght@400;500;600;700',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: 'source',
|
|
76
|
-
label: 'Source Code Pro · código',
|
|
77
|
-
sans: '"Source Code Pro", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
78
|
-
serif: 'Georgia, "Times New Roman", serif',
|
|
79
|
-
mono: '"Source Code Pro", ui-monospace, "Cascadia Code", Consolas, monospace',
|
|
80
|
-
google: 'family=Source+Code+Pro:wght@400;500;600;700',
|
|
81
|
-
},
|
|
82
29
|
];
|
|
83
30
|
|
|
84
31
|
export const DEFAULTS = { theme: 'paper', font: 'clasico', chatFont: 14.5, scale: 1 };
|
|
@@ -116,8 +63,7 @@ export function fontIds() {
|
|
|
116
63
|
}
|
|
117
64
|
|
|
118
65
|
export function resolveTheme(id) {
|
|
119
|
-
|
|
120
|
-
return THEMES.some((t) => t.id === legacy) ? legacy : DEFAULTS.theme;
|
|
66
|
+
return THEMES.some((t) => t.id === id) ? id : DEFAULTS.theme;
|
|
121
67
|
}
|
|
122
68
|
|
|
123
69
|
export function resolveFont(id) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
var root = document.documentElement;
|
|
3
|
-
var THEMES = ['paper', '
|
|
4
|
-
var DARK = ['dark', '
|
|
3
|
+
var THEMES = ['paper', 'github', 'dark', 'mocha'];
|
|
4
|
+
var DARK = ['dark', 'mocha'];
|
|
5
5
|
var appearance = null;
|
|
6
6
|
try {
|
|
7
7
|
appearance = JSON.parse(localStorage.getItem('tamnora-console-appearance') || 'null');
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Tarjetas de la consola: las que dibujan una herramienta, un permiso, una
|
|
2
|
-
// pregunta
|
|
2
|
+
// pregunta o un plan.
|
|
3
3
|
|
|
4
4
|
import { api, button, el, icon, state } from './core.js';
|
|
5
5
|
import { toast } from './commands.js';
|
|
6
6
|
import { addMessage, chatInput, paneOf, scrollMessages, sendMessage } from './chat.js';
|
|
7
|
-
import {
|
|
7
|
+
import { isFailedToolText, isReadOnlyTool, screenshotName, toolSummary } from './chatFormat.js';
|
|
8
8
|
import { renderMarkdown } from './markdown.js';
|
|
9
9
|
import { summarizeArgs } from './reconcile.js';
|
|
10
10
|
import { yesInput } from './chrome.js';
|
|
@@ -409,25 +409,6 @@ export function addPlanCard(container, { title, steps } = {}) {
|
|
|
409
409
|
return card;
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
export function addAdvisorCard(container, { text, kind } = {}) {
|
|
413
|
-
const clean = String(text ?? '').trim();
|
|
414
|
-
if (!clean || !container) return null;
|
|
415
|
-
const exists = [...container.querySelectorAll('.advisor-text')].some((node) => node.textContent === clean);
|
|
416
|
-
if (exists) return null;
|
|
417
|
-
const meta = advisorMeta(kind);
|
|
418
|
-
const klass = ADVISOR_KINDS[kind] ? ` advisor-${kind}` : '';
|
|
419
|
-
const card = el('div', `advisor-card${klass}`);
|
|
420
|
-
const head = el('div', 'advisor-head');
|
|
421
|
-
head.append(
|
|
422
|
-
el('span', 'advisor-glyph', meta.glyph),
|
|
423
|
-
el('span', 'advisor-title', 'asesor'),
|
|
424
|
-
el('span', `advisor-badge advisor-badge-${kind || 'advice'}`, meta.label)
|
|
425
|
-
);
|
|
426
|
-
card.append(head, el('div', 'advisor-text', clean));
|
|
427
|
-
container.appendChild(card);
|
|
428
|
-
return card;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
412
|
/**
|
|
432
413
|
* Marca del punto de compactación: una línea que corta el historial y, debajo,
|
|
433
414
|
* el resumen que pasa a ser el contexto del modelo. Lo de arriba sigue visible
|
|
@@ -13,9 +13,7 @@ import {
|
|
|
13
13
|
} from './chrome.js';
|
|
14
14
|
import { hideSlashMenu, notify, onChatInputChanged, runCommand, toast } from './commands.js';
|
|
15
15
|
export {
|
|
16
|
-
ADVISOR_KINDS,
|
|
17
16
|
READ_ONLY_TOOLS,
|
|
18
|
-
advisorMeta,
|
|
19
17
|
basename,
|
|
20
18
|
formatDuration,
|
|
21
19
|
isFailedToolText,
|
|
@@ -53,7 +51,6 @@ import { setStatus } from './settings.js';
|
|
|
53
51
|
import { reconcile, renderAlertSignals } from './system.js';
|
|
54
52
|
import { narrar, reproducirVoz } from './voice.js';
|
|
55
53
|
import {
|
|
56
|
-
addAdvisorCard,
|
|
57
54
|
addChoiceCard,
|
|
58
55
|
addCompactCard,
|
|
59
56
|
addPermissionCard,
|
|
@@ -69,7 +66,6 @@ import {
|
|
|
69
66
|
toolCardIndex,} from './cards.js';
|
|
70
67
|
export {
|
|
71
68
|
PLAN_MARKS,
|
|
72
|
-
addAdvisorCard,
|
|
73
69
|
addChoiceCard,
|
|
74
70
|
addCompactCard,
|
|
75
71
|
addPermissionCard,
|
|
@@ -427,13 +423,6 @@ export function renderStored(message, pane) {
|
|
|
427
423
|
addCompactCard(pane, { text: typeof message.content === 'string' ? message.content : '' });
|
|
428
424
|
return;
|
|
429
425
|
}
|
|
430
|
-
if (message.role === 'assistant' && message.name === 'advisor') {
|
|
431
|
-
addAdvisorCard(pane, {
|
|
432
|
-
text: typeof message.content === 'string' ? message.content : '',
|
|
433
|
-
kind: message.mode,
|
|
434
|
-
});
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
426
|
if (message.role === 'user') {
|
|
438
427
|
const bubble = addMessage('user', userText(message.content), pane);
|
|
439
428
|
if (message.id) {
|
|
@@ -775,11 +764,6 @@ export function addContinueButton(turn, data) {
|
|
|
775
764
|
export function handleChatEvent(event, data, turn) {
|
|
776
765
|
if (handleAgentEvent(event, data, turn)) return;
|
|
777
766
|
narrar(event, data, turn);
|
|
778
|
-
if (event === 'advice') {
|
|
779
|
-
addAdvisorCard(turn.pane, { text: data?.text, kind: data?.kind });
|
|
780
|
-
scrollMessages(turn.pane);
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
767
|
if (event === 'agent_start') {
|
|
784
768
|
turn.agents.set(data.agentId, addAgentCard(turn.assistant(), data));
|
|
785
769
|
} else if (event === 'agent_end') {
|
|
@@ -1080,6 +1064,7 @@ export async function startTurn(sessionKey, pane, input, images, opts = {}) {
|
|
|
1080
1064
|
provider: owner?.provider || providerSelect.value || undefined,
|
|
1081
1065
|
model: owner?.model || modelSelect.value || undefined,
|
|
1082
1066
|
mode: owner?.mode || modeSelect.value || undefined,
|
|
1067
|
+
effort: owner?.effort ?? undefined,
|
|
1083
1068
|
yes: yesInput.checked ? true : undefined,
|
|
1084
1069
|
contextTokens: contextTokensForRequest(),
|
|
1085
1070
|
interrupt: opts.interrupt ? true : undefined,
|
|
@@ -131,17 +131,6 @@ export function userImages(content) {
|
|
|
131
131
|
.filter(Boolean);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export const ADVISOR_KINDS = {
|
|
135
|
-
code: { label: 'Cuidado!', glyph: '⚠' },
|
|
136
|
-
explain: { label: 'Importante!', glyph: 'ℹ' },
|
|
137
|
-
advice: { label: 'Consejo', glyph: '✦' },
|
|
138
|
-
summary: { label: 'Resumen', glyph: '✎' },
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
export function advisorMeta(kind) {
|
|
142
|
-
return ADVISOR_KINDS[kind] || { label: 'Asesor', glyph: '✦' };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
134
|
/** Ultimo segmento de un path (sin separadores finales). */
|
|
146
135
|
export function basename(p) {
|
|
147
136
|
const text = String(p ?? '').replace(/[\\/]+$/, '');
|
|
@@ -16,7 +16,7 @@ import { pickVisible } from './modelsQuery.js';
|
|
|
16
16
|
import { activateSession, registerSession } from './sessions.js';
|
|
17
17
|
import {
|
|
18
18
|
activateAjustesPanel,
|
|
19
|
-
|
|
19
|
+
refreshAgents,
|
|
20
20
|
refreshChannels,
|
|
21
21
|
refreshLimits,
|
|
22
22
|
refreshMcp,
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
setAjustesLevel,
|
|
31
31
|
setStatus,
|
|
32
32
|
} from './settings.js';
|
|
33
|
-
import { refreshRuns } from './system.js';
|
|
34
33
|
import { refreshTranscribe, refreshVoz, setHandsFree } from './voice.js';
|
|
35
34
|
|
|
36
35
|
export function setCwd(value) {
|
|
@@ -48,7 +47,7 @@ export const moreMenu = $('#more-menu');
|
|
|
48
47
|
export const topbarSection = $('#topbar-section');
|
|
49
48
|
export const backChat = $('#back-chat');
|
|
50
49
|
|
|
51
|
-
export const TAB_LABELS = { chat: 'chat', providers: 'proveedores', ajustes: 'ajustes'
|
|
50
|
+
export const TAB_LABELS = { chat: 'chat', providers: 'proveedores', ajustes: 'ajustes' };
|
|
52
51
|
|
|
53
52
|
export function hideMoreMenu() {
|
|
54
53
|
if (moreMenu.hidden) return;
|
|
@@ -67,9 +66,8 @@ export function activateTab(name) {
|
|
|
67
66
|
moreTab.classList.toggle('active', name !== 'chat');
|
|
68
67
|
document.querySelectorAll('.view').forEach((v) => v.classList.toggle('active', v.id === `view-${name}`));
|
|
69
68
|
hideMoreMenu();
|
|
70
|
-
if (name === 'runs') refreshRuns();
|
|
71
69
|
if (name === 'providers') refreshProviders();
|
|
72
|
-
if (name === 'ajustes') { setAjustesLevel('list'); refreshMcp(); refreshMcpCatalog(); refreshSkills(); refreshSkillCatalog(); refreshMemory(); refreshSchedules(); refreshChannels(); refreshLimits(); refreshVoz();
|
|
70
|
+
if (name === 'ajustes') { setAjustesLevel('list'); refreshMcp(); refreshMcpCatalog(); refreshSkills(); refreshSkillCatalog(); refreshAgents(); refreshMemory(); refreshSchedules(); refreshChannels(); refreshLimits(); refreshVoz(); refreshTranscribe(); refreshProfile(); }
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
/* --- settings modal (modo / proveedor / modelo / auto) -------------------- */
|
|
@@ -122,6 +120,8 @@ export async function loadModes() {
|
|
|
122
120
|
const active = settings?.settings?.mode || 'agent';
|
|
123
121
|
if ([...modeSelect.options].some((o) => o.value === active)) modeSelect.value = active;
|
|
124
122
|
if (strictInput) strictInput.checked = settings?.settings?.strictScope === true;
|
|
123
|
+
state.active.effort = settings?.settings?.effort ?? '';
|
|
124
|
+
renderEffortPill();
|
|
125
125
|
defaultCwdCache = settings?.settings?.defaultCwd || '';
|
|
126
126
|
if (!defaultCwdCache) {
|
|
127
127
|
// Migración: la carpeta predeterminada vivía en localStorage; la subimos al
|
|
@@ -161,6 +161,19 @@ export const modePillLabel = $('#mode-pill-label');
|
|
|
161
161
|
export const modeMenu = $('#mode-menu');
|
|
162
162
|
export const modelPill = $('#model-pill');
|
|
163
163
|
export const modelPillLabel = $('#model-pill-label');
|
|
164
|
+
export const effortPill = $('#effort-pill');
|
|
165
|
+
export const effortPillLabel = $('#effort-pill-label');
|
|
166
|
+
export const effortMenu = $('#effort-menu');
|
|
167
|
+
export const effortSelect = $('#effort');
|
|
168
|
+
|
|
169
|
+
const EFFORT_CHOICES = [
|
|
170
|
+
{ value: '', label: 'auto' },
|
|
171
|
+
{ value: 'off', label: 'off' },
|
|
172
|
+
{ value: 'low', label: 'low' },
|
|
173
|
+
{ value: 'medium', label: 'medium' },
|
|
174
|
+
{ value: 'high', label: 'high' },
|
|
175
|
+
{ value: 'max', label: 'max' },
|
|
176
|
+
];
|
|
164
177
|
|
|
165
178
|
export function renderCwdPill() {
|
|
166
179
|
if (!cwdPillLabel) return;
|
|
@@ -208,8 +221,82 @@ export function closeModeMenu() {
|
|
|
208
221
|
modePill?.setAttribute('aria-expanded', 'false');
|
|
209
222
|
}
|
|
210
223
|
|
|
224
|
+
/* --- esfuerzo de razonamiento -------------------------------------------- */
|
|
225
|
+
|
|
226
|
+
/** Esfuerzo de la sesión abierta; si no eligió, el default global. */
|
|
227
|
+
export function effortValue(record = state.panes.get(state.sessionId)) {
|
|
228
|
+
if (record && record.effort !== undefined) return record.effort;
|
|
229
|
+
return state.active.effort ?? '';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function checkIcon() {
|
|
233
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
234
|
+
svg.setAttribute('class', 'ctrl-check');
|
|
235
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
236
|
+
svg.setAttribute('fill', 'none');
|
|
237
|
+
svg.setAttribute('stroke', 'currentColor');
|
|
238
|
+
svg.setAttribute('stroke-width', '2.2');
|
|
239
|
+
svg.setAttribute('stroke-linecap', 'round');
|
|
240
|
+
svg.setAttribute('stroke-linejoin', 'round');
|
|
241
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
242
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
243
|
+
path.setAttribute('d', 'M20 6 9 17l-5-5');
|
|
244
|
+
svg.appendChild(path);
|
|
245
|
+
return svg;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function buildEffortMenu() {
|
|
249
|
+
if (!effortMenu) return;
|
|
250
|
+
clear(effortMenu);
|
|
251
|
+
for (const choice of EFFORT_CHOICES) {
|
|
252
|
+
const item = document.createElement('button');
|
|
253
|
+
item.type = 'button';
|
|
254
|
+
item.className = 'ctrl-menu-item';
|
|
255
|
+
item.dataset.effort = choice.value;
|
|
256
|
+
item.setAttribute('role', 'menuitemradio');
|
|
257
|
+
item.setAttribute('aria-checked', 'false');
|
|
258
|
+
item.appendChild(el('span', '', choice.label));
|
|
259
|
+
item.appendChild(checkIcon());
|
|
260
|
+
effortMenu.appendChild(item);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
buildEffortMenu();
|
|
264
|
+
|
|
265
|
+
export function renderEffortPill() {
|
|
266
|
+
const value = effortValue();
|
|
267
|
+
if (effortPillLabel) effortPillLabel.textContent = value || 'auto';
|
|
268
|
+
if (effortPill) {
|
|
269
|
+
effortPill.title = value
|
|
270
|
+
? `esfuerzo de razonamiento: ${value}`
|
|
271
|
+
: 'esfuerzo de razonamiento: auto (default del modelo)';
|
|
272
|
+
}
|
|
273
|
+
if (effortSelect && effortSelect.value !== value) effortSelect.value = value;
|
|
274
|
+
if (!effortMenu) return;
|
|
275
|
+
for (const item of effortMenu.querySelectorAll('.ctrl-menu-item')) {
|
|
276
|
+
const active = (item.dataset.effort || '') === value;
|
|
277
|
+
item.classList.toggle('active', active);
|
|
278
|
+
item.setAttribute('aria-checked', active ? 'true' : 'false');
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function closeEffortMenu() {
|
|
283
|
+
if (!effortMenu || effortMenu.hidden) return;
|
|
284
|
+
effortMenu.hidden = true;
|
|
285
|
+
effortPill?.setAttribute('aria-expanded', 'false');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export async function setEffort(value, { persist = true } = {}) {
|
|
289
|
+
const next = EFFORT_CHOICES.some((choice) => choice.value === value) ? value : '';
|
|
290
|
+
const record = state.panes.get(state.sessionId);
|
|
291
|
+
if (record) record.effort = next;
|
|
292
|
+
state.active.effort = next;
|
|
293
|
+
renderEffortPill();
|
|
294
|
+
if (persist) await persistAgent({ effort: next });
|
|
295
|
+
}
|
|
296
|
+
|
|
211
297
|
export function updateStatus(extra = {}) {
|
|
212
298
|
renderModePill();
|
|
299
|
+
renderEffortPill();
|
|
213
300
|
renderModelPill();
|
|
214
301
|
if (extra.rounds !== undefined) $('#sb-rounds').textContent = `${extra.rounds} rondas`;
|
|
215
302
|
if (extra.stopReason) $('#sb-rounds').textContent = extra.stopReason;
|
|
@@ -492,6 +579,7 @@ export async function saveSettings(patch) {
|
|
|
492
579
|
if (out?.settings) {
|
|
493
580
|
state.active.provider = out.settings.provider;
|
|
494
581
|
state.active.model = out.settings.model;
|
|
582
|
+
if ('effort' in patch) state.active.effort = patch.effort ?? '';
|
|
495
583
|
}
|
|
496
584
|
if (patch.provider) providerSelect.value = patch.provider;
|
|
497
585
|
updateStatus();
|
|
@@ -508,6 +596,7 @@ export async function persistAgent(patch) {
|
|
|
508
596
|
if (patch.provider) record.provider = patch.provider;
|
|
509
597
|
if (patch.model) record.model = patch.model;
|
|
510
598
|
if (patch.mode) record.mode = patch.mode;
|
|
599
|
+
if (patch.effort !== undefined) record.effort = patch.effort;
|
|
511
600
|
api(`/api/sessions/${record.id}`, { method: 'PUT', body: patch }).catch(() => null);
|
|
512
601
|
}
|
|
513
602
|
await saveSettings(patch);
|
|
@@ -532,6 +621,7 @@ export async function applySessionAgent(record) {
|
|
|
532
621
|
if (mode !== 'voice') setHandsFree(false);
|
|
533
622
|
updateStatus();
|
|
534
623
|
renderModePill();
|
|
624
|
+
renderEffortPill();
|
|
535
625
|
renderModelPill();
|
|
536
626
|
}
|
|
537
627
|
|
|
@@ -218,8 +218,7 @@ export async function runCommand(name, arg) {
|
|
|
218
218
|
notify(`Carpeta de trabajo: \`${cwd}\``);
|
|
219
219
|
return { handled: true };
|
|
220
220
|
}
|
|
221
|
-
case 'portkill':
|
|
222
|
-
case 'kill': {
|
|
221
|
+
case 'portkill': {
|
|
223
222
|
const port = Number(arg);
|
|
224
223
|
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
225
224
|
notify('Uso: `/portkill <puerto>`, por ejemplo `/portkill 3000`.', 'notice err');
|
|
@@ -18,7 +18,7 @@ export const state = {
|
|
|
18
18
|
sessionId: null,
|
|
19
19
|
streaming: false,
|
|
20
20
|
providers: [],
|
|
21
|
-
active: { provider: '', model: '' },
|
|
21
|
+
active: { provider: '', model: '', effort: '' },
|
|
22
22
|
// Catalogo de modelos del proveedor y su seleccion. Se cachea porque el
|
|
23
23
|
// catalogo son cientos de modelos (~591 KB) y `loadModels` corre en cada
|
|
24
24
|
// cambio de pestana: refetchearlo hacia parpadear la consola.
|
|
@@ -245,7 +245,7 @@ export function setExplorerMode(mode) {
|
|
|
245
245
|
export function refreshExplorerMode() {
|
|
246
246
|
if (!state.explorerOpen) return;
|
|
247
247
|
if (explorerMode === 'files') refreshExplorer();
|
|
248
|
-
else if (explorerMode === 'procs')
|
|
248
|
+
else if (explorerMode === 'procs') loadProcChips();
|
|
249
249
|
else if (explorerMode === 'git') refreshGit();
|
|
250
250
|
else if (explorerMode === 'preview') syncPreviewTunnel();
|
|
251
251
|
}
|
|
@@ -349,9 +349,9 @@ export function loadPreview(url) {
|
|
|
349
349
|
setPreviewStatus(`cargando ${value} …`);
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
/** Abre acceso remoto al puerto
|
|
352
|
+
/** Abre acceso remoto al puerto en el tailnet (privado). */
|
|
353
353
|
export async function openRemoteTunnel(port) {
|
|
354
|
-
const provider =
|
|
354
|
+
const provider = 'tailscale';
|
|
355
355
|
setPreviewStatus(`abriendo acceso remoto (${provider})…`);
|
|
356
356
|
const data = await api('/api/preview/tunnel', { method: 'POST', body: { port, provider } }).catch((e) => ({ error: e.message }));
|
|
357
357
|
if (data?.error) {
|
|
@@ -366,7 +366,7 @@ export async function openRemoteTunnel(port) {
|
|
|
366
366
|
loadPreview(data.tunnel.url);
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
/* procs:
|
|
369
|
+
/* procs: dev servers declarados por el proyecto */
|
|
370
370
|
|
|
371
371
|
export const procsListEl = $('#procs-list');
|
|
372
372
|
export const procsChipsEl = $('#procs-chips');
|
|
@@ -374,7 +374,7 @@ export const procsCwdEl = $('#procs-cwd');
|
|
|
374
374
|
export const procsLogEl = $('#procs-log');
|
|
375
375
|
export let selectedProc = null;
|
|
376
376
|
|
|
377
|
-
export async function
|
|
377
|
+
export async function loadProcChips() {
|
|
378
378
|
clear(procsChipsEl);
|
|
379
379
|
const cwd = state.cwd || '';
|
|
380
380
|
procsCwdEl.textContent = cwd ? `cwd: ${cwd}` : 'sin carpeta';
|
|
@@ -382,17 +382,14 @@ export async function detectProcs() {
|
|
|
382
382
|
if (!data) return;
|
|
383
383
|
for (const chip of data.chips) {
|
|
384
384
|
const node = button(chip.label, () => startProc(chip), 'xchip');
|
|
385
|
-
|
|
385
|
+
node.title = 'definido en .tamnora/procs.json';
|
|
386
386
|
if (chip.allowed === false) {
|
|
387
387
|
node.disabled = true;
|
|
388
388
|
node.title = `"${chip.command}" no está en processes.allow`;
|
|
389
389
|
}
|
|
390
390
|
procsChipsEl.appendChild(node);
|
|
391
391
|
}
|
|
392
|
-
if (!data.chips.length) procsChipsEl.appendChild(el('span', 'muted', 'no
|
|
393
|
-
else if (data.chips.some((c) => c.source === 'project')) {
|
|
394
|
-
procsChipsEl.appendChild(el('span', 'muted', '· desde .tamnora/procs.json'));
|
|
395
|
-
}
|
|
392
|
+
if (!data.chips.length) procsChipsEl.appendChild(el('span', 'muted', 'no hay procesos definidos en .tamnora/procs.json'));
|
|
396
393
|
await refreshProcs();
|
|
397
394
|
}
|
|
398
395
|
|
|
Binary file
|