code-ollama 0.15.1 → 0.17.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/dist/assets/{tui-CSRbnCod.js → tui-CCHcdC7V.js} +499 -287
- package/dist/cli.js +160 -6
- package/package.json +3 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as PLAN_GENERATION_INSTRUCTION, C as withSystemMessage, D as ASSISTANT, E as getTheme, F as APPROVE, I as REJECT, L as VERSION, M as LABEL, N as PLAN, O as SYSTEM, P as SAFE, R as LIST, S as resetSystemMessage, T as LIST$1, _ as setClearHandler, a as tick, b as loadConfig, c as appendMessage, d as deleteSessionIfEmpty, f as listSessions, g as reset, h as clear, i as WRITE_TOOLS, j as AUTO, k as USER, l as createSession, m as updateSessionModel, n as READ_TOOLS, o as color, p as loadSession, r as TOOLS, s as write, t as executeTool, u as deleteSession, v as listModels, w as HEADER_PREFIX, x as saveConfig, y as streamChat } from "../cli.js";
|
|
2
2
|
import { readdirSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join, relative } from "node:path";
|
|
@@ -17,7 +17,7 @@ function normalizeCodeBlockContent(content, indent = "") {
|
|
|
17
17
|
const indentPattern = new RegExp(`^${indent}`, "gm");
|
|
18
18
|
return content.replace(indentPattern, "").trim();
|
|
19
19
|
}
|
|
20
|
-
async function prewarmCodeBlocks(content) {
|
|
20
|
+
async function prewarmCodeBlocks(content, theme = getTheme()) {
|
|
21
21
|
const promises = [];
|
|
22
22
|
let match;
|
|
23
23
|
CODE_BLOCK_REGEX.lastIndex = 0;
|
|
@@ -26,35 +26,35 @@ async function prewarmCodeBlocks(content) {
|
|
|
26
26
|
const language = match[3];
|
|
27
27
|
const code = normalizeCodeBlockContent(match[4], indent);
|
|
28
28
|
// v8 ignore next 2
|
|
29
|
-
if (code) promises.push(prewarmHighlight(code, language));
|
|
29
|
+
if (code) promises.push(prewarmHighlight(code, language, theme));
|
|
30
30
|
}
|
|
31
31
|
await Promise.all(promises);
|
|
32
32
|
}
|
|
33
|
-
async function prewarmHighlight(code, language) {
|
|
33
|
+
async function prewarmHighlight(code, language, theme = getTheme()) {
|
|
34
34
|
// v8 ignore start
|
|
35
|
-
const cacheKey = `${language ?? ""}:${code}`;
|
|
35
|
+
const cacheKey = `${theme.codeTheme}:${language ?? ""}:${code}`;
|
|
36
36
|
if (highlightCache.has(cacheKey)) return;
|
|
37
37
|
// v8 ignore stop
|
|
38
|
-
const result = await highlightCode(code, language);
|
|
38
|
+
const result = await highlightCode(code, language, theme.codeTheme);
|
|
39
39
|
highlightCache.set(cacheKey, result);
|
|
40
40
|
}
|
|
41
|
-
async function highlightCode(code, language = "text") {
|
|
41
|
+
async function highlightCode(code, language = "text", codeTheme = getTheme().codeTheme) {
|
|
42
42
|
const { codeToANSI } = await import("@shikijs/cli");
|
|
43
43
|
try {
|
|
44
|
-
return await codeToANSI(code, language,
|
|
44
|
+
return await codeToANSI(code, language, codeTheme);
|
|
45
45
|
} catch {
|
|
46
46
|
// v8 ignore next
|
|
47
47
|
return code;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
var CodeBlock = memo(function CodeBlock({ code, language, role }) {
|
|
51
|
-
const cacheKey = `${language ?? ""}:${code}`;
|
|
50
|
+
var CodeBlock = memo(function CodeBlock({ code, language, role, theme = getTheme() }) {
|
|
51
|
+
const cacheKey = `${theme.codeTheme}:${language ?? ""}:${code}`;
|
|
52
52
|
const [highlighted, setHighlighted] = useState(() => highlightCache.get(cacheKey) ?? code);
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
let canceled = false;
|
|
55
55
|
async function loadHighlight() {
|
|
56
56
|
try {
|
|
57
|
-
const result = await highlightCode(code, language);
|
|
57
|
+
const result = await highlightCode(code, language, theme.codeTheme);
|
|
58
58
|
highlightCache.set(cacheKey, result);
|
|
59
59
|
if (!canceled) setHighlighted(result);
|
|
60
60
|
} catch {}
|
|
@@ -66,22 +66,31 @@ var CodeBlock = memo(function CodeBlock({ code, language, role }) {
|
|
|
66
66
|
}, [
|
|
67
67
|
cacheKey,
|
|
68
68
|
code,
|
|
69
|
-
language
|
|
69
|
+
language,
|
|
70
|
+
theme.codeTheme
|
|
70
71
|
]);
|
|
71
72
|
const isSystem = role === SYSTEM;
|
|
72
73
|
return /* @__PURE__ */ jsx(Box, {
|
|
73
74
|
flexDirection: "column",
|
|
74
75
|
borderStyle: "bold",
|
|
75
|
-
borderColor: isSystem ?
|
|
76
|
+
borderColor: isSystem ? theme.colors.secondary : theme.colors.codeBorder,
|
|
76
77
|
paddingX: 1,
|
|
77
78
|
marginY: 1,
|
|
78
79
|
children: /* @__PURE__ */ jsx(Text, {
|
|
80
|
+
color: isSystem ? theme.colors.messageSystem : void 0,
|
|
79
81
|
dimColor: isSystem,
|
|
80
82
|
children: highlighted
|
|
81
83
|
})
|
|
82
84
|
});
|
|
83
85
|
});
|
|
84
86
|
//#endregion
|
|
87
|
+
//#region src/components/Messages/constants.ts
|
|
88
|
+
var TURN_ABORTED_MESSAGE = [
|
|
89
|
+
"<turn_aborted>",
|
|
90
|
+
"The user interrupted the previous turn on purpose. Any running commands may still be running in the background. If any tools were aborted, they may have partially executed.",
|
|
91
|
+
"</turn_aborted>"
|
|
92
|
+
].join("\n");
|
|
93
|
+
//#endregion
|
|
85
94
|
//#region src/components/Markdown/extensions.ts
|
|
86
95
|
var LATEX_COMMANDS = {
|
|
87
96
|
"\\rightarrow": "→",
|
|
@@ -171,7 +180,7 @@ var inlineMathExtension = {
|
|
|
171
180
|
//#endregion
|
|
172
181
|
//#region src/components/Markdown/render.ts
|
|
173
182
|
var HR_PLACEHOLDER = "__CODE_OLLAMA_HR_PLACEHOLDER__";
|
|
174
|
-
function renderMarkdown(content, hrWidth) {
|
|
183
|
+
function renderMarkdown(content, hrWidth, syntaxTheme = "gitHub") {
|
|
175
184
|
const hr = "─".repeat(Math.max(1, hrWidth));
|
|
176
185
|
const markdown = new Marked();
|
|
177
186
|
const rendererExtension = {
|
|
@@ -187,7 +196,7 @@ function renderMarkdown(content, hrWidth) {
|
|
|
187
196
|
}
|
|
188
197
|
};
|
|
189
198
|
markdown.use(markedTerminal({
|
|
190
|
-
theme:
|
|
199
|
+
theme: syntaxTheme,
|
|
191
200
|
reflowText: true,
|
|
192
201
|
width: Math.max(1, hrWidth)
|
|
193
202
|
}));
|
|
@@ -202,23 +211,20 @@ function renderMarkdown(content, hrWidth) {
|
|
|
202
211
|
}
|
|
203
212
|
//#endregion
|
|
204
213
|
//#region src/components/Markdown/Markdown.tsx
|
|
205
|
-
var Markdown = memo(function Markdown({ content, color, dimColor }) {
|
|
214
|
+
var Markdown = memo(function Markdown({ content, color, dimColor, theme = getTheme() }) {
|
|
206
215
|
const { stdout } = useStdout();
|
|
207
216
|
const availableWidth = stdout.columns - 4;
|
|
208
217
|
return /* @__PURE__ */ jsx(Text, {
|
|
209
218
|
color,
|
|
210
219
|
dimColor,
|
|
211
|
-
children: useMemo(() => renderMarkdown(content, availableWidth), [
|
|
220
|
+
children: useMemo(() => renderMarkdown(content, availableWidth, theme.markdownTheme), [
|
|
221
|
+
content,
|
|
222
|
+
availableWidth,
|
|
223
|
+
theme.markdownTheme
|
|
224
|
+
])
|
|
212
225
|
});
|
|
213
226
|
});
|
|
214
227
|
//#endregion
|
|
215
|
-
//#region src/components/Messages/constants.ts
|
|
216
|
-
var TURN_ABORTED_MESSAGE = [
|
|
217
|
-
"<turn_aborted>",
|
|
218
|
-
"The user interrupted the previous turn on purpose. Any running commands may still be running in the background. If any tools were aborted, they may have partially executed.",
|
|
219
|
-
"</turn_aborted>"
|
|
220
|
-
].join("\n");
|
|
221
|
-
//#endregion
|
|
222
228
|
//#region src/components/Messages/layout.ts
|
|
223
229
|
var ANSI_REGEX = new RegExp(String.raw`\u001B\[[0-9;]*m`, "g");
|
|
224
230
|
var CODE_BLOCK_MARGIN_Y = 2;
|
|
@@ -371,118 +377,31 @@ function parseContent(content) {
|
|
|
371
377
|
return segments;
|
|
372
378
|
}
|
|
373
379
|
//#endregion
|
|
374
|
-
//#region src/components/Messages/streaming.ts
|
|
375
|
-
function isWordCharacter(char) {
|
|
376
|
-
return char !== void 0 && /[A-Za-z0-9]/.test(char);
|
|
377
|
-
}
|
|
378
|
-
function isEscaped(content, index) {
|
|
379
|
-
let slashCount = 0;
|
|
380
|
-
for (let cursor = index - 1; cursor >= 0 && content[cursor] === "\\"; cursor--) slashCount += 1;
|
|
381
|
-
return slashCount % 2 === 1;
|
|
382
|
-
}
|
|
383
|
-
function canOpenEmphasis(content, index, length) {
|
|
384
|
-
const previous = content[index - 1];
|
|
385
|
-
const next = content[index + length];
|
|
386
|
-
if (!next || /\s/.test(next)) return false;
|
|
387
|
-
return !isWordCharacter(previous);
|
|
388
|
-
}
|
|
389
|
-
function canCloseEmphasis(content, index, length) {
|
|
390
|
-
const previous = content[index - 1];
|
|
391
|
-
const next = content[index + length];
|
|
392
|
-
if (!previous || /\s/.test(previous)) return false;
|
|
393
|
-
return !isWordCharacter(next);
|
|
394
|
-
}
|
|
395
|
-
function findUnmatchedInlineDelimiter(content) {
|
|
396
|
-
const stack = [];
|
|
397
|
-
for (let index = 0; index < content.length; index += 1) {
|
|
398
|
-
const current = content[index];
|
|
399
|
-
if (isEscaped(content, index)) continue;
|
|
400
|
-
const top = stack.at(-1);
|
|
401
|
-
if (top?.kind === "code") {
|
|
402
|
-
if (current === "`") stack.pop();
|
|
403
|
-
continue;
|
|
404
|
-
}
|
|
405
|
-
if (top?.kind === "latex") {
|
|
406
|
-
if (current === "$") stack.pop();
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
if (current === "`") {
|
|
410
|
-
stack.push({
|
|
411
|
-
index,
|
|
412
|
-
length: 1,
|
|
413
|
-
kind: "code",
|
|
414
|
-
marker: "`"
|
|
415
|
-
});
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
if (current === "$") {
|
|
419
|
-
stack.push({
|
|
420
|
-
index,
|
|
421
|
-
length: 1,
|
|
422
|
-
kind: "latex",
|
|
423
|
-
marker: "$"
|
|
424
|
-
});
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
if (current !== "*") continue;
|
|
428
|
-
const marker = current;
|
|
429
|
-
const length = content[index + 1] === marker ? 2 : 1;
|
|
430
|
-
const token = marker.repeat(length);
|
|
431
|
-
const kind = length === 2 ? "bold" : "italic";
|
|
432
|
-
if (top?.marker === token && top.kind === kind && canCloseEmphasis(content, index, length)) {
|
|
433
|
-
stack.pop();
|
|
434
|
-
if (length === 2) index += 1;
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
if (canOpenEmphasis(content, index, length)) {
|
|
438
|
-
stack.push({
|
|
439
|
-
index,
|
|
440
|
-
length,
|
|
441
|
-
kind,
|
|
442
|
-
marker: token
|
|
443
|
-
});
|
|
444
|
-
if (length === 2) index += 1;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
return stack[0] ?? null;
|
|
448
|
-
}
|
|
449
|
-
function splitStreamingInlineContent(content) {
|
|
450
|
-
const unmatched = findUnmatchedInlineDelimiter(content);
|
|
451
|
-
if (!unmatched) return [{
|
|
452
|
-
type: "markdown",
|
|
453
|
-
content
|
|
454
|
-
}];
|
|
455
|
-
const parts = [];
|
|
456
|
-
const prefix = content.slice(0, unmatched.index);
|
|
457
|
-
const plainSuffix = content.slice(unmatched.index + unmatched.length);
|
|
458
|
-
if (prefix) parts.push({
|
|
459
|
-
type: "markdown",
|
|
460
|
-
content: prefix
|
|
461
|
-
});
|
|
462
|
-
if (plainSuffix) parts.push({
|
|
463
|
-
type: "plain",
|
|
464
|
-
content: plainSuffix
|
|
465
|
-
});
|
|
466
|
-
return parts;
|
|
467
|
-
}
|
|
468
|
-
//#endregion
|
|
469
380
|
//#region src/components/Messages/styles.ts
|
|
470
|
-
function getMessageColor(role) {
|
|
381
|
+
function getMessageColor(role, theme) {
|
|
471
382
|
switch (role) {
|
|
472
|
-
case USER:
|
|
473
|
-
case ASSISTANT: return
|
|
474
|
-
case SYSTEM: return
|
|
383
|
+
case USER:
|
|
384
|
+
case ASSISTANT: return;
|
|
385
|
+
case SYSTEM: return theme.colors.messageSystem;
|
|
475
386
|
default: return;
|
|
476
387
|
}
|
|
477
388
|
}
|
|
478
389
|
//#endregion
|
|
479
|
-
//#region src/components/Messages/
|
|
480
|
-
function
|
|
481
|
-
|
|
482
|
-
|
|
390
|
+
//#region src/components/Messages/Message.tsx
|
|
391
|
+
function renderStickyPaddingLines(count) {
|
|
392
|
+
return Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx(
|
|
393
|
+
Text,
|
|
394
|
+
// v8 ignore start
|
|
395
|
+
{ children: " " },
|
|
396
|
+
index
|
|
397
|
+
));
|
|
398
|
+
}
|
|
399
|
+
function Message({ message, isStreaming = false, theme }) {
|
|
400
|
+
const messageColor = getMessageColor(message.role, theme);
|
|
483
401
|
const isSystem = message.role === SYSTEM;
|
|
484
402
|
const isUser = message.role === USER;
|
|
485
403
|
const isStreamingAssistant = isStreaming && !isUser && !isSystem;
|
|
404
|
+
const { stdout } = useStdout();
|
|
486
405
|
const stickyHeightRef = useRef({
|
|
487
406
|
columns: stdout.columns,
|
|
488
407
|
maxHeight: 0
|
|
@@ -506,7 +425,10 @@ function Message({ message, isStreaming = false }) {
|
|
|
506
425
|
const streamingHeight = isStreamingAssistant ? segments.reduce((height, segment) => {
|
|
507
426
|
if (segment.type === "code") return height + getCodeBlockHeight(segment.content, availableWidth);
|
|
508
427
|
if (segment.type === "raw") return height + getCodeBlockHeight(unwrapRawMarkdownFence(segment.content) ?? segment.content, availableWidth);
|
|
509
|
-
return height + getStreamingTextHeight(
|
|
428
|
+
return height + getStreamingTextHeight([{
|
|
429
|
+
type: "markdown",
|
|
430
|
+
content: segment.content
|
|
431
|
+
}], availableWidth);
|
|
510
432
|
}, 0) : 0;
|
|
511
433
|
if (isStreamingAssistant) stickyHeightRef.current.maxHeight = Math.max(stickyHeightRef.current.maxHeight, streamingHeight);
|
|
512
434
|
const stickyPaddingLines = isStreamingAssistant ? stickyHeightRef.current.maxHeight - streamingHeight : 0;
|
|
@@ -523,7 +445,8 @@ function Message({ message, isStreaming = false }) {
|
|
|
523
445
|
children: /* @__PURE__ */ jsx(CodeBlock, {
|
|
524
446
|
code: segment.content,
|
|
525
447
|
language: segment.language,
|
|
526
|
-
role: message.role
|
|
448
|
+
role: message.role,
|
|
449
|
+
theme
|
|
527
450
|
})
|
|
528
451
|
}, index);
|
|
529
452
|
if (segment.type === "raw") {
|
|
@@ -533,11 +456,12 @@ function Message({ message, isStreaming = false }) {
|
|
|
533
456
|
children: /* @__PURE__ */ jsx(CodeBlock, {
|
|
534
457
|
code: markdownSource ?? segment.content,
|
|
535
458
|
language: markdownSource ? "markdown" : segment.language,
|
|
536
|
-
role: message.role
|
|
459
|
+
role: message.role,
|
|
460
|
+
theme
|
|
537
461
|
})
|
|
538
462
|
}, index);
|
|
539
463
|
}
|
|
540
|
-
const textParts =
|
|
464
|
+
const textParts = [{
|
|
541
465
|
type: "markdown",
|
|
542
466
|
content: segment.content
|
|
543
467
|
}];
|
|
@@ -547,28 +471,31 @@ function Message({ message, isStreaming = false }) {
|
|
|
547
471
|
}, index) : /* @__PURE__ */ jsx(Box, {
|
|
548
472
|
flexDirection: "column",
|
|
549
473
|
marginX: 2,
|
|
550
|
-
children: textParts.map((part, partIndex) =>
|
|
551
|
-
color: messageColor,
|
|
552
|
-
children: part.content
|
|
553
|
-
}, partIndex) : /* @__PURE__ */ jsx(Markdown, {
|
|
474
|
+
children: textParts.map((part, partIndex) => /* @__PURE__ */ jsx(Markdown, {
|
|
554
475
|
content: part.content,
|
|
555
|
-
|
|
476
|
+
theme
|
|
556
477
|
}, partIndex))
|
|
557
478
|
}, index);
|
|
558
|
-
}),
|
|
479
|
+
}), renderStickyPaddingLines(stickyPaddingLines)]
|
|
559
480
|
});
|
|
560
481
|
}
|
|
561
|
-
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/components/Messages/Messages.tsx
|
|
484
|
+
function Messages({ messages, isLoading, sessionId, streamingMessage, theme = getTheme() }) {
|
|
562
485
|
return /* @__PURE__ */ jsxs(Box, {
|
|
563
486
|
flexDirection: "column",
|
|
564
487
|
children: [
|
|
565
488
|
/* @__PURE__ */ jsx(Static, {
|
|
566
489
|
items: messages.filter(({ content }) => content !== TURN_ABORTED_MESSAGE),
|
|
567
|
-
children: (message, index) => /* @__PURE__ */ jsx(Message, {
|
|
490
|
+
children: (message, index) => /* @__PURE__ */ jsx(Message, {
|
|
491
|
+
message,
|
|
492
|
+
theme
|
|
493
|
+
}, index)
|
|
568
494
|
}, sessionId),
|
|
569
495
|
streamingMessage && /* @__PURE__ */ jsx(Message, {
|
|
570
496
|
isStreaming: true,
|
|
571
|
-
message: streamingMessage
|
|
497
|
+
message: streamingMessage,
|
|
498
|
+
theme
|
|
572
499
|
}),
|
|
573
500
|
isLoading && !streamingMessage?.content && /* @__PURE__ */ jsx(Box, {
|
|
574
501
|
marginTop: -1,
|
|
@@ -580,7 +507,7 @@ function Messages({ messages, isLoading, sessionId, streamingMessage }) {
|
|
|
580
507
|
});
|
|
581
508
|
}
|
|
582
509
|
//#endregion
|
|
583
|
-
//#region src/components/SelectPrompt.tsx
|
|
510
|
+
//#region src/components/SelectPrompt/SelectPrompt.tsx
|
|
584
511
|
function SelectPrompt({ borderStyle, children, onCancel, ...selectProps }) {
|
|
585
512
|
useInput((input, key) => {
|
|
586
513
|
if (key.escape || key.ctrl && input === "c") onCancel?.();
|
|
@@ -591,6 +518,8 @@ function SelectPrompt({ borderStyle, children, onCancel, ...selectProps }) {
|
|
|
591
518
|
children: [children, /* @__PURE__ */ jsx(Select, { ...selectProps })]
|
|
592
519
|
});
|
|
593
520
|
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region src/components/SelectPrompt/SelectPromptHint.tsx
|
|
594
523
|
function SelectPromptHint({ message = "Select option", escapeLabel = "cancel" }) {
|
|
595
524
|
return /* @__PURE__ */ jsxs(Box, {
|
|
596
525
|
flexDirection: "row",
|
|
@@ -646,7 +575,7 @@ var options$1 = [
|
|
|
646
575
|
value: PLAN
|
|
647
576
|
}
|
|
648
577
|
];
|
|
649
|
-
function PlanApproval({ planContent, onModeChange }) {
|
|
578
|
+
function PlanApproval({ planContent, onModeChange, theme = getTheme() }) {
|
|
650
579
|
return /* @__PURE__ */ jsx(Box, {
|
|
651
580
|
marginX: 2,
|
|
652
581
|
children: /* @__PURE__ */ jsx(SelectPrompt, {
|
|
@@ -663,7 +592,7 @@ function PlanApproval({ planContent, onModeChange }) {
|
|
|
663
592
|
children: [
|
|
664
593
|
/* @__PURE__ */ jsx(Text, {
|
|
665
594
|
bold: true,
|
|
666
|
-
color:
|
|
595
|
+
color: theme.colors.accent,
|
|
667
596
|
children: "Plan Generated - Choose execution mode:"
|
|
668
597
|
}),
|
|
669
598
|
/* @__PURE__ */ jsx(Box, {
|
|
@@ -685,7 +614,7 @@ var options = [{
|
|
|
685
614
|
label: "Reject tool call",
|
|
686
615
|
value: REJECT
|
|
687
616
|
}];
|
|
688
|
-
function ToolApproval({ toolCall, onDecision }) {
|
|
617
|
+
function ToolApproval({ toolCall, onDecision, theme = getTheme() }) {
|
|
689
618
|
const handleChange = useCallback((value) => {
|
|
690
619
|
onDecision(value);
|
|
691
620
|
}, [onDecision]);
|
|
@@ -702,7 +631,7 @@ function ToolApproval({ toolCall, onDecision }) {
|
|
|
702
631
|
onCancel: handleEscape,
|
|
703
632
|
children: [
|
|
704
633
|
/* @__PURE__ */ jsx(Text, {
|
|
705
|
-
color:
|
|
634
|
+
color: theme.colors.warning,
|
|
706
635
|
children: "Tool requires approval ⚠️ "
|
|
707
636
|
}),
|
|
708
637
|
/* @__PURE__ */ jsxs(Box, {
|
|
@@ -734,16 +663,6 @@ function ToolApproval({ toolCall, onDecision }) {
|
|
|
734
663
|
});
|
|
735
664
|
}
|
|
736
665
|
//#endregion
|
|
737
|
-
//#region src/components/Chat/constants.ts
|
|
738
|
-
var ACTION_NOT_PERFORMED = "The requested action was NOT performed";
|
|
739
|
-
var PLAN_CHECKLIST_REMINDER = "Then display the execution plan as an unchecked Markdown checklist only";
|
|
740
|
-
var PLAN_EXECUTION_REMINDER = `Do not claim success and do not call ${Array.from(WRITE_TOOLS).join(", ")} until the user approves execution`;
|
|
741
|
-
var INTERRUPT_REASON = /* @__PURE__ */ function(INTERRUPT_REASON) {
|
|
742
|
-
INTERRUPT_REASON["INTERRUPTED"] = "interrupted";
|
|
743
|
-
INTERRUPT_REASON["REJECTED"] = "rejected";
|
|
744
|
-
return INTERRUPT_REASON;
|
|
745
|
-
}({});
|
|
746
|
-
//#endregion
|
|
747
666
|
//#region src/components/TextInput/TextInput.tsx
|
|
748
667
|
function buildLineSegments(displayValue, cursorPosition, width) {
|
|
749
668
|
const safeWidth = Math.max(1, width);
|
|
@@ -1043,17 +962,28 @@ function FileSuggestions({ input, isDisabled = false, onChange, onSelect }) {
|
|
|
1043
962
|
});
|
|
1044
963
|
}
|
|
1045
964
|
//#endregion
|
|
1046
|
-
//#region src/components/Chat/
|
|
965
|
+
//#region src/components/Chat/ChatInput.tsx
|
|
1047
966
|
function hasFileSuggestionQuery(input) {
|
|
1048
967
|
return /(^|.)@\S+/.test(input);
|
|
1049
968
|
}
|
|
1050
|
-
function
|
|
969
|
+
function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, onSubmit }) {
|
|
1051
970
|
const { exit } = useApp();
|
|
971
|
+
const [history, setHistory] = useState(sessionHistory);
|
|
972
|
+
const [historyIndex, setHistoryIndex] = useState(null);
|
|
1052
973
|
const [input, setInput] = useState("");
|
|
1053
974
|
const [cursorPosition, setCursorPosition] = useState(void 0);
|
|
1054
975
|
const fileSuggestionRef = useRef(null);
|
|
976
|
+
useEffect(() => {
|
|
977
|
+
setHistory(sessionHistory);
|
|
978
|
+
setHistoryIndex(null);
|
|
979
|
+
setInput("");
|
|
980
|
+
setCursorPosition(void 0);
|
|
981
|
+
fileSuggestionRef.current = null;
|
|
982
|
+
}, [sessionHistory]);
|
|
1055
983
|
const resetInput = useCallback(() => {
|
|
1056
984
|
setInput("");
|
|
985
|
+
setCursorPosition(void 0);
|
|
986
|
+
setHistoryIndex(null);
|
|
1057
987
|
}, []);
|
|
1058
988
|
const handleSelectFileSuggestion = useCallback((nextInput) => {
|
|
1059
989
|
setInput(nextInput.value);
|
|
@@ -1077,15 +1007,58 @@ function Input({ isDisabled = false, onInterrupt, onSubmit }) {
|
|
|
1077
1007
|
};
|
|
1078
1008
|
} else fileSuggestionRef.current = null;
|
|
1079
1009
|
}, [input]);
|
|
1010
|
+
const handleInputChange = useCallback((nextInput) => {
|
|
1011
|
+
setInput(nextInput);
|
|
1012
|
+
setHistoryIndex(null);
|
|
1013
|
+
}, []);
|
|
1080
1014
|
const submitAndReset = useCallback((input) => {
|
|
1081
1015
|
const trimmedInput = input.trim();
|
|
1082
1016
|
if (!trimmedInput) return;
|
|
1083
1017
|
onSubmit(trimmedInput);
|
|
1018
|
+
if (!trimmedInput.startsWith("/")) setHistory((previousHistory) => [...previousHistory, trimmedInput]);
|
|
1084
1019
|
resetInput();
|
|
1085
1020
|
fileSuggestionRef.current = null;
|
|
1086
1021
|
}, [onSubmit, resetInput]);
|
|
1087
1022
|
const showCommandMenu = input.startsWith("/");
|
|
1088
1023
|
const showFileSuggestions = !showCommandMenu && hasFileSuggestionQuery(input);
|
|
1024
|
+
const handleHistoryNavigation = useCallback((direction) => {
|
|
1025
|
+
if (!history.length || showFileSuggestions) return;
|
|
1026
|
+
if (direction === "up") {
|
|
1027
|
+
if (historyIndex === null) {
|
|
1028
|
+
if (input) return;
|
|
1029
|
+
const nextIndex = history.length - 1;
|
|
1030
|
+
const nextInput = history[nextIndex];
|
|
1031
|
+
setHistoryIndex(nextIndex);
|
|
1032
|
+
setInput(nextInput);
|
|
1033
|
+
setCursorPosition(nextInput.length);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
if (historyIndex === 0) return;
|
|
1037
|
+
const nextIndex = historyIndex - 1;
|
|
1038
|
+
const nextInput = history[nextIndex];
|
|
1039
|
+
setHistoryIndex(nextIndex);
|
|
1040
|
+
setInput(nextInput);
|
|
1041
|
+
setCursorPosition(nextInput.length);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
if (historyIndex === null) return;
|
|
1045
|
+
if (historyIndex === history.length - 1) {
|
|
1046
|
+
setHistoryIndex(null);
|
|
1047
|
+
setInput("");
|
|
1048
|
+
setCursorPosition(0);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
const nextIndex = historyIndex + 1;
|
|
1052
|
+
const nextInput = history[nextIndex];
|
|
1053
|
+
setHistoryIndex(nextIndex);
|
|
1054
|
+
setInput(nextInput);
|
|
1055
|
+
setCursorPosition(nextInput.length);
|
|
1056
|
+
}, [
|
|
1057
|
+
history,
|
|
1058
|
+
historyIndex,
|
|
1059
|
+
input,
|
|
1060
|
+
showFileSuggestions
|
|
1061
|
+
]);
|
|
1089
1062
|
const handleSubmitText = useCallback((input) => {
|
|
1090
1063
|
if (input.startsWith("/")) return;
|
|
1091
1064
|
if (hasFileSuggestionQuery(input)) {
|
|
@@ -1097,8 +1070,8 @@ function Input({ isDisabled = false, onInterrupt, onSubmit }) {
|
|
|
1097
1070
|
const handleSubmitCommand = useCallback((input) => {
|
|
1098
1071
|
if (LIST.find(({ name }) => name === input)) submitAndReset(input);
|
|
1099
1072
|
}, [submitAndReset]);
|
|
1100
|
-
useInput((
|
|
1101
|
-
const isCtrlC = key.ctrl &&
|
|
1073
|
+
useInput((inputKey, key) => {
|
|
1074
|
+
const isCtrlC = key.ctrl && inputKey === "c";
|
|
1102
1075
|
if (isDisabled) {
|
|
1103
1076
|
if (key.escape || isCtrlC) onInterrupt?.();
|
|
1104
1077
|
return;
|
|
@@ -1110,6 +1083,11 @@ function Input({ isDisabled = false, onInterrupt, onSubmit }) {
|
|
|
1110
1083
|
}
|
|
1111
1084
|
exit();
|
|
1112
1085
|
}
|
|
1086
|
+
if (key.upArrow) {
|
|
1087
|
+
handleHistoryNavigation("up");
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
if (key.downArrow) handleHistoryNavigation("down");
|
|
1113
1091
|
});
|
|
1114
1092
|
return /* @__PURE__ */ jsxs(Box, {
|
|
1115
1093
|
flexDirection: "column",
|
|
@@ -1119,7 +1097,7 @@ function Input({ isDisabled = false, onInterrupt, onSubmit }) {
|
|
|
1119
1097
|
isDisabled,
|
|
1120
1098
|
cursorPosition,
|
|
1121
1099
|
wrapIndent: 2,
|
|
1122
|
-
onChange:
|
|
1100
|
+
onChange: handleInputChange,
|
|
1123
1101
|
onSubmit: handleSubmitText,
|
|
1124
1102
|
placeholder: "Ask anything... (/ commands, @ files)"
|
|
1125
1103
|
})] }),
|
|
@@ -1137,6 +1115,16 @@ function Input({ isDisabled = false, onInterrupt, onSubmit }) {
|
|
|
1137
1115
|
});
|
|
1138
1116
|
}
|
|
1139
1117
|
//#endregion
|
|
1118
|
+
//#region src/components/Chat/constants.ts
|
|
1119
|
+
var ACTION_NOT_PERFORMED = "The requested action was NOT performed";
|
|
1120
|
+
var PLAN_CHECKLIST_REMINDER = "Then display the execution plan as an unchecked Markdown checklist only";
|
|
1121
|
+
var PLAN_EXECUTION_REMINDER = `Do not claim success and do not call ${Array.from(WRITE_TOOLS).join(", ")} until the user approves execution`;
|
|
1122
|
+
var INTERRUPT_REASON = /* @__PURE__ */ function(INTERRUPT_REASON) {
|
|
1123
|
+
INTERRUPT_REASON["INTERRUPTED"] = "interrupted";
|
|
1124
|
+
INTERRUPT_REASON["REJECTED"] = "rejected";
|
|
1125
|
+
return INTERRUPT_REASON;
|
|
1126
|
+
}({});
|
|
1127
|
+
//#endregion
|
|
1140
1128
|
//#region src/components/Chat/plan.ts
|
|
1141
1129
|
function hasExecutablePlan(content) {
|
|
1142
1130
|
return content.split("\n").some((line) => {
|
|
@@ -1146,8 +1134,9 @@ function hasExecutablePlan(content) {
|
|
|
1146
1134
|
}
|
|
1147
1135
|
//#endregion
|
|
1148
1136
|
//#region src/components/Chat/Chat.tsx
|
|
1149
|
-
function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onModeChange, sessionId }) {
|
|
1137
|
+
function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onModeChange, sessionId, theme = getTheme() }) {
|
|
1150
1138
|
const sessionMessages = initialMessages ?? [];
|
|
1139
|
+
const history = useMemo(() => sessionMessages.flatMap(({ role, content }) => role === "user" && !content.startsWith("/") ? [content] : []), [sessionMessages]);
|
|
1151
1140
|
const [messages, setMessages] = useState(sessionMessages);
|
|
1152
1141
|
const [streamingMessage, setStreamingMessage] = useState(null);
|
|
1153
1142
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -1262,13 +1251,13 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1262
1251
|
return;
|
|
1263
1252
|
}
|
|
1264
1253
|
}
|
|
1265
|
-
await prewarmCodeBlocks(assistantMessage.content);
|
|
1254
|
+
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1266
1255
|
commitAssistantMessage();
|
|
1267
1256
|
} catch (error) {
|
|
1268
1257
|
// v8 ignore next
|
|
1269
1258
|
if (!controller.signal.aborted) {
|
|
1270
1259
|
assistantMessage.content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
1271
|
-
await prewarmCodeBlocks(assistantMessage.content);
|
|
1260
|
+
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1272
1261
|
commitAssistantMessage();
|
|
1273
1262
|
}
|
|
1274
1263
|
} finally {
|
|
@@ -1278,7 +1267,8 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1278
1267
|
}, [
|
|
1279
1268
|
buildToolResultMessage,
|
|
1280
1269
|
model,
|
|
1281
|
-
mode
|
|
1270
|
+
mode,
|
|
1271
|
+
theme
|
|
1282
1272
|
]);
|
|
1283
1273
|
const processStreamReadOnly = useCallback(async (currentMessages) => {
|
|
1284
1274
|
const controller = new AbortController();
|
|
@@ -1334,7 +1324,7 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1334
1324
|
return;
|
|
1335
1325
|
}
|
|
1336
1326
|
}
|
|
1337
|
-
await prewarmCodeBlocks(assistantMessage.content);
|
|
1327
|
+
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1338
1328
|
const researchMessages = commitAssistantMessage();
|
|
1339
1329
|
const planInstruction = {
|
|
1340
1330
|
role: SYSTEM,
|
|
@@ -1375,7 +1365,7 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1375
1365
|
// v8 ignore next
|
|
1376
1366
|
if (!controller.signal.aborted) {
|
|
1377
1367
|
assistantMessage.content = `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
1378
|
-
await prewarmCodeBlocks(assistantMessage.content);
|
|
1368
|
+
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1379
1369
|
commitAssistantMessage();
|
|
1380
1370
|
}
|
|
1381
1371
|
} finally {
|
|
@@ -1385,7 +1375,8 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1385
1375
|
}, [
|
|
1386
1376
|
buildPlanModeCorrectionMessage,
|
|
1387
1377
|
buildToolResultMessage,
|
|
1388
|
-
model
|
|
1378
|
+
model,
|
|
1379
|
+
theme
|
|
1389
1380
|
]);
|
|
1390
1381
|
const handlePlanApproval = useCallback(async (mode) => {
|
|
1391
1382
|
// v8 ignore next
|
|
@@ -1477,26 +1468,30 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1477
1468
|
messages,
|
|
1478
1469
|
isLoading,
|
|
1479
1470
|
sessionId,
|
|
1480
|
-
streamingMessage
|
|
1471
|
+
streamingMessage,
|
|
1472
|
+
theme
|
|
1481
1473
|
}),
|
|
1482
1474
|
pendingPlan && /* @__PURE__ */ jsx(PlanApproval, {
|
|
1483
1475
|
planContent: pendingPlan.planContent,
|
|
1484
|
-
onModeChange: handlePlanApproval
|
|
1476
|
+
onModeChange: handlePlanApproval,
|
|
1477
|
+
theme
|
|
1485
1478
|
}),
|
|
1486
1479
|
!pendingPlan && pendingToolCall && /* @__PURE__ */ jsx(ToolApproval, {
|
|
1487
1480
|
toolCall: pendingToolCall,
|
|
1488
|
-
onDecision: handleToolApproval
|
|
1481
|
+
onDecision: handleToolApproval,
|
|
1482
|
+
theme
|
|
1489
1483
|
}),
|
|
1490
1484
|
interruptReason && !isLoading && /* @__PURE__ */ jsx(Box, {
|
|
1491
1485
|
marginBottom: 1,
|
|
1492
1486
|
children: /* @__PURE__ */ jsx(Text, {
|
|
1493
|
-
color:
|
|
1487
|
+
color: theme.colors.error,
|
|
1494
1488
|
children: interruptReason === INTERRUPT_REASON.REJECTED ? "❗ Tool call rejected." : "❗ Execution interrupted."
|
|
1495
1489
|
})
|
|
1496
1490
|
}),
|
|
1497
1491
|
!pendingPlan && !pendingToolCall && /* @__PURE__ */ jsx(Box, {
|
|
1498
1492
|
marginTop: 1,
|
|
1499
|
-
children: /* @__PURE__ */ jsx(
|
|
1493
|
+
children: /* @__PURE__ */ jsx(ChatInput, {
|
|
1494
|
+
history,
|
|
1500
1495
|
isDisabled: isLoading,
|
|
1501
1496
|
onInterrupt: handleInterrupt,
|
|
1502
1497
|
onSubmit: handleSubmit
|
|
@@ -1507,29 +1502,31 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1507
1502
|
}
|
|
1508
1503
|
//#endregion
|
|
1509
1504
|
//#region src/components/Footer.tsx
|
|
1510
|
-
function getModeColor(mode) {
|
|
1505
|
+
function getModeColor(mode, theme) {
|
|
1511
1506
|
switch (mode) {
|
|
1512
|
-
case PLAN: return
|
|
1513
|
-
case AUTO: return
|
|
1514
|
-
case SAFE: return
|
|
1507
|
+
case PLAN: return theme.colors.modePlan;
|
|
1508
|
+
case AUTO: return theme.colors.modeAuto;
|
|
1509
|
+
case SAFE: return theme.colors.modeSafe;
|
|
1515
1510
|
// v8 ignore next
|
|
1516
1511
|
default: return;
|
|
1517
1512
|
}
|
|
1518
1513
|
}
|
|
1519
|
-
function Footer({ mode, model, onToggleMode }) {
|
|
1514
|
+
function Footer({ mode, model, onToggleMode, theme = getTheme() }) {
|
|
1520
1515
|
useInput((_, key) => {
|
|
1521
1516
|
if (key.tab && key.shift) onToggleMode();
|
|
1522
1517
|
});
|
|
1523
1518
|
const modeLabel = LABEL[mode];
|
|
1519
|
+
const modeColor = getModeColor(mode, theme);
|
|
1524
1520
|
return /* @__PURE__ */ jsx(Box, {
|
|
1525
1521
|
justifyContent: "space-between",
|
|
1526
1522
|
marginTop: 1,
|
|
1527
1523
|
children: /* @__PURE__ */ jsxs(Text, {
|
|
1524
|
+
color: theme.colors.secondary,
|
|
1528
1525
|
dimColor: true,
|
|
1529
1526
|
children: [
|
|
1530
1527
|
"Mode: ",
|
|
1531
1528
|
/* @__PURE__ */ jsx(Text, {
|
|
1532
|
-
color:
|
|
1529
|
+
color: modeColor,
|
|
1533
1530
|
children: modeLabel
|
|
1534
1531
|
}),
|
|
1535
1532
|
" (Shift+Tab to toggle)",
|
|
@@ -1537,7 +1534,7 @@ function Footer({ mode, model, onToggleMode }) {
|
|
|
1537
1534
|
"❖",
|
|
1538
1535
|
" Model: ",
|
|
1539
1536
|
/* @__PURE__ */ jsx(Text, {
|
|
1540
|
-
color:
|
|
1537
|
+
color: theme.colors.model,
|
|
1541
1538
|
children: model
|
|
1542
1539
|
})
|
|
1543
1540
|
]
|
|
@@ -1550,7 +1547,7 @@ function abbreviatePath(dir) {
|
|
|
1550
1547
|
const home = homedir();
|
|
1551
1548
|
return dir.startsWith(home) ? `~${dir.slice(home.length)}` : dir;
|
|
1552
1549
|
}
|
|
1553
|
-
function Header({ model, onLoad }) {
|
|
1550
|
+
function Header({ model, onLoad, theme = getTheme() }) {
|
|
1554
1551
|
const directory = abbreviatePath(process.cwd());
|
|
1555
1552
|
useEffect(() => {
|
|
1556
1553
|
onLoad();
|
|
@@ -1566,9 +1563,11 @@ function Header({ model, onLoad }) {
|
|
|
1566
1563
|
bold: true,
|
|
1567
1564
|
children: [HEADER_PREFIX, "Code Ollama"]
|
|
1568
1565
|
}), /* @__PURE__ */ jsxs(Text, {
|
|
1566
|
+
color: theme.colors.secondary,
|
|
1569
1567
|
dimColor: true,
|
|
1570
1568
|
children: [
|
|
1571
|
-
"
|
|
1569
|
+
" ",
|
|
1570
|
+
"(v",
|
|
1572
1571
|
VERSION,
|
|
1573
1572
|
")"
|
|
1574
1573
|
]
|
|
@@ -1577,21 +1576,24 @@ function Header({ model, onLoad }) {
|
|
|
1577
1576
|
marginTop: 1,
|
|
1578
1577
|
children: [
|
|
1579
1578
|
/* @__PURE__ */ jsx(Text, {
|
|
1579
|
+
color: theme.colors.secondary,
|
|
1580
1580
|
dimColor: true,
|
|
1581
1581
|
children: "model:".padEnd(11)
|
|
1582
1582
|
}),
|
|
1583
1583
|
/* @__PURE__ */ jsx(Text, { children: model.padEnd(model.length + 3) }),
|
|
1584
1584
|
/* @__PURE__ */ jsx(Text, {
|
|
1585
|
-
color:
|
|
1585
|
+
color: theme.colors.command,
|
|
1586
1586
|
children: "/model"
|
|
1587
1587
|
}),
|
|
1588
|
-
/* @__PURE__ */
|
|
1588
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
1589
|
+
color: theme.colors.secondary,
|
|
1589
1590
|
dimColor: true,
|
|
1590
|
-
children: " to switch"
|
|
1591
|
+
children: [" ", "to switch"]
|
|
1591
1592
|
})
|
|
1592
1593
|
]
|
|
1593
1594
|
}),
|
|
1594
1595
|
/* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
1596
|
+
color: theme.colors.secondary,
|
|
1595
1597
|
dimColor: true,
|
|
1596
1598
|
children: "directory:".padEnd(11)
|
|
1597
1599
|
}), /* @__PURE__ */ jsx(Text, { children: directory })] })
|
|
@@ -1601,7 +1603,7 @@ function Header({ model, onLoad }) {
|
|
|
1601
1603
|
}
|
|
1602
1604
|
//#endregion
|
|
1603
1605
|
//#region src/components/ModelPicker.tsx
|
|
1604
|
-
function ModelPicker({ currentModel, onSelect, onClose }) {
|
|
1606
|
+
function ModelPicker({ currentModel, onSelect, onClose, theme = getTheme() }) {
|
|
1605
1607
|
const [options, setOptions] = useState([]);
|
|
1606
1608
|
const [error, setError] = useState(null);
|
|
1607
1609
|
const handleChange = useCallback((model) => {
|
|
@@ -1632,7 +1634,7 @@ function ModelPicker({ currentModel, onSelect, onClose }) {
|
|
|
1632
1634
|
load();
|
|
1633
1635
|
}, [currentModel]);
|
|
1634
1636
|
if (error) return /* @__PURE__ */ jsxs(Text, {
|
|
1635
|
-
color:
|
|
1637
|
+
color: theme.colors.error,
|
|
1636
1638
|
children: ["Error loading models: ", error]
|
|
1637
1639
|
});
|
|
1638
1640
|
if (!options.length) return /* @__PURE__ */ jsx(Spinner, { label: "Loading models..." });
|
|
@@ -1646,7 +1648,7 @@ function ModelPicker({ currentModel, onSelect, onClose }) {
|
|
|
1646
1648
|
}
|
|
1647
1649
|
//#endregion
|
|
1648
1650
|
//#region src/components/SearchSettings.tsx
|
|
1649
|
-
function SearchSettings({ currentUrl, onClose, onSave }) {
|
|
1651
|
+
function SearchSettings({ currentUrl, onClose, onSave, theme = getTheme() }) {
|
|
1650
1652
|
const [view, setView] = useState("menu");
|
|
1651
1653
|
const [draftUrl, setDraftUrl] = useState(currentUrl ?? "");
|
|
1652
1654
|
const [error, setError] = useState(null);
|
|
@@ -1718,10 +1720,11 @@ function SearchSettings({ currentUrl, onClose, onSave }) {
|
|
|
1718
1720
|
placeholder: "http://localhost:8080"
|
|
1719
1721
|
})] }),
|
|
1720
1722
|
error && /* @__PURE__ */ jsx(Text, {
|
|
1721
|
-
color:
|
|
1723
|
+
color: theme.colors.error,
|
|
1722
1724
|
children: error
|
|
1723
1725
|
}),
|
|
1724
1726
|
/* @__PURE__ */ jsx(Text, {
|
|
1727
|
+
color: theme.colors.secondary,
|
|
1725
1728
|
dimColor: true,
|
|
1726
1729
|
children: "Press Enter to save, Esc to go back."
|
|
1727
1730
|
})
|
|
@@ -1732,10 +1735,14 @@ function SearchSettings({ currentUrl, onClose, onSave }) {
|
|
|
1732
1735
|
onChange: handleChange,
|
|
1733
1736
|
onCancel: onClose,
|
|
1734
1737
|
children: [
|
|
1735
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1738
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1739
|
+
"SearXNG URL:",
|
|
1740
|
+
" ",
|
|
1741
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1742
|
+
color: theme.colors.status,
|
|
1743
|
+
children: currentUrl ?? "not set"
|
|
1744
|
+
})
|
|
1745
|
+
] }),
|
|
1739
1746
|
/* @__PURE__ */ jsx(Text, { children: "DuckDuckGo fallback remains available." }),
|
|
1740
1747
|
/* @__PURE__ */ jsx(SelectPromptHint, { message: "Manage web search settings" })
|
|
1741
1748
|
]
|
|
@@ -1762,7 +1769,7 @@ function formatSessionLabel(session, maxWidth, prefix = "") {
|
|
|
1762
1769
|
if (availableTitleWidth < 1) return truncate(`${prefix}${session.title}${suffix}`, maxWidth);
|
|
1763
1770
|
return `${prefix}${truncate(session.title, availableTitleWidth)}${suffix}`;
|
|
1764
1771
|
}
|
|
1765
|
-
function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen }) {
|
|
1772
|
+
function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen, theme = getTheme() }) {
|
|
1766
1773
|
const [view, setView] = useState("main");
|
|
1767
1774
|
const [error, setError] = useState();
|
|
1768
1775
|
const [, refreshSessionList] = useState(0);
|
|
@@ -1848,7 +1855,7 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen })
|
|
|
1848
1855
|
error && /* @__PURE__ */ jsx(Box, {
|
|
1849
1856
|
marginBottom: 1,
|
|
1850
1857
|
children: /* @__PURE__ */ jsx(Text, {
|
|
1851
|
-
color:
|
|
1858
|
+
color: theme.colors.error,
|
|
1852
1859
|
children: error
|
|
1853
1860
|
})
|
|
1854
1861
|
}),
|
|
@@ -1861,25 +1868,177 @@ function SessionManager({ currentSessionId, onClose, onDelete, onNew, onOpen })
|
|
|
1861
1868
|
});
|
|
1862
1869
|
}
|
|
1863
1870
|
//#endregion
|
|
1864
|
-
//#region src/components/
|
|
1865
|
-
function
|
|
1866
|
-
|
|
1871
|
+
//#region src/components/ThemeSettings.tsx
|
|
1872
|
+
function ThemeSettings({ currentTheme, onClose, onPreview, onSave }) {
|
|
1873
|
+
const [selectedIndex, setSelectedIndex] = useState(() => {
|
|
1874
|
+
const initialIndex = LIST$1.findIndex(({ id }) => id === currentTheme);
|
|
1875
|
+
return initialIndex >= 0 ? initialIndex : 0;
|
|
1876
|
+
});
|
|
1877
|
+
const selectedTheme = useMemo(
|
|
1878
|
+
// v8 ignore next
|
|
1879
|
+
() => LIST$1[selectedIndex] ?? getTheme(),
|
|
1880
|
+
[selectedIndex]
|
|
1881
|
+
);
|
|
1882
|
+
useEffect(() => {
|
|
1883
|
+
onPreview(selectedTheme.id);
|
|
1884
|
+
}, [onPreview, selectedTheme.id]);
|
|
1885
|
+
useInput((input, key) => {
|
|
1886
|
+
if (key.escape || key.ctrl && input === "c") {
|
|
1887
|
+
onClose();
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
if (key.upArrow) {
|
|
1891
|
+
setSelectedIndex((current) => current === 0 ? LIST$1.length - 1 : current - 1);
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
if (key.downArrow) {
|
|
1895
|
+
setSelectedIndex((current) => current === LIST$1.length - 1 ? 0 : current + 1);
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
if (key.return) onSave(selectedTheme.id);
|
|
1899
|
+
});
|
|
1900
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
1901
|
+
flexDirection: "column",
|
|
1902
|
+
children: [
|
|
1903
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1904
|
+
"Theme:",
|
|
1905
|
+
" ",
|
|
1906
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1907
|
+
color: selectedTheme.colors.accent,
|
|
1908
|
+
children: selectedTheme.label
|
|
1909
|
+
})
|
|
1910
|
+
] }),
|
|
1911
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1912
|
+
color: selectedTheme.colors.secondary,
|
|
1913
|
+
children: selectedTheme.description
|
|
1914
|
+
}),
|
|
1915
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1916
|
+
flexDirection: "column",
|
|
1917
|
+
marginTop: 1,
|
|
1918
|
+
children: LIST$1.map((theme, index) => {
|
|
1919
|
+
const isSelected = index === selectedIndex;
|
|
1920
|
+
return /* @__PURE__ */ jsxs(Text, {
|
|
1921
|
+
color: isSelected ? selectedTheme.colors.accent : void 0,
|
|
1922
|
+
children: [
|
|
1923
|
+
isSelected ? "›" : " ",
|
|
1924
|
+
" ",
|
|
1925
|
+
theme.label
|
|
1926
|
+
]
|
|
1927
|
+
}, theme.id);
|
|
1928
|
+
})
|
|
1929
|
+
}),
|
|
1930
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
1931
|
+
borderColor: selectedTheme.colors.border,
|
|
1932
|
+
borderStyle: "round",
|
|
1933
|
+
flexDirection: "column",
|
|
1934
|
+
marginTop: 1,
|
|
1935
|
+
paddingX: 1,
|
|
1936
|
+
children: [
|
|
1937
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
1938
|
+
color: selectedTheme.colors.status,
|
|
1939
|
+
children: [HEADER_PREFIX, " Preview"]
|
|
1940
|
+
}),
|
|
1941
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1942
|
+
color: selectedTheme.colors.secondary,
|
|
1943
|
+
children: "Markdown and code styling follow the selected theme."
|
|
1944
|
+
}),
|
|
1945
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
1946
|
+
"Status accent:",
|
|
1947
|
+
" ",
|
|
1948
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1949
|
+
color: selectedTheme.colors.status,
|
|
1950
|
+
children: "search enabled"
|
|
1951
|
+
})
|
|
1952
|
+
] }),
|
|
1953
|
+
/* @__PURE__ */ jsx(CodeBlock, {
|
|
1954
|
+
code: "const theme = 'preview';",
|
|
1955
|
+
language: "ts",
|
|
1956
|
+
role: "assistant",
|
|
1957
|
+
theme: selectedTheme
|
|
1958
|
+
})
|
|
1959
|
+
]
|
|
1960
|
+
}),
|
|
1961
|
+
/* @__PURE__ */ jsx(Box, {
|
|
1962
|
+
marginTop: 1,
|
|
1963
|
+
children: /* @__PURE__ */ jsx(SelectPromptHint, {
|
|
1964
|
+
message: "Preview theme",
|
|
1965
|
+
escapeLabel: "cancel and restore"
|
|
1966
|
+
})
|
|
1967
|
+
})
|
|
1968
|
+
]
|
|
1969
|
+
});
|
|
1867
1970
|
}
|
|
1868
|
-
|
|
1971
|
+
//#endregion
|
|
1972
|
+
//#region src/components/App/constants.ts
|
|
1973
|
+
var SCREEN = /* @__PURE__ */ function(SCREEN) {
|
|
1974
|
+
SCREEN["CHAT"] = "chat";
|
|
1975
|
+
SCREEN["MODEL_PICKER"] = "model-picker";
|
|
1976
|
+
SCREEN["SEARCH_SETTINGS"] = "search-settings";
|
|
1977
|
+
SCREEN["SESSION_MANAGER"] = "session-manager";
|
|
1978
|
+
SCREEN["THEME_SETTINGS"] = "theme-settings";
|
|
1979
|
+
return SCREEN;
|
|
1980
|
+
}({});
|
|
1981
|
+
//#endregion
|
|
1982
|
+
//#region src/components/App/hooks/useScreenRouter.ts
|
|
1983
|
+
function useScreenRouter() {
|
|
1869
1984
|
const { exit } = useApp();
|
|
1870
|
-
const [
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1985
|
+
const [currentScreen, setScreen] = useState(SCREEN.CHAT);
|
|
1986
|
+
return {
|
|
1987
|
+
currentScreen,
|
|
1988
|
+
setScreen,
|
|
1989
|
+
handleClose: useCallback(() => {
|
|
1990
|
+
setScreen(SCREEN.CHAT);
|
|
1991
|
+
}, []),
|
|
1992
|
+
handleCommand: useCallback((command, callbacks) => {
|
|
1993
|
+
const { onCreateSession, onSetPreviewThemeId, model, theme } = callbacks;
|
|
1994
|
+
switch (command) {
|
|
1995
|
+
case "/session":
|
|
1996
|
+
setScreen(SCREEN.SESSION_MANAGER);
|
|
1997
|
+
break;
|
|
1998
|
+
case "/model":
|
|
1999
|
+
setScreen(SCREEN.MODEL_PICKER);
|
|
2000
|
+
break;
|
|
2001
|
+
case "/search":
|
|
2002
|
+
setScreen(SCREEN.SEARCH_SETTINGS);
|
|
2003
|
+
break;
|
|
2004
|
+
case "/theme":
|
|
2005
|
+
onSetPreviewThemeId(theme);
|
|
2006
|
+
setScreen(SCREEN.THEME_SETTINGS);
|
|
2007
|
+
break;
|
|
2008
|
+
case "/clear": {
|
|
2009
|
+
resetSystemMessage();
|
|
2010
|
+
const nextSession = onCreateSession(model);
|
|
2011
|
+
setScreen(SCREEN.CHAT);
|
|
2012
|
+
clear(nextSession.metadata.id);
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
case "/exit":
|
|
2016
|
+
exit();
|
|
2017
|
+
break;
|
|
2018
|
+
}
|
|
2019
|
+
}, [exit])
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
//#endregion
|
|
2023
|
+
//#region src/components/App/hooks/useSessionManager.ts
|
|
2024
|
+
function useSessionManager({ sessionId, model, commandColor }) {
|
|
2025
|
+
const [activeSession, setSession] = useState(() => sessionId ? loadSession(sessionId) : createSession(model));
|
|
1875
2026
|
const sessionRef = useRef(activeSession);
|
|
2027
|
+
const commandColorRef = useRef(commandColor);
|
|
2028
|
+
const modelRef = useRef(model);
|
|
1876
2029
|
useEffect(() => {
|
|
1877
2030
|
sessionRef.current = activeSession;
|
|
1878
2031
|
}, [activeSession]);
|
|
2032
|
+
useEffect(() => {
|
|
2033
|
+
commandColorRef.current = commandColor;
|
|
2034
|
+
}, [commandColor]);
|
|
2035
|
+
useEffect(() => {
|
|
2036
|
+
modelRef.current = model;
|
|
2037
|
+
}, [model]);
|
|
1879
2038
|
useEffect(() => {
|
|
1880
2039
|
return () => {
|
|
1881
2040
|
const currentSession = sessionRef.current;
|
|
1882
|
-
if (!deleteSessionIfEmpty(currentSession.metadata.id) && currentSession.messages.length > 0) write(`Resume session: ${color(`code-ollama resume ${currentSession.metadata.id}`,
|
|
2041
|
+
if (!deleteSessionIfEmpty(currentSession.metadata.id) && currentSession.messages.length > 0) write(`Resume session: ${color(`code-ollama resume ${currentSession.metadata.id}`, commandColorRef.current)}\n`);
|
|
1883
2042
|
};
|
|
1884
2043
|
}, []);
|
|
1885
2044
|
const setActiveSession = useCallback((nextSession) => {
|
|
@@ -1888,73 +2047,81 @@ function App({ sessionId }) {
|
|
|
1888
2047
|
return nextSession;
|
|
1889
2048
|
});
|
|
1890
2049
|
}, []);
|
|
1891
|
-
|
|
1892
|
-
|
|
2050
|
+
return {
|
|
2051
|
+
activeSession,
|
|
2052
|
+
sessionRef,
|
|
2053
|
+
setActiveSession,
|
|
2054
|
+
setSession,
|
|
2055
|
+
handleCreateSession: useCallback(() => {
|
|
2056
|
+
const nextSession = createSession(modelRef.current);
|
|
2057
|
+
setActiveSession(nextSession);
|
|
2058
|
+
clear(nextSession.metadata.id);
|
|
2059
|
+
return nextSession;
|
|
2060
|
+
}, [setActiveSession]),
|
|
2061
|
+
handleOpenSession: useCallback((sessionId) => {
|
|
2062
|
+
if (sessionRef.current.metadata.id === sessionId) return false;
|
|
2063
|
+
setActiveSession(loadSession(sessionId));
|
|
2064
|
+
clear(sessionId);
|
|
2065
|
+
return true;
|
|
2066
|
+
}, [setActiveSession]),
|
|
2067
|
+
handleDeleteSession: useCallback((sessionId) => {
|
|
2068
|
+
deleteSession(sessionId);
|
|
2069
|
+
setSession((current) => {
|
|
2070
|
+
if (current.metadata.id !== sessionId) return current;
|
|
2071
|
+
return createSession(modelRef.current);
|
|
2072
|
+
});
|
|
2073
|
+
}, []),
|
|
2074
|
+
handleMessagesChange: useCallback((messages) => {
|
|
2075
|
+
setSession((current) => {
|
|
2076
|
+
const persistedMessages = messages.filter(({ content }) => content !== TURN_ABORTED_MESSAGE);
|
|
2077
|
+
if (persistedMessages.length <= current.messages.length) return current;
|
|
2078
|
+
let metadata = current.metadata;
|
|
2079
|
+
for (const message of persistedMessages.slice(current.messages.length)) metadata = appendMessage(metadata.id, message, modelRef.current);
|
|
2080
|
+
return {
|
|
2081
|
+
metadata,
|
|
2082
|
+
messages: persistedMessages
|
|
2083
|
+
};
|
|
2084
|
+
});
|
|
2085
|
+
}, [])
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
//#endregion
|
|
2089
|
+
//#region src/components/App/hooks/useThemeSettings.ts
|
|
2090
|
+
function useThemeSettings({ currentTheme, onUpdateConfig, setScreen }) {
|
|
2091
|
+
const [previewThemeId, setPreviewThemeId] = useState(null);
|
|
2092
|
+
const activeThemeId = previewThemeId ?? currentTheme;
|
|
2093
|
+
const activeTheme = getTheme(activeThemeId);
|
|
2094
|
+
const handleThemePreview = useCallback((themeId) => {
|
|
2095
|
+
setPreviewThemeId(themeId);
|
|
1893
2096
|
}, []);
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
let metadata = current.metadata;
|
|
1923
|
-
for (const message of persistedMessages.slice(current.messages.length)) metadata = appendMessage(metadata.id, message, appConfig.model);
|
|
1924
|
-
return {
|
|
1925
|
-
metadata,
|
|
1926
|
-
messages: persistedMessages
|
|
1927
|
-
};
|
|
1928
|
-
});
|
|
1929
|
-
}, [appConfig.model]);
|
|
1930
|
-
const handleCommand = useCallback((command) => {
|
|
1931
|
-
switch (command) {
|
|
1932
|
-
case "/session":
|
|
1933
|
-
setScreen("session-manager");
|
|
1934
|
-
break;
|
|
1935
|
-
case "/model":
|
|
1936
|
-
setScreen("model-picker");
|
|
1937
|
-
break;
|
|
1938
|
-
case "/search":
|
|
1939
|
-
setScreen("search-settings");
|
|
1940
|
-
break;
|
|
1941
|
-
case "/clear": {
|
|
1942
|
-
resetSystemMessage();
|
|
1943
|
-
setScreen("chat");
|
|
1944
|
-
const nextSession = createSession$1(appConfig.model);
|
|
1945
|
-
setActiveSession(nextSession);
|
|
1946
|
-
clear(nextSession.metadata.id);
|
|
1947
|
-
break;
|
|
1948
|
-
}
|
|
1949
|
-
case "/exit":
|
|
1950
|
-
exit();
|
|
1951
|
-
break;
|
|
1952
|
-
}
|
|
1953
|
-
}, [
|
|
1954
|
-
appConfig.model,
|
|
1955
|
-
exit,
|
|
1956
|
-
setActiveSession
|
|
1957
|
-
]);
|
|
2097
|
+
return {
|
|
2098
|
+
activeTheme,
|
|
2099
|
+
activeThemeId,
|
|
2100
|
+
handleThemeClose: useCallback(() => {
|
|
2101
|
+
setPreviewThemeId(null);
|
|
2102
|
+
setScreen(SCREEN.CHAT);
|
|
2103
|
+
}, [setScreen]),
|
|
2104
|
+
handleThemePreview,
|
|
2105
|
+
handleThemeSave: useCallback((themeId) => {
|
|
2106
|
+
setPreviewThemeId(null);
|
|
2107
|
+
onUpdateConfig({ theme: themeId });
|
|
2108
|
+
}, [onUpdateConfig]),
|
|
2109
|
+
previewThemeId,
|
|
2110
|
+
setPreviewThemeId
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
//#endregion
|
|
2114
|
+
//#region src/components/App/App.tsx
|
|
2115
|
+
function App({ sessionId }) {
|
|
2116
|
+
const [appConfig, setConfig] = useState(() => loadConfig());
|
|
2117
|
+
const [mode, setMode] = useState(SAFE);
|
|
2118
|
+
const [isHeaderLoaded, setIsHeaderLoaded] = useState(false);
|
|
2119
|
+
const { currentScreen, setScreen, handleClose, handleCommand } = useScreenRouter();
|
|
2120
|
+
const { activeSession, setSession, handleCreateSession, handleOpenSession, handleDeleteSession, handleMessagesChange } = useSessionManager({
|
|
2121
|
+
sessionId,
|
|
2122
|
+
model: appConfig.model,
|
|
2123
|
+
commandColor: getTheme(appConfig.theme).colors.command
|
|
2124
|
+
});
|
|
1958
2125
|
const handleUpdateConfig = useCallback((update) => {
|
|
1959
2126
|
setConfig((current) => ({
|
|
1960
2127
|
...current,
|
|
@@ -1966,10 +2133,15 @@ function App({ sessionId }) {
|
|
|
1966
2133
|
...current,
|
|
1967
2134
|
metadata: updateSessionModel(current.metadata.id, newModel)
|
|
1968
2135
|
}));
|
|
1969
|
-
setScreen(
|
|
1970
|
-
}, []);
|
|
1971
|
-
const
|
|
1972
|
-
|
|
2136
|
+
setScreen(SCREEN.CHAT);
|
|
2137
|
+
}, [setScreen, setSession]);
|
|
2138
|
+
const { activeTheme, handleThemeClose, handleThemePreview, handleThemeSave, setPreviewThemeId } = useThemeSettings({
|
|
2139
|
+
currentTheme: appConfig.theme,
|
|
2140
|
+
onUpdateConfig: handleUpdateConfig,
|
|
2141
|
+
setScreen
|
|
2142
|
+
});
|
|
2143
|
+
const handleHeaderLoad = useCallback(() => {
|
|
2144
|
+
setIsHeaderLoaded(true);
|
|
1973
2145
|
}, []);
|
|
1974
2146
|
const handleToggleMode = useCallback(() => {
|
|
1975
2147
|
setMode((mode) => {
|
|
@@ -1981,40 +2153,78 @@ function App({ sessionId }) {
|
|
|
1981
2153
|
}
|
|
1982
2154
|
});
|
|
1983
2155
|
}, []);
|
|
2156
|
+
const handleChatCommand = useCallback((command) => {
|
|
2157
|
+
handleCommand(command, {
|
|
2158
|
+
model: appConfig.model,
|
|
2159
|
+
theme: appConfig.theme,
|
|
2160
|
+
onCreateSession: handleCreateSession,
|
|
2161
|
+
onSetPreviewThemeId: setPreviewThemeId
|
|
2162
|
+
});
|
|
2163
|
+
}, [
|
|
2164
|
+
appConfig.model,
|
|
2165
|
+
appConfig.theme,
|
|
2166
|
+
handleCommand,
|
|
2167
|
+
handleCreateSession,
|
|
2168
|
+
setPreviewThemeId
|
|
2169
|
+
]);
|
|
2170
|
+
const handleDeleteSessionAndStay = useCallback((sid) => {
|
|
2171
|
+
handleDeleteSession(sid);
|
|
2172
|
+
setScreen(SCREEN.SESSION_MANAGER);
|
|
2173
|
+
}, [handleDeleteSession, setScreen]);
|
|
2174
|
+
const handleOpenSessionAndNavigate = useCallback((sid) => {
|
|
2175
|
+
handleOpenSession(sid);
|
|
2176
|
+
setScreen(SCREEN.CHAT);
|
|
2177
|
+
}, [handleOpenSession, setScreen]);
|
|
2178
|
+
const handleCreateSessionAndNavigate = useCallback(() => {
|
|
2179
|
+
handleCreateSession();
|
|
2180
|
+
setScreen(SCREEN.CHAT);
|
|
2181
|
+
}, [handleCreateSession, setScreen]);
|
|
1984
2182
|
let screenContent;
|
|
1985
2183
|
switch (currentScreen) {
|
|
1986
|
-
case
|
|
2184
|
+
case SCREEN.MODEL_PICKER:
|
|
1987
2185
|
screenContent = /* @__PURE__ */ jsx(ModelPicker, {
|
|
1988
2186
|
currentModel: appConfig.model,
|
|
1989
2187
|
onSelect: handleUpdateConfig,
|
|
1990
|
-
onClose: handleClose
|
|
2188
|
+
onClose: handleClose,
|
|
2189
|
+
theme: activeTheme
|
|
1991
2190
|
});
|
|
1992
2191
|
break;
|
|
1993
|
-
case
|
|
2192
|
+
case SCREEN.SEARCH_SETTINGS:
|
|
1994
2193
|
screenContent = /* @__PURE__ */ jsx(SearchSettings, {
|
|
1995
2194
|
currentUrl: appConfig.searxngBaseUrl,
|
|
1996
2195
|
onSave: handleUpdateConfig,
|
|
1997
|
-
onClose: handleClose
|
|
2196
|
+
onClose: handleClose,
|
|
2197
|
+
theme: activeTheme
|
|
1998
2198
|
});
|
|
1999
2199
|
break;
|
|
2000
|
-
case
|
|
2200
|
+
case SCREEN.SESSION_MANAGER:
|
|
2001
2201
|
screenContent = /* @__PURE__ */ jsx(SessionManager, {
|
|
2002
2202
|
currentSessionId: activeSession.metadata.id,
|
|
2003
2203
|
onClose: handleClose,
|
|
2004
|
-
onDelete:
|
|
2005
|
-
onNew:
|
|
2006
|
-
onOpen:
|
|
2204
|
+
onDelete: handleDeleteSessionAndStay,
|
|
2205
|
+
onNew: handleCreateSessionAndNavigate,
|
|
2206
|
+
onOpen: handleOpenSessionAndNavigate,
|
|
2207
|
+
theme: activeTheme
|
|
2208
|
+
});
|
|
2209
|
+
break;
|
|
2210
|
+
case SCREEN.THEME_SETTINGS:
|
|
2211
|
+
screenContent = /* @__PURE__ */ jsx(ThemeSettings, {
|
|
2212
|
+
currentTheme: appConfig.theme,
|
|
2213
|
+
onClose: handleThemeClose,
|
|
2214
|
+
onPreview: handleThemePreview,
|
|
2215
|
+
onSave: handleThemeSave
|
|
2007
2216
|
});
|
|
2008
2217
|
break;
|
|
2009
|
-
case
|
|
2218
|
+
case SCREEN.CHAT:
|
|
2010
2219
|
screenContent = /* @__PURE__ */ jsx(Chat, {
|
|
2011
2220
|
initialMessages: activeSession.messages,
|
|
2012
2221
|
model: appConfig.model,
|
|
2013
|
-
onCommand:
|
|
2222
|
+
onCommand: handleChatCommand,
|
|
2014
2223
|
onMessagesChange: handleMessagesChange,
|
|
2015
2224
|
mode,
|
|
2016
2225
|
onModeChange: setMode,
|
|
2017
|
-
sessionId: activeSession.metadata.id
|
|
2226
|
+
sessionId: activeSession.metadata.id,
|
|
2227
|
+
theme: activeTheme
|
|
2018
2228
|
});
|
|
2019
2229
|
break;
|
|
2020
2230
|
}
|
|
@@ -2023,13 +2233,15 @@ function App({ sessionId }) {
|
|
|
2023
2233
|
children: [
|
|
2024
2234
|
/* @__PURE__ */ jsx(Header, {
|
|
2025
2235
|
model: appConfig.model,
|
|
2026
|
-
onLoad: handleHeaderLoad
|
|
2236
|
+
onLoad: handleHeaderLoad,
|
|
2237
|
+
theme: activeTheme
|
|
2027
2238
|
}),
|
|
2028
2239
|
isHeaderLoaded && screenContent,
|
|
2029
2240
|
/* @__PURE__ */ jsx(Footer, {
|
|
2030
2241
|
mode,
|
|
2031
2242
|
model: appConfig.model,
|
|
2032
|
-
onToggleMode: handleToggleMode
|
|
2243
|
+
onToggleMode: handleToggleMode,
|
|
2244
|
+
theme: activeTheme
|
|
2033
2245
|
})
|
|
2034
2246
|
]
|
|
2035
2247
|
});
|