@makefinks/daemon 0.9.1 → 0.11.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/README.md +60 -14
- package/package.json +4 -2
- package/src/ai/copilot-client.ts +775 -0
- package/src/ai/daemon-ai.ts +32 -234
- package/src/ai/model-config.ts +55 -14
- package/src/ai/providers/capabilities.ts +16 -0
- package/src/ai/providers/copilot-provider.ts +632 -0
- package/src/ai/providers/openrouter-provider.ts +217 -0
- package/src/ai/providers/registry.ts +14 -0
- package/src/ai/providers/types.ts +31 -0
- package/src/ai/system-prompt.ts +16 -0
- package/src/ai/tools/subagents.ts +1 -1
- package/src/ai/tools/tool-registry.ts +22 -1
- package/src/ai/tools/write-file.ts +51 -0
- package/src/app/components/AppOverlays.tsx +9 -1
- package/src/app/components/ConversationPane.tsx +8 -2
- package/src/components/ModelMenu.tsx +202 -140
- package/src/components/OnboardingOverlay.tsx +147 -1
- package/src/components/SettingsMenu.tsx +27 -1
- package/src/components/TokenUsageDisplay.tsx +5 -3
- package/src/components/tool-layouts/layouts/index.ts +1 -0
- package/src/components/tool-layouts/layouts/write-file.tsx +117 -0
- package/src/hooks/daemon-event-handlers.ts +61 -14
- package/src/hooks/keyboard-handlers.ts +109 -28
- package/src/hooks/use-app-callbacks.ts +141 -43
- package/src/hooks/use-app-context-builder.ts +5 -0
- package/src/hooks/use-app-controller.ts +31 -2
- package/src/hooks/use-app-copilot-models-loader.ts +45 -0
- package/src/hooks/use-app-display-state.ts +24 -2
- package/src/hooks/use-app-model.ts +103 -17
- package/src/hooks/use-app-preferences-bootstrap.ts +54 -10
- package/src/hooks/use-bootstrap-controller.ts +5 -0
- package/src/hooks/use-daemon-events.ts +8 -2
- package/src/hooks/use-daemon-keyboard.ts +19 -6
- package/src/hooks/use-daemon-runtime-controller.ts +4 -0
- package/src/hooks/use-menu-keyboard.ts +6 -1
- package/src/state/app-context.tsx +6 -0
- package/src/types/index.ts +24 -1
- package/src/utils/copilot-models.ts +77 -0
- package/src/utils/preferences.ts +3 -0
|
@@ -2,7 +2,7 @@ import type { ScrollBoxRenderable, TextareaRenderable } from "@opentui/core";
|
|
|
2
2
|
import { useKeyboard } from "@opentui/react";
|
|
3
3
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { useMenuKeyboard } from "../hooks/use-menu-keyboard";
|
|
5
|
-
import type { ModelOption } from "../types";
|
|
5
|
+
import type { LlmProvider, ModelOption } from "../types";
|
|
6
6
|
import { COLORS } from "../ui/constants";
|
|
7
7
|
import { formatContextWindowK, formatPrice } from "../utils/formatters";
|
|
8
8
|
|
|
@@ -20,6 +20,7 @@ const MIN_ALL_MODEL_QUERY_LENGTH = 3;
|
|
|
20
20
|
interface ModelMenuProps {
|
|
21
21
|
curatedModels: ModelOption[];
|
|
22
22
|
allModels: ModelOption[];
|
|
23
|
+
modelProvider: LlmProvider;
|
|
23
24
|
allModelsLoading: boolean;
|
|
24
25
|
allModelsUpdatedAt: number | null;
|
|
25
26
|
currentModelId: string;
|
|
@@ -36,6 +37,7 @@ function formatUpdatedAt(timestamp: number | null): string {
|
|
|
36
37
|
export function ModelMenu({
|
|
37
38
|
curatedModels,
|
|
38
39
|
allModels,
|
|
40
|
+
modelProvider,
|
|
39
41
|
allModelsLoading,
|
|
40
42
|
allModelsUpdatedAt,
|
|
41
43
|
currentModelId,
|
|
@@ -46,35 +48,38 @@ export function ModelMenu({
|
|
|
46
48
|
const [searchQuery, setSearchQuery] = useState("");
|
|
47
49
|
const [isSearchFocused, setIsSearchFocused] = useState(false);
|
|
48
50
|
const searchInputRef = useRef<TextareaRenderable | null>(null);
|
|
51
|
+
const isCopilotProvider = modelProvider === "copilot";
|
|
49
52
|
|
|
50
53
|
const sortedCurated = useMemo(() => {
|
|
54
|
+
if (isCopilotProvider) return [];
|
|
51
55
|
return [...curatedModels].sort((a, b) => {
|
|
52
56
|
const priceA = a.pricing ? a.pricing.prompt + a.pricing.completion : Number.MAX_SAFE_INTEGER;
|
|
53
57
|
const priceB = b.pricing ? b.pricing.prompt + b.pricing.completion : Number.MAX_SAFE_INTEGER;
|
|
54
58
|
if (priceA !== priceB) return priceA - priceB;
|
|
55
59
|
return a.name.localeCompare(b.name);
|
|
56
60
|
});
|
|
57
|
-
}, [curatedModels]);
|
|
61
|
+
}, [curatedModels, isCopilotProvider]);
|
|
58
62
|
|
|
59
63
|
const curatedIdSet = useMemo(() => new Set(sortedCurated.map((model) => model.id)), [sortedCurated]);
|
|
60
64
|
|
|
65
|
+
const allModelsWithFallback = useMemo(() => {
|
|
66
|
+
if (!currentModelId) return allModels;
|
|
67
|
+
if (allModels.some((model) => model.id === currentModelId)) return allModels;
|
|
68
|
+
return [...allModels, { id: currentModelId, name: currentModelId }];
|
|
69
|
+
}, [allModels, currentModelId]);
|
|
70
|
+
|
|
61
71
|
const savedModel = useMemo(() => {
|
|
72
|
+
if (isCopilotProvider) return null;
|
|
62
73
|
if (!currentModelId) return null;
|
|
63
74
|
if (curatedIdSet.has(currentModelId)) return null;
|
|
64
|
-
const match =
|
|
75
|
+
const match = allModelsWithFallback.find((model) => model.id === currentModelId);
|
|
65
76
|
return match ?? { id: currentModelId, name: currentModelId };
|
|
66
|
-
}, [
|
|
77
|
+
}, [allModelsWithFallback, curatedIdSet, currentModelId, isCopilotProvider]);
|
|
67
78
|
|
|
68
79
|
const savedModels = useMemo(() => (savedModel ? [savedModel] : []), [savedModel]);
|
|
69
80
|
|
|
70
|
-
const allModelsWithFallback = useMemo(() => {
|
|
71
|
-
if (!currentModelId) return allModels;
|
|
72
|
-
if (curatedIdSet.has(currentModelId)) return allModels;
|
|
73
|
-
if (savedModel) return allModels;
|
|
74
|
-
return [...allModels, { id: currentModelId, name: currentModelId }];
|
|
75
|
-
}, [allModels, curatedIdSet, currentModelId, savedModel]);
|
|
76
|
-
|
|
77
81
|
const filteredAllModels = useMemo(() => {
|
|
82
|
+
if (isCopilotProvider) return [];
|
|
78
83
|
const filtered = allModelsWithFallback.filter(
|
|
79
84
|
(model) => !curatedIdSet.has(model.id) && model.id !== savedModel?.id
|
|
80
85
|
);
|
|
@@ -82,63 +87,55 @@ export function ModelMenu({
|
|
|
82
87
|
if (query.length < MIN_ALL_MODEL_QUERY_LENGTH) {
|
|
83
88
|
return [];
|
|
84
89
|
}
|
|
90
|
+
const matching = filtered.filter(
|
|
91
|
+
(model) => model.name.toLowerCase().includes(query) || model.id.toLowerCase().includes(query)
|
|
92
|
+
);
|
|
93
|
+
return matching.sort((a, b) => a.name.localeCompare(b.name));
|
|
94
|
+
}, [allModelsWithFallback, curatedIdSet, isCopilotProvider, savedModel?.id, searchQuery]);
|
|
95
|
+
|
|
96
|
+
const copilotModels = useMemo(() => {
|
|
97
|
+
if (!isCopilotProvider) return [];
|
|
98
|
+
const query = searchQuery.trim().toLowerCase();
|
|
85
99
|
const matching = query
|
|
86
|
-
?
|
|
100
|
+
? allModelsWithFallback.filter(
|
|
87
101
|
(model) => model.name.toLowerCase().includes(query) || model.id.toLowerCase().includes(query)
|
|
88
102
|
)
|
|
89
|
-
:
|
|
103
|
+
: allModelsWithFallback;
|
|
104
|
+
return [...matching].sort((a, b) => a.name.localeCompare(b.name));
|
|
105
|
+
}, [allModelsWithFallback, isCopilotProvider, searchQuery]);
|
|
90
106
|
|
|
91
|
-
|
|
92
|
-
|
|
107
|
+
const menuItems = useMemo(() => {
|
|
108
|
+
if (isCopilotProvider) return copilotModels;
|
|
109
|
+
return [...sortedCurated, ...savedModels, ...filteredAllModels];
|
|
110
|
+
}, [copilotModels, filteredAllModels, isCopilotProvider, savedModels, sortedCurated]);
|
|
93
111
|
|
|
94
|
-
const totalItems =
|
|
112
|
+
const totalItems = menuItems.length;
|
|
95
113
|
|
|
96
114
|
const initialIndex = useMemo(() => {
|
|
97
115
|
if (totalItems === 0) return 0;
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (savedIdx >= 0) return sortedCurated.length + savedIdx;
|
|
102
|
-
const allIdx = filteredAllModels.findIndex((model) => model.id === currentModelId);
|
|
103
|
-
if (allIdx >= 0) return sortedCurated.length + savedModels.length + allIdx;
|
|
104
|
-
return 0;
|
|
105
|
-
}, [sortedCurated, savedModels, filteredAllModels, currentModelId, totalItems]);
|
|
116
|
+
const idx = menuItems.findIndex((model) => model.id === currentModelId);
|
|
117
|
+
return idx >= 0 ? idx : 0;
|
|
118
|
+
}, [currentModelId, menuItems, totalItems]);
|
|
106
119
|
|
|
107
120
|
const { selectedIndex } = useMenuKeyboard({
|
|
108
121
|
itemCount: totalItems,
|
|
109
122
|
initialIndex,
|
|
110
123
|
onClose,
|
|
111
124
|
onSelect: (selectedIdx) => {
|
|
112
|
-
|
|
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];
|
|
125
|
+
const model = menuItems[selectedIdx];
|
|
130
126
|
if (model) {
|
|
131
127
|
onSelect(model);
|
|
132
128
|
}
|
|
133
129
|
},
|
|
134
130
|
enableViKeys: !isSearchFocused,
|
|
135
131
|
ignoreEscape: isSearchFocused,
|
|
132
|
+
disabled: isSearchFocused,
|
|
136
133
|
});
|
|
137
134
|
|
|
138
135
|
useKeyboard((key) => {
|
|
139
136
|
if (key.eventType !== "press") return;
|
|
140
137
|
|
|
141
|
-
if (!isSearchFocused && (key.name === "r" || key.sequence?.toLowerCase() === "r")) {
|
|
138
|
+
if (!isCopilotProvider && !isSearchFocused && (key.name === "r" || key.sequence?.toLowerCase() === "r")) {
|
|
142
139
|
onRefreshAllModels();
|
|
143
140
|
key.preventDefault();
|
|
144
141
|
return;
|
|
@@ -151,13 +148,16 @@ export function ModelMenu({
|
|
|
151
148
|
}
|
|
152
149
|
});
|
|
153
150
|
|
|
154
|
-
const
|
|
151
|
+
const scrollModels = isCopilotProvider ? copilotModels : filteredAllModels;
|
|
152
|
+
const allSelectedIndex = isCopilotProvider
|
|
153
|
+
? selectedIndex
|
|
154
|
+
: selectedIndex - sortedCurated.length - savedModels.length;
|
|
155
155
|
const isAllSectionSelected = allSelectedIndex >= 0;
|
|
156
156
|
|
|
157
157
|
const scrollRef = useRef<ScrollBoxRenderable | null>(null);
|
|
158
158
|
const scrollboxHeight = Math.min(
|
|
159
159
|
MAX_ALL_SCROLLBOX_HEIGHT,
|
|
160
|
-
Math.max(ALL_MODEL_ITEM_HEIGHT,
|
|
160
|
+
Math.max(ALL_MODEL_ITEM_HEIGHT, scrollModels.length * ALL_MODEL_ITEM_HEIGHT)
|
|
161
161
|
);
|
|
162
162
|
|
|
163
163
|
useEffect(() => {
|
|
@@ -184,9 +184,10 @@ export function ModelMenu({
|
|
|
184
184
|
if (nextTop !== currentTop) {
|
|
185
185
|
scrollbox.scrollTop = nextTop;
|
|
186
186
|
}
|
|
187
|
-
}, [allSelectedIndex,
|
|
187
|
+
}, [allSelectedIndex, isAllSectionSelected, scrollModels.length]);
|
|
188
188
|
|
|
189
189
|
const updatedAtLabel = formatUpdatedAt(allModelsUpdatedAt);
|
|
190
|
+
const needsSearchHint = !isCopilotProvider && searchQuery.trim().length < MIN_ALL_MODEL_QUERY_LENGTH;
|
|
190
191
|
|
|
191
192
|
const renderModelRow = (model: ModelOption, isSelected: boolean, isCurrent: boolean) => {
|
|
192
193
|
const pricing = model.pricing;
|
|
@@ -262,7 +263,10 @@ export function ModelMenu({
|
|
|
262
263
|
</box>
|
|
263
264
|
<box marginBottom={1}>
|
|
264
265
|
<text>
|
|
265
|
-
<span fg={COLORS.USER_LABEL}
|
|
266
|
+
<span fg={COLORS.USER_LABEL}>
|
|
267
|
+
↑/↓ or j/k navigate · ENTER select
|
|
268
|
+
{isCopilotProvider ? "" : " · R refresh"} · ESC cancel
|
|
269
|
+
</span>
|
|
266
270
|
</text>
|
|
267
271
|
</box>
|
|
268
272
|
<box marginBottom={1}>
|
|
@@ -273,7 +277,7 @@ export function ModelMenu({
|
|
|
273
277
|
|
|
274
278
|
<box marginBottom={0}>
|
|
275
279
|
<text>
|
|
276
|
-
<span fg={COLORS.USER_LABEL}>— SEARCH
|
|
280
|
+
<span fg={COLORS.USER_LABEL}>— SEARCH MODELS —</span>
|
|
277
281
|
</text>
|
|
278
282
|
</box>
|
|
279
283
|
|
|
@@ -337,118 +341,176 @@ export function ModelMenu({
|
|
|
337
341
|
</box>
|
|
338
342
|
) : null}
|
|
339
343
|
|
|
340
|
-
|
|
341
|
-
<text>
|
|
342
|
-
<span fg={COLORS.DAEMON_LABEL}>[ RECOMMENDED ]</span>
|
|
343
|
-
</text>
|
|
344
|
-
</box>
|
|
345
|
-
|
|
346
|
-
{sortedCurated.length === 0 ? (
|
|
347
|
-
<box marginBottom={1} paddingLeft={1}>
|
|
348
|
-
<text>
|
|
349
|
-
<span fg={COLORS.REASONING_DIM}>No curated models available</span>
|
|
350
|
-
</text>
|
|
351
|
-
</box>
|
|
352
|
-
) : (
|
|
344
|
+
{isCopilotProvider ? (
|
|
353
345
|
<>
|
|
354
|
-
<box marginBottom={1}>
|
|
355
|
-
<
|
|
356
|
-
<
|
|
357
|
-
|
|
358
|
-
|
|
346
|
+
<box marginBottom={1} marginTop={1}>
|
|
347
|
+
<text>
|
|
348
|
+
<span fg={COLORS.DAEMON_LABEL}>[ MODELS ]</span>
|
|
349
|
+
{allModelsLoading ? <span fg={COLORS.REASONING_DIM}> (loading...)</span> : null}
|
|
350
|
+
</text>
|
|
351
|
+
</box>
|
|
352
|
+
{copilotModels.length === 0 ? (
|
|
353
|
+
<box marginTop={0} paddingLeft={1}>
|
|
359
354
|
<text>
|
|
360
355
|
<span fg={COLORS.REASONING_DIM}>
|
|
361
|
-
{"
|
|
362
|
-
{"OUT".padStart(COL_WIDTH.OUT)} {"CACHE".padStart(COL_WIDTH.CACHE)}
|
|
356
|
+
{allModelsLoading ? "Loading models..." : "No models found"}
|
|
363
357
|
</span>
|
|
364
358
|
</text>
|
|
365
359
|
</box>
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
360
|
+
) : (
|
|
361
|
+
<>
|
|
362
|
+
<box marginBottom={1}>
|
|
363
|
+
<box flexDirection="row" justifyContent="space-between">
|
|
364
|
+
<text>
|
|
365
|
+
<span fg={COLORS.REASONING_DIM}>MODEL</span>
|
|
366
|
+
</text>
|
|
367
|
+
<text>
|
|
368
|
+
<span fg={COLORS.REASONING_DIM}>
|
|
369
|
+
{"CTX".padStart(COL_WIDTH.CTX)} {"IN".padStart(COL_WIDTH.IN)}{" "}
|
|
370
|
+
{"OUT".padStart(COL_WIDTH.OUT)} {"CACHE".padStart(COL_WIDTH.CACHE)}
|
|
371
|
+
</span>
|
|
372
|
+
</text>
|
|
373
|
+
</box>
|
|
374
|
+
</box>
|
|
375
|
+
<scrollbox
|
|
376
|
+
ref={scrollRef}
|
|
377
|
+
height={scrollboxHeight}
|
|
378
|
+
alignSelf="flex-start"
|
|
379
|
+
focused={false}
|
|
380
|
+
scrollY={true}
|
|
381
|
+
scrollX={false}
|
|
382
|
+
style={{
|
|
383
|
+
rootOptions: { backgroundColor: COLORS.MENU_BG },
|
|
384
|
+
wrapperOptions: { backgroundColor: COLORS.MENU_BG },
|
|
385
|
+
viewportOptions: { backgroundColor: COLORS.MENU_BG },
|
|
386
|
+
contentOptions: { backgroundColor: COLORS.MENU_BG },
|
|
387
|
+
}}
|
|
388
|
+
>
|
|
389
|
+
<box flexDirection="column">
|
|
390
|
+
{copilotModels.map((model, idx) =>
|
|
391
|
+
renderModelRow(model, idx === selectedIndex, model.id === currentModelId)
|
|
392
|
+
)}
|
|
393
|
+
</box>
|
|
394
|
+
</scrollbox>
|
|
395
|
+
</>
|
|
396
|
+
)}
|
|
372
397
|
</>
|
|
373
|
-
)
|
|
374
|
-
|
|
375
|
-
{savedModels.length > 0 ? (
|
|
398
|
+
) : (
|
|
376
399
|
<>
|
|
377
400
|
<box marginBottom={1} marginTop={1}>
|
|
378
401
|
<text>
|
|
379
|
-
<span fg={COLORS.DAEMON_LABEL}>[
|
|
402
|
+
<span fg={COLORS.DAEMON_LABEL}>[ RECOMMENDED ]</span>
|
|
380
403
|
</text>
|
|
381
404
|
</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
405
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
<span fg={COLORS.DAEMON_LABEL}>[ ALL MODELS ]</span>
|
|
397
|
-
{allModelsLoading ? <span fg={COLORS.REASONING_DIM}> (refreshing...)</span> : null}
|
|
398
|
-
</text>
|
|
399
|
-
</box>
|
|
400
|
-
|
|
401
|
-
{filteredAllModels.length === 0 ? (
|
|
402
|
-
<box marginTop={0} paddingLeft={1}>
|
|
403
|
-
<text>
|
|
404
|
-
<span fg={COLORS.REASONING_DIM}>
|
|
405
|
-
{searchQuery.trim().length < MIN_ALL_MODEL_QUERY_LENGTH
|
|
406
|
-
? `Type ${MIN_ALL_MODEL_QUERY_LENGTH}+ characters to search`
|
|
407
|
-
: allModelsLoading
|
|
408
|
-
? "Loading models..."
|
|
409
|
-
: "No models found"}
|
|
410
|
-
</span>
|
|
411
|
-
</text>
|
|
412
|
-
</box>
|
|
413
|
-
) : (
|
|
414
|
-
<>
|
|
415
|
-
<box marginBottom={1}>
|
|
416
|
-
<box flexDirection="row" justifyContent="space-between">
|
|
406
|
+
{sortedCurated.length === 0 ? (
|
|
407
|
+
<box marginBottom={1} paddingLeft={1}>
|
|
417
408
|
<text>
|
|
418
|
-
<span fg={COLORS.REASONING_DIM}>
|
|
409
|
+
<span fg={COLORS.REASONING_DIM}>No curated models available</span>
|
|
419
410
|
</text>
|
|
411
|
+
</box>
|
|
412
|
+
) : (
|
|
413
|
+
<>
|
|
414
|
+
<box marginBottom={1}>
|
|
415
|
+
<box flexDirection="row" justifyContent="space-between">
|
|
416
|
+
<text>
|
|
417
|
+
<span fg={COLORS.REASONING_DIM}>MODEL</span>
|
|
418
|
+
</text>
|
|
419
|
+
<text>
|
|
420
|
+
<span fg={COLORS.REASONING_DIM}>
|
|
421
|
+
{"CTX".padStart(COL_WIDTH.CTX)} {"IN".padStart(COL_WIDTH.IN)}{" "}
|
|
422
|
+
{"OUT".padStart(COL_WIDTH.OUT)} {"CACHE".padStart(COL_WIDTH.CACHE)}
|
|
423
|
+
</span>
|
|
424
|
+
</text>
|
|
425
|
+
</box>
|
|
426
|
+
</box>
|
|
427
|
+
<box flexDirection="column">
|
|
428
|
+
{sortedCurated.map((model, idx) =>
|
|
429
|
+
renderModelRow(model, idx === selectedIndex, model.id === currentModelId)
|
|
430
|
+
)}
|
|
431
|
+
</box>
|
|
432
|
+
</>
|
|
433
|
+
)}
|
|
434
|
+
|
|
435
|
+
{savedModels.length > 0 ? (
|
|
436
|
+
<>
|
|
437
|
+
<box marginBottom={1} marginTop={1}>
|
|
438
|
+
<text>
|
|
439
|
+
<span fg={COLORS.DAEMON_LABEL}>[ SAVED ]</span>
|
|
440
|
+
</text>
|
|
441
|
+
</box>
|
|
442
|
+
<box flexDirection="column">
|
|
443
|
+
{savedModels.map((model, idx) =>
|
|
444
|
+
renderModelRow(
|
|
445
|
+
model,
|
|
446
|
+
sortedCurated.length + idx === selectedIndex,
|
|
447
|
+
model.id === currentModelId
|
|
448
|
+
)
|
|
449
|
+
)}
|
|
450
|
+
</box>
|
|
451
|
+
</>
|
|
452
|
+
) : null}
|
|
453
|
+
|
|
454
|
+
<box marginBottom={1} marginTop={1}>
|
|
455
|
+
<text>
|
|
456
|
+
<span fg={COLORS.DAEMON_LABEL}>[ ALL MODELS ]</span>
|
|
457
|
+
{allModelsLoading ? <span fg={COLORS.REASONING_DIM}> (refreshing...)</span> : null}
|
|
458
|
+
</text>
|
|
459
|
+
</box>
|
|
460
|
+
|
|
461
|
+
{filteredAllModels.length === 0 ? (
|
|
462
|
+
<box marginTop={0} paddingLeft={1}>
|
|
420
463
|
<text>
|
|
421
464
|
<span fg={COLORS.REASONING_DIM}>
|
|
422
|
-
{
|
|
423
|
-
|
|
465
|
+
{needsSearchHint
|
|
466
|
+
? `Type ${MIN_ALL_MODEL_QUERY_LENGTH}+ characters to search`
|
|
467
|
+
: allModelsLoading
|
|
468
|
+
? "Loading models..."
|
|
469
|
+
: "No models found"}
|
|
424
470
|
</span>
|
|
425
471
|
</text>
|
|
426
472
|
</box>
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
473
|
+
) : (
|
|
474
|
+
<>
|
|
475
|
+
<box marginBottom={1}>
|
|
476
|
+
<box flexDirection="row" justifyContent="space-between">
|
|
477
|
+
<text>
|
|
478
|
+
<span fg={COLORS.REASONING_DIM}>MODEL</span>
|
|
479
|
+
</text>
|
|
480
|
+
<text>
|
|
481
|
+
<span fg={COLORS.REASONING_DIM}>
|
|
482
|
+
{"CTX".padStart(COL_WIDTH.CTX)} {"IN".padStart(COL_WIDTH.IN)}{" "}
|
|
483
|
+
{"OUT".padStart(COL_WIDTH.OUT)} {"CACHE".padStart(COL_WIDTH.CACHE)}
|
|
484
|
+
</span>
|
|
485
|
+
</text>
|
|
486
|
+
</box>
|
|
487
|
+
</box>
|
|
488
|
+
<scrollbox
|
|
489
|
+
ref={scrollRef}
|
|
490
|
+
height={scrollboxHeight}
|
|
491
|
+
alignSelf="flex-start"
|
|
492
|
+
focused={false}
|
|
493
|
+
scrollY={true}
|
|
494
|
+
scrollX={false}
|
|
495
|
+
style={{
|
|
496
|
+
rootOptions: { backgroundColor: COLORS.MENU_BG },
|
|
497
|
+
wrapperOptions: { backgroundColor: COLORS.MENU_BG },
|
|
498
|
+
viewportOptions: { backgroundColor: COLORS.MENU_BG },
|
|
499
|
+
contentOptions: { backgroundColor: COLORS.MENU_BG },
|
|
500
|
+
}}
|
|
501
|
+
>
|
|
502
|
+
<box flexDirection="column">
|
|
503
|
+
{filteredAllModels.map((model, idx) =>
|
|
504
|
+
renderModelRow(
|
|
505
|
+
model,
|
|
506
|
+
sortedCurated.length + savedModels.length + idx === selectedIndex,
|
|
507
|
+
model.id === currentModelId
|
|
508
|
+
)
|
|
509
|
+
)}
|
|
510
|
+
</box>
|
|
511
|
+
</scrollbox>
|
|
512
|
+
</>
|
|
513
|
+
)}
|
|
452
514
|
</>
|
|
453
515
|
)}
|
|
454
516
|
</box>
|