@dexto/tui 1.6.8 → 1.6.9
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/components/overlays/LoginOverlay.cjs +41 -50
- package/dist/components/overlays/LoginOverlay.d.ts.map +1 -1
- package/dist/components/overlays/LoginOverlay.js +43 -44
- package/dist/components/overlays/ModelSelectorRefactored.cjs +543 -221
- package/dist/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/components/overlays/ModelSelectorRefactored.js +553 -223
- package/dist/components/overlays/SessionSelectorRefactored.cjs +3 -0
- package/dist/components/overlays/SessionSelectorRefactored.d.ts.map +1 -1
- package/dist/components/overlays/SessionSelectorRefactored.js +3 -0
- package/dist/containers/OverlayContainer.cjs +35 -3
- package/dist/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/containers/OverlayContainer.js +36 -3
- package/dist/hooks/useInputOrchestrator.cjs +1 -1
- package/dist/hooks/useInputOrchestrator.d.ts.map +1 -1
- package/dist/hooks/useInputOrchestrator.js +1 -1
- package/dist/host/index.cjs +12 -13
- package/dist/host/index.d.ts +23 -15
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js +10 -11
- package/dist/index.d.cts +17 -12
- package/dist/interactive-commands/auth/index.d.ts +1 -1
- package/dist/interactive-commands/commands.cjs +2 -0
- package/dist/interactive-commands/commands.d.ts.map +1 -1
- package/dist/interactive-commands/commands.js +3 -1
- package/dist/interactive-commands/model/index.cjs +1 -1
- package/dist/interactive-commands/model/index.js +1 -1
- package/dist/interactive-commands/session/index.cjs +2 -0
- package/dist/interactive-commands/session/index.d.ts +2 -1
- package/dist/interactive-commands/session/index.d.ts.map +1 -1
- package/dist/interactive-commands/session/index.js +2 -1
- package/dist/interactive-commands/session/session-commands.cjs +26 -0
- package/dist/interactive-commands/session/session-commands.d.ts +5 -0
- package/dist/interactive-commands/session/session-commands.d.ts.map +1 -1
- package/dist/interactive-commands/session/session-commands.js +25 -0
- package/dist/utils/modelOrdering.cjs +106 -0
- package/dist/utils/modelOrdering.d.ts +7 -0
- package/dist/utils/modelOrdering.d.ts.map +1 -0
- package/dist/utils/modelOrdering.js +81 -0
- package/dist/utils/modelOrdering.test.cjs +59 -0
- package/dist/utils/modelOrdering.test.d.ts +2 -0
- package/dist/utils/modelOrdering.test.d.ts.map +1 -0
- package/dist/utils/modelOrdering.test.js +61 -0
- package/package.json +4 -4
|
@@ -29,33 +29,187 @@ var import_core = require("@dexto/core");
|
|
|
29
29
|
var import_agent_management = require("@dexto/agent-management");
|
|
30
30
|
var import_llm_provider_display = require("../../utils/llm-provider-display.js");
|
|
31
31
|
var import_overlaySizing = require("../../utils/overlaySizing.js");
|
|
32
|
+
var import_modelOrdering = require("../../utils/modelOrdering.js");
|
|
33
|
+
var import_textUtils = require("../../utils/textUtils.js");
|
|
32
34
|
var import_HintBar = require("../shared/HintBar.js");
|
|
35
|
+
const FEATURED_SECTION_LIMIT = 8;
|
|
36
|
+
const MODEL_SELECTOR_TABS = [
|
|
37
|
+
{ id: "all-models", label: "All" },
|
|
38
|
+
{ id: "featured", label: "Featured" },
|
|
39
|
+
{ id: "recents", label: "Recents" },
|
|
40
|
+
{ id: "favorites", label: "Favorites" },
|
|
41
|
+
{ id: "custom", label: "Custom" }
|
|
42
|
+
];
|
|
43
|
+
const PROVIDER_COLLATOR = new Intl.Collator("en", { sensitivity: "base" });
|
|
44
|
+
const PROVIDER_TOKEN_PATTERN = /[^a-z0-9]/g;
|
|
45
|
+
function normalizeProviderToken(value) {
|
|
46
|
+
return value.toLowerCase().replace(PROVIDER_TOKEN_PATTERN, "");
|
|
47
|
+
}
|
|
48
|
+
function toReleaseDateLookupKey(provider, modelName) {
|
|
49
|
+
return `${provider}::${modelName.toLowerCase()}`;
|
|
50
|
+
}
|
|
51
|
+
function splitGatewayModelName(modelName) {
|
|
52
|
+
const slashIndex = modelName.indexOf("/");
|
|
53
|
+
if (slashIndex <= 0 || slashIndex >= modelName.length - 1) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
providerPrefix: modelName.slice(0, slashIndex),
|
|
58
|
+
unprefixedName: modelName.slice(slashIndex + 1)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function createReleaseDateResolver({
|
|
62
|
+
allModels,
|
|
63
|
+
providers
|
|
64
|
+
}) {
|
|
65
|
+
const releaseDateByProviderAndName = /* @__PURE__ */ new Map();
|
|
66
|
+
const releaseDateCandidatesByName = /* @__PURE__ */ new Map();
|
|
67
|
+
const latestReleaseDateByName = /* @__PURE__ */ new Map();
|
|
68
|
+
const providerByToken = /* @__PURE__ */ new Map();
|
|
69
|
+
for (const provider of providers) {
|
|
70
|
+
const token = normalizeProviderToken(provider);
|
|
71
|
+
if (token && !providerByToken.has(token)) {
|
|
72
|
+
providerByToken.set(token, provider);
|
|
73
|
+
}
|
|
74
|
+
const modelsForProvider = allModels[provider];
|
|
75
|
+
if (!modelsForProvider || modelsForProvider.length === 0) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
for (const model of modelsForProvider) {
|
|
79
|
+
const releaseDate = model.releaseDate;
|
|
80
|
+
if (!releaseDate) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const lowerName = model.name.toLowerCase();
|
|
84
|
+
releaseDateByProviderAndName.set(
|
|
85
|
+
toReleaseDateLookupKey(provider, lowerName),
|
|
86
|
+
releaseDate
|
|
87
|
+
);
|
|
88
|
+
const existingLatest = latestReleaseDateByName.get(lowerName);
|
|
89
|
+
if (!existingLatest || releaseDate > existingLatest) {
|
|
90
|
+
latestReleaseDateByName.set(lowerName, releaseDate);
|
|
91
|
+
}
|
|
92
|
+
const candidates = releaseDateCandidatesByName.get(lowerName) ?? [];
|
|
93
|
+
candidates.push({ provider, releaseDate });
|
|
94
|
+
releaseDateCandidatesByName.set(lowerName, candidates);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return (provider, modelName, explicitReleaseDate) => {
|
|
98
|
+
if (explicitReleaseDate) {
|
|
99
|
+
return explicitReleaseDate;
|
|
100
|
+
}
|
|
101
|
+
const lowerName = modelName.toLowerCase();
|
|
102
|
+
const sameProviderDate = releaseDateByProviderAndName.get(
|
|
103
|
+
toReleaseDateLookupKey(provider, lowerName)
|
|
104
|
+
);
|
|
105
|
+
if (sameProviderDate) {
|
|
106
|
+
return sameProviderDate;
|
|
107
|
+
}
|
|
108
|
+
const openRouterDate = releaseDateByProviderAndName.get(
|
|
109
|
+
toReleaseDateLookupKey("openrouter", lowerName)
|
|
110
|
+
);
|
|
111
|
+
if (openRouterDate) {
|
|
112
|
+
return openRouterDate;
|
|
113
|
+
}
|
|
114
|
+
const parsedGatewayModel = splitGatewayModelName(modelName);
|
|
115
|
+
if (!parsedGatewayModel) {
|
|
116
|
+
return void 0;
|
|
117
|
+
}
|
|
118
|
+
const unprefixedName = parsedGatewayModel.unprefixedName.toLowerCase();
|
|
119
|
+
const preferredProvider = providerByToken.get(
|
|
120
|
+
normalizeProviderToken(parsedGatewayModel.providerPrefix)
|
|
121
|
+
);
|
|
122
|
+
if (preferredProvider) {
|
|
123
|
+
const providerDate = releaseDateByProviderAndName.get(
|
|
124
|
+
toReleaseDateLookupKey(preferredProvider, unprefixedName)
|
|
125
|
+
);
|
|
126
|
+
if (providerDate) {
|
|
127
|
+
return providerDate;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const candidates = releaseDateCandidatesByName.get(unprefixedName);
|
|
131
|
+
if (candidates && preferredProvider) {
|
|
132
|
+
const preferredProviderCandidate = candidates.find(
|
|
133
|
+
(candidate) => candidate.provider === preferredProvider
|
|
134
|
+
);
|
|
135
|
+
if (preferredProviderCandidate) {
|
|
136
|
+
return preferredProviderCandidate.releaseDate;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return latestReleaseDateByName.get(unprefixedName);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function getNextModelSelectorTab(current) {
|
|
143
|
+
const currentIndex = MODEL_SELECTOR_TABS.findIndex((tab) => tab.id === current);
|
|
144
|
+
const nextIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % MODEL_SELECTOR_TABS.length;
|
|
145
|
+
return MODEL_SELECTOR_TABS[nextIndex]?.id ?? "all-models";
|
|
146
|
+
}
|
|
147
|
+
function getPreviousModelSelectorTab(current) {
|
|
148
|
+
const currentIndex = MODEL_SELECTOR_TABS.findIndex((tab) => tab.id === current);
|
|
149
|
+
const previousIndex = currentIndex < 0 ? 0 : (currentIndex - 1 + MODEL_SELECTOR_TABS.length) % MODEL_SELECTOR_TABS.length;
|
|
150
|
+
return MODEL_SELECTOR_TABS[previousIndex]?.id ?? "all-models";
|
|
151
|
+
}
|
|
152
|
+
function compareModelOptionsForDisplay(left, right) {
|
|
153
|
+
const byRecency = (0, import_modelOrdering.compareModelsLatestFirst)(left, right);
|
|
154
|
+
if (byRecency !== 0) {
|
|
155
|
+
return byRecency;
|
|
156
|
+
}
|
|
157
|
+
const byProvider = PROVIDER_COLLATOR.compare(left.provider, right.provider);
|
|
158
|
+
if (byProvider !== 0) {
|
|
159
|
+
return byProvider;
|
|
160
|
+
}
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
function toModelIdentityKey(model) {
|
|
164
|
+
return (0, import_agent_management.toModelPickerKey)({ provider: model.provider, model: model.name });
|
|
165
|
+
}
|
|
166
|
+
function normalizeLineText(value) {
|
|
167
|
+
return (0, import_textUtils.stripUnsafeCharacters)(value).replace(/\r?\n/g, " ").replace(/\s+/g, " ").trim();
|
|
168
|
+
}
|
|
169
|
+
function formatLineToWidth(value, width) {
|
|
170
|
+
if (width <= 0) return "";
|
|
171
|
+
const normalized = normalizeLineText(value);
|
|
172
|
+
if (!normalized) {
|
|
173
|
+
return " ".repeat(width);
|
|
174
|
+
}
|
|
175
|
+
const normalizedWidth = (0, import_textUtils.getCachedStringWidth)(normalized);
|
|
176
|
+
if (normalizedWidth <= width) {
|
|
177
|
+
return normalized + " ".repeat(width - normalizedWidth);
|
|
178
|
+
}
|
|
179
|
+
if (width === 1) {
|
|
180
|
+
return "\u2026";
|
|
181
|
+
}
|
|
182
|
+
const ellipsis = "\u2026";
|
|
183
|
+
const targetWidth = width - (0, import_textUtils.getCachedStringWidth)(ellipsis);
|
|
184
|
+
let truncated = "";
|
|
185
|
+
for (const char of (0, import_textUtils.toCodePoints)(normalized)) {
|
|
186
|
+
const candidate = `${truncated}${char}`;
|
|
187
|
+
if ((0, import_textUtils.getCachedStringWidth)(candidate) > targetWidth) {
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
truncated = candidate;
|
|
191
|
+
}
|
|
192
|
+
const withEllipsis = `${truncated}${ellipsis}`;
|
|
193
|
+
const finalWidth = (0, import_textUtils.getCachedStringWidth)(withEllipsis);
|
|
194
|
+
if (finalWidth >= width) {
|
|
195
|
+
return withEllipsis;
|
|
196
|
+
}
|
|
197
|
+
return withEllipsis + " ".repeat(width - finalWidth);
|
|
198
|
+
}
|
|
33
199
|
function isAddCustomOption(item) {
|
|
34
200
|
return "type" in item && item.type === "add-custom";
|
|
35
201
|
}
|
|
202
|
+
function isModelOption(item) {
|
|
203
|
+
return !("type" in item);
|
|
204
|
+
}
|
|
36
205
|
function getRowPrefix({
|
|
37
206
|
isSelected,
|
|
38
207
|
isDefault,
|
|
39
208
|
isCurrent,
|
|
40
|
-
isCustom
|
|
209
|
+
isCustom,
|
|
210
|
+
isFavorite
|
|
41
211
|
}) {
|
|
42
|
-
return `${isSelected ? "\u203A" : " "} ${isDefault ? "\u2713" : " "} ${isCurrent ? "\u25CF" : " "} ${
|
|
43
|
-
}
|
|
44
|
-
function computeNextSelection(currentIndex, itemsLength, viewportItems) {
|
|
45
|
-
const nextIndex = currentIndex;
|
|
46
|
-
let nextOffset = 0;
|
|
47
|
-
const modelsLength = Math.max(0, itemsLength - 1);
|
|
48
|
-
if (nextIndex > 0) {
|
|
49
|
-
const modelIndex = nextIndex - 1;
|
|
50
|
-
if (modelIndex < nextOffset) {
|
|
51
|
-
nextOffset = modelIndex;
|
|
52
|
-
} else if (modelIndex >= nextOffset + viewportItems) {
|
|
53
|
-
nextOffset = Math.max(0, modelIndex - viewportItems + 1);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const maxOffset = Math.max(0, modelsLength - viewportItems);
|
|
57
|
-
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
58
|
-
return { index: nextIndex, offset: nextOffset };
|
|
212
|
+
return `${isSelected ? "\u203A" : " "} ${isDefault ? "\u2713" : " "} ${isCurrent ? "\u25CF" : " "} ${isFavorite ? "\u2605" : isCustom ? "\u25C7" : " "}`;
|
|
59
213
|
}
|
|
60
214
|
const REASONING_VARIANT_DESCRIPTIONS = {
|
|
61
215
|
disabled: "Disable reasoning (fastest)",
|
|
@@ -90,7 +244,8 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
90
244
|
onEditCustomModel,
|
|
91
245
|
agent
|
|
92
246
|
}, ref) {
|
|
93
|
-
const { rows: terminalRows } = (0, import_useTerminalSize.useTerminalSize)();
|
|
247
|
+
const { rows: terminalRows, columns: terminalColumns } = (0, import_useTerminalSize.useTerminalSize)();
|
|
248
|
+
const overlayWidth = (0, import_react.useMemo)(() => Math.max(20, terminalColumns - 2), [terminalColumns]);
|
|
94
249
|
const maxVisibleItems = (0, import_react.useMemo)(() => {
|
|
95
250
|
return (0, import_overlaySizing.getMaxVisibleItemsForTerminalRows)({
|
|
96
251
|
rows: terminalRows,
|
|
@@ -100,6 +255,8 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
100
255
|
}, [terminalRows]);
|
|
101
256
|
const [models, setModels] = (0, import_react.useState)([]);
|
|
102
257
|
const [customModels, setCustomModels] = (0, import_react.useState)([]);
|
|
258
|
+
const [modelPickerState, setModelPickerState] = (0, import_react.useState)(null);
|
|
259
|
+
const [activeTab, setActiveTab] = (0, import_react.useState)("all-models");
|
|
103
260
|
const [isLoading, setIsLoading] = (0, import_react.useState)(false);
|
|
104
261
|
const [selection, setSelection] = (0, import_react.useState)({ index: 0, offset: 0 });
|
|
105
262
|
const [searchQuery, setSearchQuery] = (0, import_react.useState)("");
|
|
@@ -143,6 +300,8 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
143
300
|
setPendingReasoningModel(null);
|
|
144
301
|
setIsSettingDefault(false);
|
|
145
302
|
setReasoningVariantIndex(0);
|
|
303
|
+
setActiveTab("all-models");
|
|
304
|
+
setModelPickerState(null);
|
|
146
305
|
if (deleteTimeoutRef.current) {
|
|
147
306
|
clearTimeout(deleteTimeoutRef.current);
|
|
148
307
|
deleteTimeoutRef.current = null;
|
|
@@ -166,11 +325,13 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
166
325
|
(0, import_agent_management.loadCustomModels)(),
|
|
167
326
|
(0, import_agent_management.loadGlobalPreferences)().catch(() => null)
|
|
168
327
|
]);
|
|
328
|
+
const pickerState = await (0, import_agent_management.loadModelPickerState)().catch(() => null);
|
|
169
329
|
const modelList = [];
|
|
170
330
|
const defaultProvider = preferences?.llm.provider;
|
|
171
331
|
const defaultModel = preferences?.llm.model;
|
|
172
332
|
const defaultBaseURL = preferences?.llm.baseURL;
|
|
173
333
|
const defaultReasoningVariant = preferences?.llm.reasoning?.variant;
|
|
334
|
+
const resolveReleaseDate = createReleaseDateResolver({ allModels, providers });
|
|
174
335
|
let ollamaModels = [];
|
|
175
336
|
let localModels = [];
|
|
176
337
|
try {
|
|
@@ -211,8 +372,16 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
211
372
|
if (provider === "dexto-nova" && !(0, import_agent_management.isDextoAuthEnabled)()) {
|
|
212
373
|
continue;
|
|
213
374
|
}
|
|
214
|
-
const providerModels = allModels[provider];
|
|
375
|
+
const providerModels = [...allModels[provider]].sort(import_modelOrdering.compareModelsLatestFirst);
|
|
215
376
|
for (const model of providerModels) {
|
|
377
|
+
if ((0, import_modelOrdering.isDeprecatedModelStatus)(model.status)) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
const releaseDate = resolveReleaseDate(
|
|
381
|
+
provider,
|
|
382
|
+
model.name,
|
|
383
|
+
model.releaseDate
|
|
384
|
+
);
|
|
216
385
|
const originalProvider = "originalProvider" in model ? model.originalProvider : void 0;
|
|
217
386
|
modelList.push({
|
|
218
387
|
provider,
|
|
@@ -222,6 +391,8 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
222
391
|
isDefault: provider === defaultProvider && model.name === defaultModel,
|
|
223
392
|
isCurrent: provider === currentConfig.provider && model.name === currentConfig.model,
|
|
224
393
|
isCustom: false,
|
|
394
|
+
...releaseDate !== void 0 ? { releaseDate } : {},
|
|
395
|
+
...model.status !== void 0 ? { status: model.status } : {},
|
|
225
396
|
...defaultReasoningVariant && provider === defaultProvider && model.name === defaultModel ? { reasoningVariant: defaultReasoningVariant } : {},
|
|
226
397
|
...defaultBaseURL && provider === defaultProvider && model.name === defaultModel ? { baseURL: defaultBaseURL } : {},
|
|
227
398
|
// Store original provider for display purposes
|
|
@@ -257,7 +428,15 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
257
428
|
}
|
|
258
429
|
const vertexModels = allModels["vertex"];
|
|
259
430
|
if (vertexModels) {
|
|
260
|
-
for (const model of vertexModels) {
|
|
431
|
+
for (const model of [...vertexModels].sort(import_modelOrdering.compareModelsLatestFirst)) {
|
|
432
|
+
if ((0, import_modelOrdering.isDeprecatedModelStatus)(model.status)) {
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const releaseDate = resolveReleaseDate(
|
|
436
|
+
"vertex",
|
|
437
|
+
model.name,
|
|
438
|
+
model.releaseDate
|
|
439
|
+
);
|
|
261
440
|
modelList.push({
|
|
262
441
|
provider: "vertex",
|
|
263
442
|
name: model.name,
|
|
@@ -266,23 +445,73 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
266
445
|
isDefault: defaultProvider === "vertex" && defaultModel === model.name,
|
|
267
446
|
isCurrent: currentConfig.provider === "vertex" && currentConfig.model === model.name,
|
|
268
447
|
isCustom: false,
|
|
448
|
+
...releaseDate !== void 0 ? { releaseDate } : {},
|
|
449
|
+
...model.status !== void 0 ? { status: model.status } : {},
|
|
269
450
|
...defaultReasoningVariant && defaultProvider === "vertex" && defaultModel === model.name ? { reasoningVariant: defaultReasoningVariant } : {}
|
|
270
451
|
});
|
|
271
452
|
}
|
|
272
453
|
}
|
|
273
454
|
if (!cancelled) {
|
|
274
|
-
|
|
455
|
+
const dedupedByKey = /* @__PURE__ */ new Map();
|
|
456
|
+
const dedupeOrder = [];
|
|
457
|
+
for (const model of modelList) {
|
|
458
|
+
const key = toModelIdentityKey(model);
|
|
459
|
+
const existing = dedupedByKey.get(key);
|
|
460
|
+
if (!existing) {
|
|
461
|
+
dedupedByKey.set(key, model);
|
|
462
|
+
dedupeOrder.push(key);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const preferred = model.isCustom && !existing.isCustom ? model : existing;
|
|
466
|
+
const secondary = preferred === existing ? model : existing;
|
|
467
|
+
const mergedBaseURL = preferred.baseURL ?? secondary.baseURL;
|
|
468
|
+
const mergedReasoningVariant = preferred.reasoningVariant ?? secondary.reasoningVariant;
|
|
469
|
+
const mergedOriginalProvider = preferred.originalProvider ?? secondary.originalProvider;
|
|
470
|
+
const mergedReleaseDate = preferred.releaseDate ?? secondary.releaseDate;
|
|
471
|
+
const mergedStatus = preferred.status ?? secondary.status;
|
|
472
|
+
const mergedModel = {
|
|
473
|
+
...preferred,
|
|
474
|
+
isDefault: preferred.isDefault || secondary.isDefault,
|
|
475
|
+
isCurrent: preferred.isCurrent || secondary.isCurrent,
|
|
476
|
+
displayName: preferred.displayName ?? secondary.displayName,
|
|
477
|
+
maxInputTokens: Math.max(
|
|
478
|
+
preferred.maxInputTokens,
|
|
479
|
+
secondary.maxInputTokens
|
|
480
|
+
)
|
|
481
|
+
};
|
|
482
|
+
if (mergedBaseURL !== void 0) {
|
|
483
|
+
mergedModel.baseURL = mergedBaseURL;
|
|
484
|
+
}
|
|
485
|
+
if (mergedReasoningVariant !== void 0) {
|
|
486
|
+
mergedModel.reasoningVariant = mergedReasoningVariant;
|
|
487
|
+
}
|
|
488
|
+
if (mergedOriginalProvider !== void 0) {
|
|
489
|
+
mergedModel.originalProvider = mergedOriginalProvider;
|
|
490
|
+
}
|
|
491
|
+
if (mergedReleaseDate !== void 0) {
|
|
492
|
+
mergedModel.releaseDate = mergedReleaseDate;
|
|
493
|
+
}
|
|
494
|
+
if (mergedStatus !== void 0) {
|
|
495
|
+
mergedModel.status = mergedStatus;
|
|
496
|
+
}
|
|
497
|
+
dedupedByKey.set(key, mergedModel);
|
|
498
|
+
}
|
|
499
|
+
const dedupedModelList = dedupeOrder.map((key) => dedupedByKey.get(key)).filter((model) => model !== void 0);
|
|
500
|
+
setModels(dedupedModelList);
|
|
275
501
|
setCustomModels(loadedCustomModels);
|
|
502
|
+
setModelPickerState(pickerState);
|
|
276
503
|
setIsLoading(false);
|
|
277
|
-
const currentIndex =
|
|
504
|
+
const currentIndex = dedupedModelList.findIndex((m) => m.isCurrent);
|
|
278
505
|
if (currentIndex >= 0) {
|
|
279
|
-
const nextIndex = currentIndex
|
|
506
|
+
const nextIndex = currentIndex;
|
|
280
507
|
const nextMaxVisibleItems = maxVisibleItemsRef.current;
|
|
281
|
-
const
|
|
282
|
-
|
|
508
|
+
const maxOffset = Math.max(
|
|
509
|
+
0,
|
|
510
|
+
dedupedModelList.length - nextMaxVisibleItems
|
|
511
|
+
);
|
|
283
512
|
const nextOffset = Math.min(
|
|
284
513
|
maxOffset,
|
|
285
|
-
Math.max(0, currentIndex -
|
|
514
|
+
Math.max(0, currentIndex - nextMaxVisibleItems + 1)
|
|
286
515
|
);
|
|
287
516
|
selectedIndexRef.current = nextIndex;
|
|
288
517
|
setSelection({ index: nextIndex, offset: nextOffset });
|
|
@@ -294,6 +523,7 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
294
523
|
`Failed to fetch models: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
295
524
|
);
|
|
296
525
|
setModels([]);
|
|
526
|
+
setModelPickerState(null);
|
|
297
527
|
setIsLoading(false);
|
|
298
528
|
}
|
|
299
529
|
}
|
|
@@ -303,35 +533,99 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
303
533
|
cancelled = true;
|
|
304
534
|
};
|
|
305
535
|
}, [isVisible, agent, refreshVersion]);
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
536
|
+
const favoriteKeySet = (0, import_react.useMemo)(
|
|
537
|
+
() => new Set(
|
|
538
|
+
(modelPickerState?.favorites ?? []).map(
|
|
539
|
+
(entry) => (0, import_agent_management.toModelPickerKey)({
|
|
540
|
+
provider: entry.provider,
|
|
541
|
+
model: entry.model
|
|
542
|
+
})
|
|
543
|
+
)
|
|
544
|
+
),
|
|
545
|
+
[modelPickerState]
|
|
546
|
+
);
|
|
547
|
+
const matchesSearch = (0, import_react.useCallback)(
|
|
548
|
+
(model) => {
|
|
549
|
+
if (!searchQuery.trim()) {
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
const query = searchQuery.toLowerCase().replace(/[\s-]+/g, "");
|
|
313
553
|
const name = model.name.toLowerCase().replace(/[\s-]+/g, "");
|
|
314
554
|
const displayName = (model.displayName || "").toLowerCase().replace(/[\s-]+/g, "");
|
|
315
555
|
const provider = model.provider.toLowerCase().replace(/[\s-]+/g, "");
|
|
316
556
|
return name.includes(query) || displayName.includes(query) || provider.includes(query);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
557
|
+
},
|
|
558
|
+
[searchQuery]
|
|
559
|
+
);
|
|
560
|
+
const filteredItems = (0, import_react.useMemo)(() => {
|
|
561
|
+
const addCustomOption = { type: "add-custom" };
|
|
562
|
+
const hasSearchQuery = searchQuery.trim().length > 0;
|
|
563
|
+
const allCandidates = [...models].sort(compareModelOptionsForDisplay);
|
|
564
|
+
const modelsByKey = new Map(
|
|
565
|
+
allCandidates.map((model) => [
|
|
566
|
+
(0, import_agent_management.toModelPickerKey)({ provider: model.provider, model: model.name }),
|
|
567
|
+
model
|
|
568
|
+
])
|
|
569
|
+
);
|
|
570
|
+
const toUniqueMatchingModels = (candidates, limit) => {
|
|
571
|
+
const deduped = [];
|
|
572
|
+
const seen = /* @__PURE__ */ new Set();
|
|
573
|
+
for (const candidate of candidates) {
|
|
574
|
+
if (!candidate || !matchesSearch(candidate)) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const key = (0, import_agent_management.toModelPickerKey)({
|
|
578
|
+
provider: candidate.provider,
|
|
579
|
+
model: candidate.name
|
|
580
|
+
});
|
|
581
|
+
if (seen.has(key)) {
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
seen.add(key);
|
|
585
|
+
deduped.push(candidate);
|
|
586
|
+
if (limit !== void 0 && deduped.length >= limit) {
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return deduped;
|
|
591
|
+
};
|
|
592
|
+
const providersInModels = Array.from(
|
|
593
|
+
new Set(models.map((model) => model.provider))
|
|
594
|
+
);
|
|
595
|
+
const featuredCandidates = (0, import_core.getCuratedModelRefsForProviders)({
|
|
596
|
+
providers: providersInModels,
|
|
597
|
+
max: FEATURED_SECTION_LIMIT
|
|
598
|
+
}).map((ref2) => modelsByKey.get((0, import_agent_management.toModelPickerKey)(ref2)));
|
|
599
|
+
const recentsFromState = (modelPickerState?.recents ?? []).map(
|
|
600
|
+
(entry) => modelsByKey.get((0, import_agent_management.toModelPickerKey)({ provider: entry.provider, model: entry.model }))
|
|
601
|
+
);
|
|
602
|
+
const favoritesFromState = (modelPickerState?.favorites ?? []).map(
|
|
603
|
+
(entry) => modelsByKey.get((0, import_agent_management.toModelPickerKey)({ provider: entry.provider, model: entry.model }))
|
|
604
|
+
);
|
|
605
|
+
const customCandidates = allCandidates.filter((model) => model.isCustom);
|
|
606
|
+
const tabModels = hasSearchQuery ? toUniqueMatchingModels(allCandidates) : activeTab === "all-models" ? toUniqueMatchingModels(allCandidates) : activeTab === "featured" ? toUniqueMatchingModels(featuredCandidates) : activeTab === "recents" ? toUniqueMatchingModels(recentsFromState) : activeTab === "favorites" ? toUniqueMatchingModels(favoritesFromState) : toUniqueMatchingModels(customCandidates);
|
|
607
|
+
return activeTab === "custom" && !hasSearchQuery ? [addCustomOption, ...tabModels] : tabModels;
|
|
608
|
+
}, [activeTab, matchesSearch, modelPickerState, models, searchQuery]);
|
|
609
|
+
const hasAddCustomOption = activeTab === "custom" && searchQuery.trim().length === 0;
|
|
610
|
+
const modelStartIndex = hasAddCustomOption ? 1 : 0;
|
|
611
|
+
const listViewportItems = hasAddCustomOption ? modelsViewportItems : maxVisibleItems;
|
|
320
612
|
(0, import_react.useEffect)(() => {
|
|
321
613
|
setSelection((prev) => {
|
|
322
614
|
const maxIndex = Math.max(0, filteredItems.length - 1);
|
|
323
615
|
const nextIndex = Math.min(prev.index, maxIndex);
|
|
324
616
|
let nextOffset = prev.offset;
|
|
325
|
-
const nextModelsLength = Math.max(0, filteredItems.length -
|
|
326
|
-
if (nextIndex
|
|
327
|
-
const modelIndex = nextIndex -
|
|
617
|
+
const nextModelsLength = Math.max(0, filteredItems.length - modelStartIndex);
|
|
618
|
+
if (nextIndex >= modelStartIndex) {
|
|
619
|
+
const modelIndex = nextIndex - modelStartIndex;
|
|
328
620
|
if (modelIndex < nextOffset) {
|
|
329
621
|
nextOffset = modelIndex;
|
|
330
|
-
} else if (modelIndex >= nextOffset +
|
|
331
|
-
nextOffset = Math.max(0, modelIndex -
|
|
622
|
+
} else if (modelIndex >= nextOffset + listViewportItems) {
|
|
623
|
+
nextOffset = Math.max(0, modelIndex - listViewportItems + 1);
|
|
332
624
|
}
|
|
625
|
+
} else {
|
|
626
|
+
nextOffset = 0;
|
|
333
627
|
}
|
|
334
|
-
const maxOffset = Math.max(0, nextModelsLength -
|
|
628
|
+
const maxOffset = Math.max(0, nextModelsLength - listViewportItems);
|
|
335
629
|
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
336
630
|
if (nextIndex === prev.index && nextOffset === prev.offset) {
|
|
337
631
|
return prev;
|
|
@@ -339,7 +633,7 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
339
633
|
selectedIndexRef.current = nextIndex;
|
|
340
634
|
return { index: nextIndex, offset: nextOffset };
|
|
341
635
|
});
|
|
342
|
-
}, [filteredItems.length,
|
|
636
|
+
}, [filteredItems.length, listViewportItems, modelStartIndex]);
|
|
343
637
|
const handleDeleteCustomModel = (0, import_react.useCallback)(
|
|
344
638
|
async (model) => {
|
|
345
639
|
if (!model.isCustom) return;
|
|
@@ -356,6 +650,23 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
356
650
|
},
|
|
357
651
|
[agent]
|
|
358
652
|
);
|
|
653
|
+
const handleToggleFavoriteModel = (0, import_react.useCallback)(
|
|
654
|
+
async (model) => {
|
|
655
|
+
try {
|
|
656
|
+
await (0, import_agent_management.toggleFavoriteModel)({
|
|
657
|
+
provider: model.provider,
|
|
658
|
+
model: model.name
|
|
659
|
+
});
|
|
660
|
+
const nextState = await (0, import_agent_management.loadModelPickerState)();
|
|
661
|
+
setModelPickerState(nextState);
|
|
662
|
+
} catch (error) {
|
|
663
|
+
agent.logger.error(
|
|
664
|
+
`Failed to toggle favorite model: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
},
|
|
668
|
+
[agent]
|
|
669
|
+
);
|
|
359
670
|
const clearActionState = () => {
|
|
360
671
|
setCustomModelAction(null);
|
|
361
672
|
setPendingDeleteConfirm(false);
|
|
@@ -454,27 +765,44 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
454
765
|
}
|
|
455
766
|
const itemsLength = filteredItems.length;
|
|
456
767
|
const currentItem = filteredItems[selectedIndexRef.current];
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
768
|
+
const selectedModel = currentItem && isModelOption(currentItem) ? currentItem : null;
|
|
769
|
+
const isCustomActionItem = selectedModel?.isCustom ?? false;
|
|
770
|
+
const isSelectableItem = selectedModel !== null;
|
|
771
|
+
if (key.tab) {
|
|
772
|
+
clearActionState();
|
|
773
|
+
setActiveTab((prev) => getNextModelSelectorTab(prev));
|
|
774
|
+
selectedIndexRef.current = 0;
|
|
775
|
+
setSelection({ index: 0, offset: 0 });
|
|
776
|
+
return true;
|
|
777
|
+
}
|
|
778
|
+
if (key.ctrl && input === "f" && isSelectableItem) {
|
|
779
|
+
const item = selectedModel;
|
|
780
|
+
if (!item) return true;
|
|
781
|
+
clearActionState();
|
|
782
|
+
void handleToggleFavoriteModel(item);
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
if (key.ctrl && key.rightArrow) {
|
|
460
786
|
if (!isSelectableItem) return false;
|
|
461
787
|
if (customModelAction === null) {
|
|
462
|
-
|
|
463
|
-
setCustomModelAction("edit");
|
|
464
|
-
} else {
|
|
465
|
-
setCustomModelAction("default");
|
|
466
|
-
}
|
|
788
|
+
setCustomModelAction("favorite");
|
|
467
789
|
return true;
|
|
468
790
|
}
|
|
469
|
-
if (customModelAction === "
|
|
791
|
+
if (customModelAction === "favorite") {
|
|
470
792
|
setCustomModelAction("default");
|
|
471
793
|
return true;
|
|
472
794
|
}
|
|
473
795
|
if (customModelAction === "default") {
|
|
796
|
+
if (isCustomActionItem) {
|
|
797
|
+
setCustomModelAction("edit");
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
return true;
|
|
801
|
+
}
|
|
802
|
+
if (customModelAction === "edit") {
|
|
474
803
|
if (isCustomActionItem) {
|
|
475
804
|
setCustomModelAction("delete");
|
|
476
805
|
setPendingDeleteConfirm(false);
|
|
477
|
-
return true;
|
|
478
806
|
}
|
|
479
807
|
return true;
|
|
480
808
|
}
|
|
@@ -482,9 +810,9 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
482
810
|
return true;
|
|
483
811
|
}
|
|
484
812
|
}
|
|
485
|
-
if (key.leftArrow) {
|
|
813
|
+
if (key.ctrl && key.leftArrow) {
|
|
486
814
|
if (customModelAction === "delete") {
|
|
487
|
-
setCustomModelAction("
|
|
815
|
+
setCustomModelAction("edit");
|
|
488
816
|
setPendingDeleteConfirm(false);
|
|
489
817
|
if (deleteTimeoutRef.current) {
|
|
490
818
|
clearTimeout(deleteTimeoutRef.current);
|
|
@@ -493,19 +821,33 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
493
821
|
return true;
|
|
494
822
|
}
|
|
495
823
|
if (customModelAction === "default") {
|
|
496
|
-
|
|
497
|
-
setCustomModelAction("edit");
|
|
498
|
-
} else {
|
|
499
|
-
setCustomModelAction(null);
|
|
500
|
-
}
|
|
824
|
+
setCustomModelAction("favorite");
|
|
501
825
|
return true;
|
|
502
826
|
}
|
|
503
827
|
if (customModelAction === "edit") {
|
|
828
|
+
setCustomModelAction("default");
|
|
829
|
+
return true;
|
|
830
|
+
}
|
|
831
|
+
if (customModelAction === "favorite") {
|
|
504
832
|
setCustomModelAction(null);
|
|
505
833
|
return true;
|
|
506
834
|
}
|
|
507
835
|
return false;
|
|
508
836
|
}
|
|
837
|
+
if (key.rightArrow) {
|
|
838
|
+
clearActionState();
|
|
839
|
+
setActiveTab((prev) => getNextModelSelectorTab(prev));
|
|
840
|
+
selectedIndexRef.current = 0;
|
|
841
|
+
setSelection({ index: 0, offset: 0 });
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
844
|
+
if (key.leftArrow) {
|
|
845
|
+
clearActionState();
|
|
846
|
+
setActiveTab((prev) => getPreviousModelSelectorTab(prev));
|
|
847
|
+
selectedIndexRef.current = 0;
|
|
848
|
+
setSelection({ index: 0, offset: 0 });
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
509
851
|
if (input && !key.return && !key.upArrow && !key.downArrow && !key.tab) {
|
|
510
852
|
if (customModelAction) {
|
|
511
853
|
clearActionState();
|
|
@@ -534,16 +876,18 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
534
876
|
selectedIndexRef.current = nextIndex;
|
|
535
877
|
setSelection((prev) => {
|
|
536
878
|
let nextOffset = prev.offset;
|
|
537
|
-
const nextModelsLength = Math.max(0, itemsLength -
|
|
538
|
-
if (nextIndex
|
|
539
|
-
const modelIndex = nextIndex -
|
|
879
|
+
const nextModelsLength = Math.max(0, itemsLength - modelStartIndex);
|
|
880
|
+
if (nextIndex >= modelStartIndex) {
|
|
881
|
+
const modelIndex = nextIndex - modelStartIndex;
|
|
540
882
|
if (modelIndex < prev.offset) {
|
|
541
883
|
nextOffset = modelIndex;
|
|
542
|
-
} else if (modelIndex >= prev.offset +
|
|
543
|
-
nextOffset = Math.max(0, modelIndex -
|
|
884
|
+
} else if (modelIndex >= prev.offset + listViewportItems) {
|
|
885
|
+
nextOffset = Math.max(0, modelIndex - listViewportItems + 1);
|
|
544
886
|
}
|
|
887
|
+
} else {
|
|
888
|
+
nextOffset = 0;
|
|
545
889
|
}
|
|
546
|
-
const maxOffset = Math.max(0, nextModelsLength -
|
|
890
|
+
const maxOffset = Math.max(0, nextModelsLength - listViewportItems);
|
|
547
891
|
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
548
892
|
return { index: nextIndex, offset: nextOffset };
|
|
549
893
|
});
|
|
@@ -557,16 +901,18 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
557
901
|
selectedIndexRef.current = nextIndex;
|
|
558
902
|
setSelection((prev) => {
|
|
559
903
|
let nextOffset = prev.offset;
|
|
560
|
-
const nextModelsLength = Math.max(0, itemsLength -
|
|
561
|
-
if (nextIndex
|
|
562
|
-
const modelIndex = nextIndex -
|
|
904
|
+
const nextModelsLength = Math.max(0, itemsLength - modelStartIndex);
|
|
905
|
+
if (nextIndex >= modelStartIndex) {
|
|
906
|
+
const modelIndex = nextIndex - modelStartIndex;
|
|
563
907
|
if (modelIndex < prev.offset) {
|
|
564
908
|
nextOffset = modelIndex;
|
|
565
|
-
} else if (modelIndex >= prev.offset +
|
|
566
|
-
nextOffset = Math.max(0, modelIndex -
|
|
909
|
+
} else if (modelIndex >= prev.offset + listViewportItems) {
|
|
910
|
+
nextOffset = Math.max(0, modelIndex - listViewportItems + 1);
|
|
567
911
|
}
|
|
912
|
+
} else {
|
|
913
|
+
nextOffset = 0;
|
|
568
914
|
}
|
|
569
|
-
const maxOffset = Math.max(0, nextModelsLength -
|
|
915
|
+
const maxOffset = Math.max(0, nextModelsLength - listViewportItems);
|
|
570
916
|
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
571
917
|
return { index: nextIndex, offset: nextOffset };
|
|
572
918
|
});
|
|
@@ -579,6 +925,10 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
579
925
|
onAddCustomModel();
|
|
580
926
|
return true;
|
|
581
927
|
}
|
|
928
|
+
if (customModelAction === "favorite") {
|
|
929
|
+
void handleToggleFavoriteModel(item);
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
582
932
|
if (customModelAction === "edit" && item.isCustom) {
|
|
583
933
|
const customModel = customModels.find(
|
|
584
934
|
(cm) => cm.name === item.name && (cm.provider ?? "openai-compatible") === item.provider
|
|
@@ -637,7 +987,8 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
637
987
|
isLoading,
|
|
638
988
|
filteredItems,
|
|
639
989
|
maxVisibleItems,
|
|
640
|
-
|
|
990
|
+
listViewportItems,
|
|
991
|
+
modelStartIndex,
|
|
641
992
|
onClose,
|
|
642
993
|
onSelectModel,
|
|
643
994
|
onSetDefaultModel,
|
|
@@ -647,14 +998,18 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
647
998
|
pendingDeleteConfirm,
|
|
648
999
|
customModels,
|
|
649
1000
|
handleDeleteCustomModel,
|
|
1001
|
+
handleToggleFavoriteModel,
|
|
650
1002
|
pendingReasoningModel,
|
|
651
1003
|
reasoningVariantIndex,
|
|
652
1004
|
reasoningVariantOptions,
|
|
653
1005
|
isSettingDefault,
|
|
1006
|
+
activeTab,
|
|
1007
|
+
agent,
|
|
654
1008
|
beginReasoningVariantSelection
|
|
655
1009
|
]
|
|
656
1010
|
);
|
|
657
1011
|
if (!isVisible) return null;
|
|
1012
|
+
const blankLine = " ".repeat(overlayWidth);
|
|
658
1013
|
if (pendingReasoningModel) {
|
|
659
1014
|
const totalOptions = reasoningVariantOptions.length;
|
|
660
1015
|
const reasoningVisibleItems = Math.min(maxVisibleItems, totalOptions);
|
|
@@ -667,200 +1022,167 @@ const ModelSelector = (0, import_react.forwardRef)(function ModelSelector2({
|
|
|
667
1022
|
reasoningOffset + reasoningVisibleItems
|
|
668
1023
|
);
|
|
669
1024
|
const selectedReasoningOption = reasoningVariantOptions[reasoningVariantIndex] ?? reasoningVariantOptions[0];
|
|
670
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", children: [
|
|
671
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "cyan", bold: true, children: [
|
|
1025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", width: overlayWidth, children: [
|
|
1026
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Text, { color: "cyan", bold: true, children: [
|
|
672
1027
|
"Reasoning Variant",
|
|
673
1028
|
isSettingDefault ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: " (default)" }) : null
|
|
674
1029
|
] }) }),
|
|
675
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray",
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
1030
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: formatLineToWidth(
|
|
1031
|
+
pendingReasoningModel.displayName || pendingReasoningModel.name,
|
|
1032
|
+
overlayWidth
|
|
1033
|
+
) }) }),
|
|
1034
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1035
|
+
import_ink.Box,
|
|
1036
|
+
{
|
|
1037
|
+
flexDirection: "column",
|
|
1038
|
+
height: maxVisibleItems,
|
|
1039
|
+
marginTop: 1,
|
|
1040
|
+
width: overlayWidth,
|
|
1041
|
+
children: Array.from({ length: maxVisibleItems }, (_, rowIndex) => {
|
|
1042
|
+
const option = visibleReasoningOptions[rowIndex];
|
|
1043
|
+
if (!option) {
|
|
1044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1045
|
+
import_ink.Box,
|
|
1046
|
+
{
|
|
1047
|
+
paddingX: 0,
|
|
1048
|
+
paddingY: 0,
|
|
1049
|
+
width: overlayWidth,
|
|
1050
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: blankLine })
|
|
1051
|
+
},
|
|
1052
|
+
`reasoning-empty-${rowIndex}`
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
const actualIndex = reasoningOffset + rowIndex;
|
|
1056
|
+
const isSelected = actualIndex === reasoningVariantIndex;
|
|
1057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: isSelected ? "cyan" : "gray", bold: isSelected, children: formatLineToWidth(
|
|
1058
|
+
`${isSelected ? "\u203A" : " "} ${option.label}`,
|
|
1059
|
+
overlayWidth
|
|
1060
|
+
) }) }, option.value);
|
|
1061
|
+
})
|
|
680
1062
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
bold: isSelected,
|
|
688
|
-
wrap: "truncate-end",
|
|
689
|
-
children: [
|
|
690
|
-
isSelected ? "\u203A" : " ",
|
|
691
|
-
" ",
|
|
692
|
-
option.label
|
|
693
|
-
]
|
|
694
|
-
}
|
|
695
|
-
) }, option.value);
|
|
696
|
-
}) }),
|
|
697
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", wrap: "truncate-end", children: selectedReasoningOption?.description ?? "" }) }),
|
|
698
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_HintBar.HintBar, { hints: ["\u2191\u2193 navigate", "Enter select", "Esc back"] }) })
|
|
1063
|
+
),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, marginTop: 1, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: formatLineToWidth(
|
|
1065
|
+
selectedReasoningOption?.description ?? "",
|
|
1066
|
+
overlayWidth
|
|
1067
|
+
) }) }),
|
|
1068
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_HintBar.HintBar, { hints: ["\u2191\u2193 navigate", "Enter select", "Esc back"] }) })
|
|
699
1069
|
] });
|
|
700
1070
|
}
|
|
701
1071
|
const selectedIndex = selection.index;
|
|
702
1072
|
const scrollOffset = selection.offset;
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
);
|
|
706
|
-
const visibleModels = modelsOnly.slice(scrollOffset, scrollOffset + modelsViewportItems);
|
|
1073
|
+
const listItems = filteredItems.filter((item) => !isAddCustomOption(item));
|
|
1074
|
+
const visibleItems = listItems.slice(scrollOffset, scrollOffset + listViewportItems);
|
|
707
1075
|
const selectedItem = filteredItems[selectedIndex];
|
|
708
|
-
const hasActionableItems = selectedItem &&
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1076
|
+
const hasActionableItems = Boolean(selectedItem && isModelOption(selectedItem));
|
|
1077
|
+
const searchLine = formatLineToWidth(
|
|
1078
|
+
`Search: ${searchQuery || "Type to filter models\u2026"}`,
|
|
1079
|
+
overlayWidth
|
|
1080
|
+
);
|
|
1081
|
+
const addCustomLine = hasAddCustomOption ? formatLineToWidth(
|
|
1082
|
+
`${getRowPrefix({
|
|
1083
|
+
isSelected: selectedIndex === 0,
|
|
1084
|
+
isDefault: false,
|
|
1085
|
+
isCurrent: false,
|
|
1086
|
+
isCustom: false,
|
|
1087
|
+
isFavorite: false
|
|
1088
|
+
})} Add custom model\u2026`,
|
|
1089
|
+
overlayWidth
|
|
1090
|
+
) : "";
|
|
1091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", width: overlayWidth, children: [
|
|
1092
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "cyan", bold: true, children: "Models" }) }),
|
|
1093
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, flexDirection: "row", children: MODEL_SELECTOR_TABS.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1094
|
+
import_ink.Box,
|
|
1095
|
+
{
|
|
1096
|
+
marginRight: 1,
|
|
1097
|
+
borderStyle: "round",
|
|
1098
|
+
borderColor: activeTab === tab.id ? "cyan" : "gray",
|
|
1099
|
+
paddingX: 1,
|
|
1100
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1101
|
+
import_ink.Text,
|
|
1102
|
+
{
|
|
1103
|
+
color: activeTab === tab.id ? "cyan" : "gray",
|
|
1104
|
+
bold: activeTab === tab.id,
|
|
1105
|
+
children: tab.label
|
|
1106
|
+
}
|
|
1107
|
+
)
|
|
1108
|
+
},
|
|
1109
|
+
tab.id
|
|
1110
|
+
)) }),
|
|
1111
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: searchQuery ? "white" : "gray", children: searchLine }) }),
|
|
1112
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginTop: 1, width: overlayWidth, children: [
|
|
1113
|
+
hasAddCustomOption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
739
1114
|
import_ink.Text,
|
|
740
1115
|
{
|
|
741
1116
|
color: selectedIndex === 0 ? "green" : "gray",
|
|
742
1117
|
bold: selectedIndex === 0,
|
|
743
|
-
|
|
744
|
-
children: [
|
|
745
|
-
getRowPrefix({
|
|
746
|
-
isSelected: selectedIndex === 0,
|
|
747
|
-
isDefault: false,
|
|
748
|
-
isCurrent: false,
|
|
749
|
-
isCustom: false
|
|
750
|
-
}),
|
|
751
|
-
" ",
|
|
752
|
-
"Add custom model\u2026"
|
|
753
|
-
]
|
|
1118
|
+
children: addCustomLine
|
|
754
1119
|
}
|
|
755
1120
|
) }),
|
|
756
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", height:
|
|
757
|
-
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { flexDirection: "column", height: listViewportItems, width: overlayWidth, children: isLoading || listItems.length === 0 ? Array.from({ length: listViewportItems }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1122
|
+
import_ink.Box,
|
|
1123
|
+
{
|
|
1124
|
+
paddingX: 0,
|
|
1125
|
+
paddingY: 0,
|
|
1126
|
+
width: overlayWidth,
|
|
1127
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: blankLine })
|
|
1128
|
+
},
|
|
1129
|
+
`model-empty-${index}`
|
|
1130
|
+
)) : Array.from({ length: listViewportItems }, (_, rowIndex) => {
|
|
1131
|
+
const item = visibleItems[rowIndex];
|
|
758
1132
|
if (!item) {
|
|
759
1133
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
760
1134
|
import_ink.Box,
|
|
761
1135
|
{
|
|
762
1136
|
paddingX: 0,
|
|
763
1137
|
paddingY: 0,
|
|
764
|
-
|
|
1138
|
+
width: overlayWidth,
|
|
1139
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: blankLine })
|
|
765
1140
|
},
|
|
766
1141
|
`model-empty-${rowIndex}`
|
|
767
1142
|
);
|
|
768
1143
|
}
|
|
769
|
-
const actualIndex =
|
|
1144
|
+
const actualIndex = modelStartIndex + scrollOffset + rowIndex;
|
|
770
1145
|
const isSelected = actualIndex === selectedIndex;
|
|
771
1146
|
const providerDisplay = (0, import_llm_provider_display.getLLMProviderDisplayName)(item.provider);
|
|
772
1147
|
const name = item.displayName || item.name;
|
|
1148
|
+
const isFavorite = favoriteKeySet.has(
|
|
1149
|
+
(0, import_agent_management.toModelPickerKey)({
|
|
1150
|
+
provider: item.provider,
|
|
1151
|
+
model: item.name
|
|
1152
|
+
})
|
|
1153
|
+
);
|
|
773
1154
|
const prefix = getRowPrefix({
|
|
774
1155
|
isSelected,
|
|
775
1156
|
isDefault: item.isDefault,
|
|
776
1157
|
isCurrent: item.isCurrent,
|
|
777
|
-
isCustom: item.isCustom
|
|
1158
|
+
isCustom: item.isCustom,
|
|
1159
|
+
isFavorite
|
|
778
1160
|
});
|
|
779
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
1161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
780
1162
|
import_ink.Box,
|
|
781
1163
|
{
|
|
782
1164
|
flexDirection: "row",
|
|
783
1165
|
paddingX: 0,
|
|
784
1166
|
paddingY: 0,
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
bold: isSelected,
|
|
791
|
-
wrap: "truncate-end",
|
|
792
|
-
children: [
|
|
793
|
-
prefix,
|
|
794
|
-
" ",
|
|
795
|
-
name,
|
|
796
|
-
" (",
|
|
797
|
-
providerDisplay,
|
|
798
|
-
")"
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
) }),
|
|
802
|
-
isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "row", marginLeft: 1, children: [
|
|
803
|
-
item.isCustom && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
804
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
805
|
-
import_ink.Text,
|
|
806
|
-
{
|
|
807
|
-
color: customModelAction === "edit" ? "green" : "gray",
|
|
808
|
-
bold: customModelAction === "edit",
|
|
809
|
-
inverse: customModelAction === "edit",
|
|
810
|
-
children: [
|
|
811
|
-
" ",
|
|
812
|
-
"Edit",
|
|
813
|
-
" "
|
|
814
|
-
]
|
|
815
|
-
}
|
|
816
|
-
),
|
|
817
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: " " })
|
|
818
|
-
] }),
|
|
819
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
820
|
-
import_ink.Text,
|
|
821
|
-
{
|
|
822
|
-
color: customModelAction === "default" ? "cyan" : "gray",
|
|
823
|
-
bold: customModelAction === "default",
|
|
824
|
-
inverse: customModelAction === "default",
|
|
825
|
-
children: [
|
|
826
|
-
" ",
|
|
827
|
-
"Set as Default",
|
|
828
|
-
" "
|
|
829
|
-
]
|
|
830
|
-
}
|
|
831
|
-
),
|
|
832
|
-
item.isCustom && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
833
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: " " }),
|
|
834
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
835
|
-
import_ink.Text,
|
|
836
|
-
{
|
|
837
|
-
color: customModelAction === "delete" ? "red" : "gray",
|
|
838
|
-
bold: customModelAction === "delete",
|
|
839
|
-
inverse: customModelAction === "delete",
|
|
840
|
-
children: [
|
|
841
|
-
" ",
|
|
842
|
-
"Delete",
|
|
843
|
-
" "
|
|
844
|
-
]
|
|
845
|
-
}
|
|
846
|
-
)
|
|
847
|
-
] })
|
|
848
|
-
] })
|
|
849
|
-
]
|
|
1167
|
+
width: overlayWidth,
|
|
1168
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: isSelected ? "cyan" : "gray", bold: isSelected, children: formatLineToWidth(
|
|
1169
|
+
`${prefix} ${name} (${providerDisplay})`,
|
|
1170
|
+
overlayWidth
|
|
1171
|
+
) })
|
|
850
1172
|
},
|
|
851
|
-
|
|
1173
|
+
`model-${activeTab}-${actualIndex}-${toModelIdentityKey(item)}`
|
|
852
1174
|
);
|
|
853
1175
|
}) })
|
|
854
1176
|
] }),
|
|
855
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
856
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { paddingX: 0, paddingY: 0, marginTop: 1, width: overlayWidth, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
857
1178
|
import_HintBar.HintBar,
|
|
858
1179
|
{
|
|
859
1180
|
hints: [
|
|
860
1181
|
"\u2191\u2193 navigate",
|
|
861
|
-
"Enter select",
|
|
1182
|
+
"Enter select/apply",
|
|
862
1183
|
"Esc close",
|
|
863
|
-
|
|
1184
|
+
"\u2190\u2192 switch tab",
|
|
1185
|
+
hasActionableItems ? "Ctrl+F quick favorite" : ""
|
|
864
1186
|
]
|
|
865
1187
|
}
|
|
866
1188
|
) })
|