@makefinks/daemon 0.3.1 → 0.4.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/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ScrollBoxRenderable, TextareaRenderable } from "@opentui/core";
|
|
2
2
|
import { useKeyboard } from "@opentui/react";
|
|
3
3
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import type { ModelOption } from "../types";
|
|
5
4
|
import { useMenuKeyboard } from "../hooks/use-menu-keyboard";
|
|
5
|
+
import type { ModelOption } from "../types";
|
|
6
6
|
import { COLORS } from "../ui/constants";
|
|
7
7
|
import { formatContextWindowK, formatPrice } from "../utils/formatters";
|
|
8
8
|
|
|
@@ -58,15 +58,26 @@ export function ModelMenu({
|
|
|
58
58
|
|
|
59
59
|
const curatedIdSet = useMemo(() => new Set(sortedCurated.map((model) => model.id)), [sortedCurated]);
|
|
60
60
|
|
|
61
|
+
const savedModel = useMemo(() => {
|
|
62
|
+
if (!currentModelId) return null;
|
|
63
|
+
if (curatedIdSet.has(currentModelId)) return null;
|
|
64
|
+
const match = allModels.find((model) => model.id === currentModelId);
|
|
65
|
+
return match ?? { id: currentModelId, name: currentModelId };
|
|
66
|
+
}, [allModels, curatedIdSet, currentModelId]);
|
|
67
|
+
|
|
68
|
+
const savedModels = useMemo(() => (savedModel ? [savedModel] : []), [savedModel]);
|
|
69
|
+
|
|
61
70
|
const allModelsWithFallback = useMemo(() => {
|
|
62
71
|
if (!currentModelId) return allModels;
|
|
63
72
|
if (curatedIdSet.has(currentModelId)) return allModels;
|
|
64
|
-
if (
|
|
73
|
+
if (savedModel) return allModels;
|
|
65
74
|
return [...allModels, { id: currentModelId, name: currentModelId }];
|
|
66
|
-
}, [allModels, curatedIdSet, currentModelId]);
|
|
75
|
+
}, [allModels, curatedIdSet, currentModelId, savedModel]);
|
|
67
76
|
|
|
68
77
|
const filteredAllModels = useMemo(() => {
|
|
69
|
-
const filtered = allModelsWithFallback.filter(
|
|
78
|
+
const filtered = allModelsWithFallback.filter(
|
|
79
|
+
(model) => !curatedIdSet.has(model.id) && model.id !== savedModel?.id
|
|
80
|
+
);
|
|
70
81
|
const query = searchQuery.trim().toLowerCase();
|
|
71
82
|
if (query.length < MIN_ALL_MODEL_QUERY_LENGTH) {
|
|
72
83
|
return [];
|
|
@@ -78,28 +89,44 @@ export function ModelMenu({
|
|
|
78
89
|
: filtered;
|
|
79
90
|
|
|
80
91
|
return matching.sort((a, b) => a.name.localeCompare(b.name));
|
|
81
|
-
}, [allModelsWithFallback, curatedIdSet, searchQuery]);
|
|
92
|
+
}, [allModelsWithFallback, curatedIdSet, savedModel?.id, searchQuery]);
|
|
82
93
|
|
|
83
|
-
const totalItems = sortedCurated.length + filteredAllModels.length;
|
|
94
|
+
const totalItems = sortedCurated.length + savedModels.length + filteredAllModels.length;
|
|
84
95
|
|
|
85
96
|
const initialIndex = useMemo(() => {
|
|
86
97
|
if (totalItems === 0) return 0;
|
|
87
98
|
const curatedIdx = sortedCurated.findIndex((model) => model.id === currentModelId);
|
|
88
99
|
if (curatedIdx >= 0) return curatedIdx;
|
|
100
|
+
const savedIdx = savedModels.findIndex((model) => model.id === currentModelId);
|
|
101
|
+
if (savedIdx >= 0) return sortedCurated.length + savedIdx;
|
|
89
102
|
const allIdx = filteredAllModels.findIndex((model) => model.id === currentModelId);
|
|
90
|
-
if (allIdx >= 0) return sortedCurated.length + allIdx;
|
|
103
|
+
if (allIdx >= 0) return sortedCurated.length + savedModels.length + allIdx;
|
|
91
104
|
return 0;
|
|
92
|
-
}, [sortedCurated, filteredAllModels, currentModelId, totalItems]);
|
|
105
|
+
}, [sortedCurated, savedModels, filteredAllModels, currentModelId, totalItems]);
|
|
93
106
|
|
|
94
107
|
const { selectedIndex } = useMenuKeyboard({
|
|
95
108
|
itemCount: totalItems,
|
|
96
109
|
initialIndex,
|
|
97
110
|
onClose,
|
|
98
111
|
onSelect: (selectedIdx) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
112
|
+
if (selectedIdx < sortedCurated.length) {
|
|
113
|
+
const model = sortedCurated[selectedIdx];
|
|
114
|
+
if (model) {
|
|
115
|
+
onSelect(model);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const afterCurated = selectedIdx - sortedCurated.length;
|
|
121
|
+
if (afterCurated < savedModels.length) {
|
|
122
|
+
const model = savedModels[afterCurated];
|
|
123
|
+
if (model) {
|
|
124
|
+
onSelect(model);
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const model = filteredAllModels[afterCurated - savedModels.length];
|
|
103
130
|
if (model) {
|
|
104
131
|
onSelect(model);
|
|
105
132
|
}
|
|
@@ -124,7 +151,7 @@ export function ModelMenu({
|
|
|
124
151
|
}
|
|
125
152
|
});
|
|
126
153
|
|
|
127
|
-
const allSelectedIndex = selectedIndex - sortedCurated.length;
|
|
154
|
+
const allSelectedIndex = selectedIndex - sortedCurated.length - savedModels.length;
|
|
128
155
|
const isAllSectionSelected = allSelectedIndex >= 0;
|
|
129
156
|
|
|
130
157
|
const scrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
@@ -345,6 +372,25 @@ export function ModelMenu({
|
|
|
345
372
|
</>
|
|
346
373
|
)}
|
|
347
374
|
|
|
375
|
+
{savedModels.length > 0 ? (
|
|
376
|
+
<>
|
|
377
|
+
<box marginBottom={1} marginTop={1}>
|
|
378
|
+
<text>
|
|
379
|
+
<span fg={COLORS.DAEMON_LABEL}>[ SAVED ]</span>
|
|
380
|
+
</text>
|
|
381
|
+
</box>
|
|
382
|
+
<box flexDirection="column">
|
|
383
|
+
{savedModels.map((model, idx) =>
|
|
384
|
+
renderModelRow(
|
|
385
|
+
model,
|
|
386
|
+
sortedCurated.length + idx === selectedIndex,
|
|
387
|
+
model.id === currentModelId
|
|
388
|
+
)
|
|
389
|
+
)}
|
|
390
|
+
</box>
|
|
391
|
+
</>
|
|
392
|
+
) : null}
|
|
393
|
+
|
|
348
394
|
<box marginBottom={1} marginTop={1}>
|
|
349
395
|
<text>
|
|
350
396
|
<span fg={COLORS.DAEMON_LABEL}>[ ALL MODELS ]</span>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { setOpenRouterProviderTag, setResponseModel } from "../ai/model-config";
|
|
3
3
|
import type {
|
|
4
4
|
AppPreferences,
|
|
5
5
|
BashApprovalLevel,
|
|
@@ -94,11 +94,8 @@ export function useAppPreferencesBootstrap(
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (prefs?.modelId) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
setResponseModel(prefs.modelId);
|
|
100
|
-
setCurrentModelId(prefs.modelId);
|
|
101
|
-
}
|
|
97
|
+
setResponseModel(prefs.modelId);
|
|
98
|
+
setCurrentModelId(prefs.modelId);
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
if (prefs?.openRouterProviderTag) {
|
|
@@ -62,11 +62,11 @@ export function useReasoningAnimation(): UseReasoningAnimationReturn {
|
|
|
62
62
|
const maxWidth = terminalWidth ? Math.max(20, terminalWidth - 12) : REASONING_ANIMATION.LINE_WIDTH;
|
|
63
63
|
const lineWidth = Math.min(REASONING_ANIMATION.LINE_WIDTH, maxWidth);
|
|
64
64
|
|
|
65
|
-
// Add to display,
|
|
65
|
+
// Add to display, restart when reaching the line width
|
|
66
66
|
setReasoningDisplay((display: string) => {
|
|
67
67
|
const newDisplay = display + movedChars;
|
|
68
|
-
if (newDisplay.length
|
|
69
|
-
return
|
|
68
|
+
if (newDisplay.length >= lineWidth) {
|
|
69
|
+
return movedChars;
|
|
70
70
|
}
|
|
71
71
|
return newDisplay;
|
|
72
72
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TextAttributes } from "@opentui/core";
|
|
1
2
|
import { COLORS, REASONING_ANIMATION } from "./constants";
|
|
2
3
|
|
|
3
4
|
export function renderReasoningTicker(reasoningDisplay: string) {
|
|
@@ -29,7 +30,7 @@ export function renderReasoningTicker(reasoningDisplay: string) {
|
|
|
29
30
|
<text>
|
|
30
31
|
<span fg={REASONING_ANIMATION.PREFIX_COLOR}>{"// "}</span>
|
|
31
32
|
{segments.map((segment, index) => (
|
|
32
|
-
<span fg={segment.color} key={`reasoning-seg-${index}`}>
|
|
33
|
+
<span fg={segment.color} key={`reasoning-seg-${index}`} attributes={TextAttributes.ITALIC}>
|
|
33
34
|
{segment.text}
|
|
34
35
|
</span>
|
|
35
36
|
))}
|