@dexto/tui 1.8.1 → 1.8.3
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/agent-backend.d.ts +2 -2
- package/dist/agent-backend.d.ts.map +1 -1
- package/dist/components/overlays/ConnectOverlay.cjs +423 -0
- package/dist/components/overlays/ConnectOverlay.d.ts +21 -0
- package/dist/components/overlays/ConnectOverlay.d.ts.map +1 -0
- package/dist/components/overlays/ConnectOverlay.js +412 -0
- package/dist/containers/OverlayContainer.cjs +58 -0
- package/dist/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/containers/OverlayContainer.js +58 -0
- package/dist/hooks/useTokenCounter.cjs +9 -11
- package/dist/hooks/useTokenCounter.d.ts.map +1 -1
- package/dist/hooks/useTokenCounter.js +9 -11
- package/dist/index.d.cts +2 -2
- package/dist/interactive-commands/auth/index.cjs +9 -0
- package/dist/interactive-commands/auth/index.d.ts +1 -0
- package/dist/interactive-commands/auth/index.d.ts.map +1 -1
- package/dist/interactive-commands/auth/index.js +8 -0
- package/dist/interactive-commands/commands.cjs +3 -1
- package/dist/interactive-commands/commands.d.ts.map +1 -1
- package/dist/interactive-commands/commands.js +4 -2
- package/dist/services/processStream.cjs +29 -20
- package/dist/services/processStream.d.ts.map +1 -1
- package/dist/services/processStream.js +29 -20
- package/dist/services/processStream.test.cjs +58 -20
- package/dist/services/processStream.test.js +58 -20
- package/dist/state/types.d.ts +1 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/utils/commandOverlays.cjs +1 -0
- package/dist/utils/commandOverlays.d.ts.map +1 -1
- package/dist/utils/commandOverlays.js +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
useState
|
|
10
|
+
} from "react";
|
|
11
|
+
import { Box, Text } from "ink";
|
|
12
|
+
import open from "open";
|
|
13
|
+
import { BaseSelector } from "../base/BaseSelector.js";
|
|
14
|
+
import {
|
|
15
|
+
deleteModelAuthProfile,
|
|
16
|
+
getDefaultModelAuthProfileIdForProvider,
|
|
17
|
+
getModelAuthProfileId,
|
|
18
|
+
getProviderAuthDefinitions,
|
|
19
|
+
listSavedModelAuthProfiles,
|
|
20
|
+
markModelAuthProviderConnected,
|
|
21
|
+
saveApiKeyModelAuthProfile,
|
|
22
|
+
saveProviderApiKey,
|
|
23
|
+
setDefaultModelAuthProfile,
|
|
24
|
+
startModelAuthBrowserLogin
|
|
25
|
+
} from "@dexto/agent-management";
|
|
26
|
+
import { LLM_PROVIDERS } from "@dexto/llm";
|
|
27
|
+
import { applyLayeredEnvironmentLoading, isValidApiKeyFormat } from "../../host/index.js";
|
|
28
|
+
function methodHint(method, profile, defaultProfileId) {
|
|
29
|
+
const parts = [
|
|
30
|
+
profile ? profile.id === defaultProfileId ? "Connected (default)" : "Connected" : void 0,
|
|
31
|
+
method.hint
|
|
32
|
+
].filter((part) => Boolean(part));
|
|
33
|
+
return parts.length ? parts.join(" - ") : void 0;
|
|
34
|
+
}
|
|
35
|
+
function maskSecret(secret) {
|
|
36
|
+
if (secret.length <= 8) {
|
|
37
|
+
return "*".repeat(secret.length);
|
|
38
|
+
}
|
|
39
|
+
return `${secret.slice(0, 4)}${"*".repeat(Math.min(secret.length - 8, 24))}${secret.slice(-4)}`;
|
|
40
|
+
}
|
|
41
|
+
function toLlmProvider(providerId) {
|
|
42
|
+
const provider = LLM_PROVIDERS.find((candidate) => candidate === providerId);
|
|
43
|
+
if (!provider) {
|
|
44
|
+
throw new Error(`API-key auth is not implemented for provider: ${providerId}`);
|
|
45
|
+
}
|
|
46
|
+
return provider;
|
|
47
|
+
}
|
|
48
|
+
const ConnectOverlay = forwardRef(
|
|
49
|
+
function ConnectOverlay2({ isVisible, onDone }, ref) {
|
|
50
|
+
const selectorRef = useRef(null);
|
|
51
|
+
const loginCancelRef = useRef(null);
|
|
52
|
+
const [step, setStep] = useState("provider");
|
|
53
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
54
|
+
const [provider, setProvider] = useState(null);
|
|
55
|
+
const [method, setMethod] = useState(null);
|
|
56
|
+
const [profiles, setProfiles] = useState([]);
|
|
57
|
+
const [defaultProfileId, setDefaultProfileId] = useState(null);
|
|
58
|
+
const [apiKey, setApiKey] = useState("");
|
|
59
|
+
const [status, setStatus] = useState("Choose a provider to connect.");
|
|
60
|
+
const [error, setError] = useState(null);
|
|
61
|
+
const currentProfileId = provider && method ? getModelAuthProfileId(provider.providerId, method.id) : null;
|
|
62
|
+
const existingProfile = currentProfileId ? profiles.find((profile) => profile.id === currentProfileId) ?? null : null;
|
|
63
|
+
const close = useCallback(
|
|
64
|
+
(outcome) => {
|
|
65
|
+
void loginCancelRef.current?.();
|
|
66
|
+
loginCancelRef.current = null;
|
|
67
|
+
onDone(outcome);
|
|
68
|
+
},
|
|
69
|
+
[onDone]
|
|
70
|
+
);
|
|
71
|
+
const handleActionError = useCallback((err) => {
|
|
72
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
73
|
+
setStep("error");
|
|
74
|
+
}, []);
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!isVisible) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
setStep("provider");
|
|
80
|
+
setSelectedIndex(0);
|
|
81
|
+
setProvider(null);
|
|
82
|
+
setMethod(null);
|
|
83
|
+
setProfiles([]);
|
|
84
|
+
setDefaultProfileId(null);
|
|
85
|
+
setApiKey("");
|
|
86
|
+
setStatus("Choose a provider to connect.");
|
|
87
|
+
setError(null);
|
|
88
|
+
}, [isVisible]);
|
|
89
|
+
const providerOptions = useMemo(
|
|
90
|
+
() => getProviderAuthDefinitions().map((item) => ({
|
|
91
|
+
value: item.providerId,
|
|
92
|
+
label: item.label,
|
|
93
|
+
hint: `${item.methods.length} method${item.methods.length === 1 ? "" : "s"}`
|
|
94
|
+
})),
|
|
95
|
+
[]
|
|
96
|
+
);
|
|
97
|
+
const methodOptions = useMemo(() => {
|
|
98
|
+
if (!provider) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
return provider.methods.map((item) => {
|
|
102
|
+
const profile = profiles.find(
|
|
103
|
+
(candidate) => candidate.id === getModelAuthProfileId(provider.providerId, item.id)
|
|
104
|
+
);
|
|
105
|
+
return {
|
|
106
|
+
value: item.id,
|
|
107
|
+
label: item.label,
|
|
108
|
+
hint: methodHint(item, profile, defaultProfileId)
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
}, [defaultProfileId, profiles, provider]);
|
|
112
|
+
const existingActionOptions = useMemo(() => {
|
|
113
|
+
if (!existingProfile) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
return [
|
|
117
|
+
{
|
|
118
|
+
value: "use",
|
|
119
|
+
label: existingProfile.id === defaultProfileId ? "Keep as default" : "Use existing",
|
|
120
|
+
hint: existingProfile.id === defaultProfileId ? "No changes" : "Set this method as provider default"
|
|
121
|
+
},
|
|
122
|
+
{ value: "replace", label: "Replace credentials", hint: "Reconnect this method" },
|
|
123
|
+
{
|
|
124
|
+
value: "delete",
|
|
125
|
+
label: "Delete credentials",
|
|
126
|
+
...existingProfile.id === defaultProfileId ? { hint: "Also clears default" } : {}
|
|
127
|
+
}
|
|
128
|
+
];
|
|
129
|
+
}, [defaultProfileId, existingProfile]);
|
|
130
|
+
const activeItems = step === "provider" ? providerOptions : step === "method" ? methodOptions : step === "existing-action" ? existingActionOptions : [];
|
|
131
|
+
const loadProvider = useCallback(async (nextProvider) => {
|
|
132
|
+
setProvider(nextProvider);
|
|
133
|
+
setMethod(null);
|
|
134
|
+
setStatus(`Loading saved ${nextProvider.label} profiles...`);
|
|
135
|
+
const [savedProfiles, savedDefaultProfileId] = await Promise.all([
|
|
136
|
+
listSavedModelAuthProfiles(nextProvider.providerId),
|
|
137
|
+
getDefaultModelAuthProfileIdForProvider(nextProvider.providerId)
|
|
138
|
+
]);
|
|
139
|
+
setProfiles(savedProfiles);
|
|
140
|
+
setDefaultProfileId(savedDefaultProfileId);
|
|
141
|
+
setSelectedIndex(0);
|
|
142
|
+
setStatus(`Choose how to connect ${nextProvider.label}.`);
|
|
143
|
+
setStep("method");
|
|
144
|
+
}, []);
|
|
145
|
+
const saveApiKey = useCallback(async () => {
|
|
146
|
+
if (!provider || !method) {
|
|
147
|
+
close({ outcome: "cancelled" });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const trimmed = apiKey.trim();
|
|
151
|
+
if (!trimmed) {
|
|
152
|
+
setError("API key is required");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const llmProvider = toLlmProvider(provider.providerId);
|
|
156
|
+
if (!isValidApiKeyFormat(trimmed, llmProvider)) {
|
|
157
|
+
setError(`${provider.label} API key format is invalid`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
setError(null);
|
|
161
|
+
try {
|
|
162
|
+
setStatus(`Saving ${provider.label} API key...`);
|
|
163
|
+
await saveProviderApiKey(llmProvider, trimmed, process.cwd());
|
|
164
|
+
await applyLayeredEnvironmentLoading();
|
|
165
|
+
await saveApiKeyModelAuthProfile(llmProvider);
|
|
166
|
+
await markModelAuthProviderConnected(provider.providerId);
|
|
167
|
+
close({
|
|
168
|
+
outcome: "success",
|
|
169
|
+
providerId: provider.providerId,
|
|
170
|
+
message: `Connected ${provider.label} (${method.label})`
|
|
171
|
+
});
|
|
172
|
+
} catch (err) {
|
|
173
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
174
|
+
}
|
|
175
|
+
}, [apiKey, close, method, provider]);
|
|
176
|
+
const connectOAuth = useCallback(
|
|
177
|
+
async (nextProvider, nextMethod) => {
|
|
178
|
+
setStep("oauth-progress");
|
|
179
|
+
setStatus(`Starting ${nextMethod.label}...`);
|
|
180
|
+
let timeout = null;
|
|
181
|
+
try {
|
|
182
|
+
const login = await startModelAuthBrowserLogin({
|
|
183
|
+
providerId: nextProvider.providerId,
|
|
184
|
+
methodId: nextMethod.id
|
|
185
|
+
});
|
|
186
|
+
loginCancelRef.current = login.cancel;
|
|
187
|
+
setStatus(`Opening browser for ${nextMethod.label}...`);
|
|
188
|
+
await open(login.authUrl).catch(() => void 0);
|
|
189
|
+
setStatus("Waiting for browser authorization...");
|
|
190
|
+
await Promise.race([
|
|
191
|
+
login.waitForProfile(),
|
|
192
|
+
new Promise((_, reject) => {
|
|
193
|
+
timeout = setTimeout(
|
|
194
|
+
() => reject(new Error(`${nextMethod.label} timed out`)),
|
|
195
|
+
5 * 60 * 1e3
|
|
196
|
+
);
|
|
197
|
+
})
|
|
198
|
+
]);
|
|
199
|
+
await markModelAuthProviderConnected(nextProvider.providerId);
|
|
200
|
+
close({
|
|
201
|
+
outcome: "success",
|
|
202
|
+
providerId: nextProvider.providerId,
|
|
203
|
+
message: `Connected ${nextProvider.label} (${nextMethod.label})`
|
|
204
|
+
});
|
|
205
|
+
} catch (err) {
|
|
206
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
207
|
+
setStep("error");
|
|
208
|
+
} finally {
|
|
209
|
+
if (timeout) {
|
|
210
|
+
clearTimeout(timeout);
|
|
211
|
+
}
|
|
212
|
+
await loginCancelRef.current?.();
|
|
213
|
+
loginCancelRef.current = null;
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
[close]
|
|
217
|
+
);
|
|
218
|
+
const startConnect = useCallback(async () => {
|
|
219
|
+
if (!provider || !method) {
|
|
220
|
+
close({ outcome: "cancelled" });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (method.kind === "api_key") {
|
|
224
|
+
setApiKey("");
|
|
225
|
+
setError(null);
|
|
226
|
+
setStatus(`Enter your ${provider.label} API key.`);
|
|
227
|
+
setStep("api-key");
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (method.kind === "oauth") {
|
|
231
|
+
await connectOAuth(provider, method);
|
|
232
|
+
}
|
|
233
|
+
}, [close, connectOAuth, method, provider]);
|
|
234
|
+
const handleSelect = useCallback(
|
|
235
|
+
async (option) => {
|
|
236
|
+
if (step === "provider") {
|
|
237
|
+
const nextProvider = getProviderAuthDefinitions().find(
|
|
238
|
+
(candidate) => candidate.providerId === option.value
|
|
239
|
+
);
|
|
240
|
+
if (nextProvider) {
|
|
241
|
+
await loadProvider(nextProvider);
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (step === "method" && provider) {
|
|
246
|
+
const nextMethod = provider.methods.find(
|
|
247
|
+
(candidate) => candidate.id === option.value
|
|
248
|
+
);
|
|
249
|
+
if (nextMethod) {
|
|
250
|
+
setMethod(nextMethod);
|
|
251
|
+
const profileId = getModelAuthProfileId(provider.providerId, nextMethod.id);
|
|
252
|
+
if (profiles.some((item) => item.id === profileId)) {
|
|
253
|
+
setStatus(`Manage ${provider.label} ${nextMethod.label}.`);
|
|
254
|
+
setStep("existing-action");
|
|
255
|
+
setSelectedIndex(0);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if (nextMethod.kind === "api_key") {
|
|
259
|
+
setApiKey("");
|
|
260
|
+
setError(null);
|
|
261
|
+
setStatus(`Enter your ${provider.label} API key.`);
|
|
262
|
+
setStep("api-key");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (nextMethod.kind === "oauth") {
|
|
266
|
+
await connectOAuth(provider, nextMethod);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (step === "existing-action" && provider && method && currentProfileId) {
|
|
272
|
+
if (option.value === "use") {
|
|
273
|
+
await setDefaultModelAuthProfile({
|
|
274
|
+
providerId: provider.providerId,
|
|
275
|
+
profileId: currentProfileId
|
|
276
|
+
});
|
|
277
|
+
close({
|
|
278
|
+
outcome: "success",
|
|
279
|
+
providerId: provider.providerId,
|
|
280
|
+
message: `Using ${provider.label} ${method.label}`
|
|
281
|
+
});
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (option.value === "replace") {
|
|
285
|
+
await startConnect();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (option.value === "delete") {
|
|
289
|
+
setStatus(`Press Enter to delete ${provider.label} ${method.label}.`);
|
|
290
|
+
setStep("delete-confirm");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
[
|
|
295
|
+
close,
|
|
296
|
+
connectOAuth,
|
|
297
|
+
currentProfileId,
|
|
298
|
+
loadProvider,
|
|
299
|
+
method,
|
|
300
|
+
profiles,
|
|
301
|
+
provider,
|
|
302
|
+
startConnect,
|
|
303
|
+
step
|
|
304
|
+
]
|
|
305
|
+
);
|
|
306
|
+
useImperativeHandle(
|
|
307
|
+
ref,
|
|
308
|
+
() => ({
|
|
309
|
+
handleInput: (input, key) => {
|
|
310
|
+
if (!isVisible) return false;
|
|
311
|
+
if (step === "api-key") {
|
|
312
|
+
if (key.escape) {
|
|
313
|
+
close({ outcome: "cancelled" });
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
if (key.return) {
|
|
317
|
+
void saveApiKey().catch(handleActionError);
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
if (key.backspace || key.delete) {
|
|
321
|
+
setApiKey((prev) => prev.slice(0, -1));
|
|
322
|
+
setError(null);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
if (input && !key.ctrl && !key.meta) {
|
|
326
|
+
setApiKey((prev) => prev + input);
|
|
327
|
+
setError(null);
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
if (step === "delete-confirm") {
|
|
333
|
+
if (key.escape) {
|
|
334
|
+
close({ outcome: "cancelled" });
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
if (key.return && provider && method && currentProfileId) {
|
|
338
|
+
void deleteModelAuthProfile(currentProfileId).then(
|
|
339
|
+
() => close({
|
|
340
|
+
outcome: "success",
|
|
341
|
+
providerId: provider.providerId,
|
|
342
|
+
message: `Deleted ${provider.label} ${method.label}`
|
|
343
|
+
})
|
|
344
|
+
).catch(handleActionError);
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
if (step === "oauth-progress") {
|
|
350
|
+
if (key.escape) {
|
|
351
|
+
close({ outcome: "cancelled" });
|
|
352
|
+
}
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
if (step === "error") {
|
|
356
|
+
if (key.escape || key.return) {
|
|
357
|
+
close({ outcome: "closed" });
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
return selectorRef.current?.handleInput(input, key) ?? false;
|
|
362
|
+
}
|
|
363
|
+
}),
|
|
364
|
+
[
|
|
365
|
+
close,
|
|
366
|
+
currentProfileId,
|
|
367
|
+
handleActionError,
|
|
368
|
+
isVisible,
|
|
369
|
+
method,
|
|
370
|
+
provider,
|
|
371
|
+
saveApiKey,
|
|
372
|
+
step
|
|
373
|
+
]
|
|
374
|
+
);
|
|
375
|
+
if (!isVisible) return null;
|
|
376
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
377
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Connect Model Provider" }) }),
|
|
378
|
+
/* @__PURE__ */ jsx(Text, { color: error ? "red" : "gray", children: error ?? status }),
|
|
379
|
+
step === "api-key" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
380
|
+
/* @__PURE__ */ jsx(Text, { children: maskSecret(apiKey) }),
|
|
381
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Enter save \u2022 Esc cancel" })
|
|
382
|
+
] }) : step === "delete-confirm" ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
383
|
+
/* @__PURE__ */ jsx(Text, { color: "red", children: "This removes saved credentials for this method." }),
|
|
384
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Enter delete \u2022 Esc cancel" })
|
|
385
|
+
] }) : step === "oauth-progress" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Esc cancel" }) }) : step === "error" ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Enter close \u2022 Esc close" }) }) : /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
386
|
+
BaseSelector,
|
|
387
|
+
{
|
|
388
|
+
ref: selectorRef,
|
|
389
|
+
items: activeItems,
|
|
390
|
+
isVisible: true,
|
|
391
|
+
selectedIndex,
|
|
392
|
+
onSelectIndex: setSelectedIndex,
|
|
393
|
+
onSelect: (item) => void handleSelect(item).catch(handleActionError),
|
|
394
|
+
onClose: () => close({ outcome: "cancelled" }),
|
|
395
|
+
title: step === "provider" ? "Providers" : step === "method" ? `${provider?.label ?? "Provider"} methods` : "Existing profile",
|
|
396
|
+
formatItem: (item, selected) => /* @__PURE__ */ jsxs(Text, { ...selected ? { color: "cyan" } : {}, children: [
|
|
397
|
+
selected ? "\u203A " : " ",
|
|
398
|
+
item.label,
|
|
399
|
+
item.hint ? /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
400
|
+
" \u2014 ",
|
|
401
|
+
item.hint
|
|
402
|
+
] }) : null
|
|
403
|
+
] })
|
|
404
|
+
}
|
|
405
|
+
) })
|
|
406
|
+
] });
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
var ConnectOverlay_default = ConnectOverlay;
|
|
410
|
+
export {
|
|
411
|
+
ConnectOverlay_default as default
|
|
412
|
+
};
|
|
@@ -76,6 +76,7 @@ var import_MarketplaceBrowser = __toESM(require("../components/overlays/Marketpl
|
|
|
76
76
|
var import_MarketplaceAddPrompt = __toESM(require("../components/overlays/MarketplaceAddPrompt.js"), 1);
|
|
77
77
|
var import_LoginOverlay = __toESM(require("../components/overlays/LoginOverlay.js"), 1);
|
|
78
78
|
var import_LogoutOverlay = __toESM(require("../components/overlays/LogoutOverlay.js"), 1);
|
|
79
|
+
var import_ConnectOverlay = __toESM(require("../components/overlays/ConnectOverlay.js"), 1);
|
|
79
80
|
var import_llm = require("@dexto/llm");
|
|
80
81
|
var import_core2 = require("@dexto/core");
|
|
81
82
|
var import_messageFormatting = require("../utils/messageFormatting.js");
|
|
@@ -149,6 +150,7 @@ const OverlayContainer = (0, import_react.forwardRef)(
|
|
|
149
150
|
const apiKeyInputRef = (0, import_react.useRef)(null);
|
|
150
151
|
const loginOverlayRef = (0, import_react.useRef)(null);
|
|
151
152
|
const logoutOverlayRef = (0, import_react.useRef)(null);
|
|
153
|
+
const connectOverlayRef = (0, import_react.useRef)(null);
|
|
152
154
|
const searchOverlayRef = (0, import_react.useRef)(null);
|
|
153
155
|
const promptListRef = (0, import_react.useRef)(null);
|
|
154
156
|
const promptAddChoiceRef = (0, import_react.useRef)(null);
|
|
@@ -235,6 +237,8 @@ const OverlayContainer = (0, import_react.forwardRef)(
|
|
|
235
237
|
return loginOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
236
238
|
case "logout":
|
|
237
239
|
return logoutOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
240
|
+
case "connect":
|
|
241
|
+
return connectOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
238
242
|
case "search":
|
|
239
243
|
return searchOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
240
244
|
case "prompt-list":
|
|
@@ -1200,6 +1204,52 @@ ${result.context}`,
|
|
|
1200
1204
|
},
|
|
1201
1205
|
[handleClose, setMessages]
|
|
1202
1206
|
);
|
|
1207
|
+
const handleConnectDone = (0, import_react.useCallback)(
|
|
1208
|
+
async (outcome) => {
|
|
1209
|
+
handleClose();
|
|
1210
|
+
if (outcome.outcome === "closed") {
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
setMessages((prev) => [
|
|
1214
|
+
...prev,
|
|
1215
|
+
{
|
|
1216
|
+
id: (0, import_idGenerator.generateMessageId)("system"),
|
|
1217
|
+
role: "system",
|
|
1218
|
+
content: outcome.outcome === "success" ? `\u2705 ${outcome.message}` : "Model provider connection cancelled.",
|
|
1219
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1220
|
+
}
|
|
1221
|
+
]);
|
|
1222
|
+
if (outcome.outcome !== "success") {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const currentConfig = agent.getCurrentLLMConfig(session.id || void 0);
|
|
1226
|
+
if (currentConfig.provider !== outcome.providerId) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
try {
|
|
1230
|
+
await agent.switchLLM(
|
|
1231
|
+
{
|
|
1232
|
+
provider: currentConfig.provider,
|
|
1233
|
+
model: currentConfig.model,
|
|
1234
|
+
...currentConfig.baseURL ? { baseURL: currentConfig.baseURL } : {},
|
|
1235
|
+
...currentConfig.reasoning ? { reasoning: currentConfig.reasoning } : {}
|
|
1236
|
+
},
|
|
1237
|
+
session.id || void 0
|
|
1238
|
+
);
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
setMessages((prev) => [
|
|
1241
|
+
...prev,
|
|
1242
|
+
{
|
|
1243
|
+
id: (0, import_idGenerator.generateMessageId)("error"),
|
|
1244
|
+
role: "system",
|
|
1245
|
+
content: `Failed to apply model provider connection: ${error instanceof Error ? error.message : String(error)}`,
|
|
1246
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1247
|
+
}
|
|
1248
|
+
]);
|
|
1249
|
+
}
|
|
1250
|
+
},
|
|
1251
|
+
[agent, handleClose, session.id, setMessages]
|
|
1252
|
+
);
|
|
1203
1253
|
const handleLogLevelSelect = (0, import_react.useCallback)(
|
|
1204
1254
|
(level) => {
|
|
1205
1255
|
setUi((prev) => ({ ...prev, activeOverlay: "none", mcpWizardServerType: null }));
|
|
@@ -2452,6 +2502,14 @@ Use /${data.name} to run it.`,
|
|
|
2452
2502
|
onDone: handleLogoutDone
|
|
2453
2503
|
}
|
|
2454
2504
|
) }),
|
|
2505
|
+
ui.activeOverlay === "connect" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2506
|
+
import_ConnectOverlay.default,
|
|
2507
|
+
{
|
|
2508
|
+
ref: connectOverlayRef,
|
|
2509
|
+
isVisible: true,
|
|
2510
|
+
onDone: handleConnectDone
|
|
2511
|
+
}
|
|
2512
|
+
) }),
|
|
2455
2513
|
ui.activeOverlay === "api-key-input" && ui.pendingModelSwitch && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2456
2514
|
import_ApiKeyInput.default,
|
|
2457
2515
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverlayContainer.d.ts","sourceRoot":"","sources":["../../src/containers/OverlayContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAyE,MAAM,OAAO,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,iCAAiC,CAAC;AAmGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"OverlayContainer.d.ts","sourceRoot":"","sources":["../../src/containers/OverlayContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAyE,MAAM,OAAO,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,iCAAiC,CAAC;AAmGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAuC3D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAuC3D,MAAM,WAAW,sBAAsB;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,qBAAqB;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAC1E,KAAK,EAAE,eAAe,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,sGAi/F5B,CAAC"}
|
|
@@ -56,6 +56,7 @@ import MarketplaceBrowser from "../components/overlays/MarketplaceBrowser.js";
|
|
|
56
56
|
import MarketplaceAddPrompt from "../components/overlays/MarketplaceAddPrompt.js";
|
|
57
57
|
import LoginOverlay from "../components/overlays/LoginOverlay.js";
|
|
58
58
|
import LogoutOverlay from "../components/overlays/LogoutOverlay.js";
|
|
59
|
+
import ConnectOverlay from "../components/overlays/ConnectOverlay.js";
|
|
59
60
|
import { LLM_PROVIDERS, getModelDisplayName, getReasoningProfile } from "@dexto/llm";
|
|
60
61
|
import { DextoValidationError, LLMErrorCode } from "@dexto/core";
|
|
61
62
|
import { createUserMessage, convertHistoryToUIMessages } from "../utils/messageFormatting.js";
|
|
@@ -129,6 +130,7 @@ const OverlayContainer = forwardRef(
|
|
|
129
130
|
const apiKeyInputRef = useRef(null);
|
|
130
131
|
const loginOverlayRef = useRef(null);
|
|
131
132
|
const logoutOverlayRef = useRef(null);
|
|
133
|
+
const connectOverlayRef = useRef(null);
|
|
132
134
|
const searchOverlayRef = useRef(null);
|
|
133
135
|
const promptListRef = useRef(null);
|
|
134
136
|
const promptAddChoiceRef = useRef(null);
|
|
@@ -215,6 +217,8 @@ const OverlayContainer = forwardRef(
|
|
|
215
217
|
return loginOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
216
218
|
case "logout":
|
|
217
219
|
return logoutOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
220
|
+
case "connect":
|
|
221
|
+
return connectOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
218
222
|
case "search":
|
|
219
223
|
return searchOverlayRef.current?.handleInput(inputStr, key) ?? false;
|
|
220
224
|
case "prompt-list":
|
|
@@ -1180,6 +1184,52 @@ ${result.context}`,
|
|
|
1180
1184
|
},
|
|
1181
1185
|
[handleClose, setMessages]
|
|
1182
1186
|
);
|
|
1187
|
+
const handleConnectDone = useCallback(
|
|
1188
|
+
async (outcome) => {
|
|
1189
|
+
handleClose();
|
|
1190
|
+
if (outcome.outcome === "closed") {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
setMessages((prev) => [
|
|
1194
|
+
...prev,
|
|
1195
|
+
{
|
|
1196
|
+
id: generateMessageId("system"),
|
|
1197
|
+
role: "system",
|
|
1198
|
+
content: outcome.outcome === "success" ? `\u2705 ${outcome.message}` : "Model provider connection cancelled.",
|
|
1199
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1200
|
+
}
|
|
1201
|
+
]);
|
|
1202
|
+
if (outcome.outcome !== "success") {
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
const currentConfig = agent.getCurrentLLMConfig(session.id || void 0);
|
|
1206
|
+
if (currentConfig.provider !== outcome.providerId) {
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
await agent.switchLLM(
|
|
1211
|
+
{
|
|
1212
|
+
provider: currentConfig.provider,
|
|
1213
|
+
model: currentConfig.model,
|
|
1214
|
+
...currentConfig.baseURL ? { baseURL: currentConfig.baseURL } : {},
|
|
1215
|
+
...currentConfig.reasoning ? { reasoning: currentConfig.reasoning } : {}
|
|
1216
|
+
},
|
|
1217
|
+
session.id || void 0
|
|
1218
|
+
);
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
setMessages((prev) => [
|
|
1221
|
+
...prev,
|
|
1222
|
+
{
|
|
1223
|
+
id: generateMessageId("error"),
|
|
1224
|
+
role: "system",
|
|
1225
|
+
content: `Failed to apply model provider connection: ${error instanceof Error ? error.message : String(error)}`,
|
|
1226
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1227
|
+
}
|
|
1228
|
+
]);
|
|
1229
|
+
}
|
|
1230
|
+
},
|
|
1231
|
+
[agent, handleClose, session.id, setMessages]
|
|
1232
|
+
);
|
|
1183
1233
|
const handleLogLevelSelect = useCallback(
|
|
1184
1234
|
(level) => {
|
|
1185
1235
|
setUi((prev) => ({ ...prev, activeOverlay: "none", mcpWizardServerType: null }));
|
|
@@ -2432,6 +2482,14 @@ Use /${data.name} to run it.`,
|
|
|
2432
2482
|
onDone: handleLogoutDone
|
|
2433
2483
|
}
|
|
2434
2484
|
) }),
|
|
2485
|
+
ui.activeOverlay === "connect" && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
2486
|
+
ConnectOverlay,
|
|
2487
|
+
{
|
|
2488
|
+
ref: connectOverlayRef,
|
|
2489
|
+
isVisible: true,
|
|
2490
|
+
onDone: handleConnectDone
|
|
2491
|
+
}
|
|
2492
|
+
) }),
|
|
2435
2493
|
ui.activeOverlay === "api-key-input" && ui.pendingModelSwitch && /* @__PURE__ */ jsx(
|
|
2436
2494
|
ApiKeyInput,
|
|
2437
2495
|
{
|
|
@@ -67,17 +67,15 @@ function useTokenCounter({ agent, isActive }) {
|
|
|
67
67
|
"llm:response",
|
|
68
68
|
(payload) => {
|
|
69
69
|
const usage = payload.tokenUsage;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
setCumulativeOutputTokens((prev) => prev + outputTokens);
|
|
80
|
-
}
|
|
70
|
+
const rawInputTokens = usage.inputTokens ?? 0;
|
|
71
|
+
const cacheWriteTokens = usage.cacheWriteTokens ?? 0;
|
|
72
|
+
const inputTokens = Math.max(0, rawInputTokens - cacheWriteTokens);
|
|
73
|
+
if (inputTokens > 0) {
|
|
74
|
+
setLastInputTokens(inputTokens);
|
|
75
|
+
}
|
|
76
|
+
const outputTokens = usage.outputTokens ?? 0;
|
|
77
|
+
if (outputTokens > 0) {
|
|
78
|
+
setCumulativeOutputTokens((prev) => prev + outputTokens);
|
|
81
79
|
}
|
|
82
80
|
currentCharCountRef.current = 0;
|
|
83
81
|
setCurrentSegmentEstimate(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenCounter.d.ts","sourceRoot":"","sources":["../../src/hooks/useTokenCounter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAChC,+CAA+C;IAC/C,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAC/B,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;CACrB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"useTokenCounter.d.ts","sourceRoot":"","sources":["../../src/hooks/useTokenCounter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAChC,+CAA+C;IAC/C,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAC/B,yDAAyD;IACzD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qDAAqD;IACrD,sBAAsB,EAAE,MAAM,CAAC;IAC/B,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;CACrB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,kBAAkB,CA2F5F"}
|
|
@@ -44,17 +44,15 @@ function useTokenCounter({ agent, isActive }) {
|
|
|
44
44
|
"llm:response",
|
|
45
45
|
(payload) => {
|
|
46
46
|
const usage = payload.tokenUsage;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
setCumulativeOutputTokens((prev) => prev + outputTokens);
|
|
57
|
-
}
|
|
47
|
+
const rawInputTokens = usage.inputTokens ?? 0;
|
|
48
|
+
const cacheWriteTokens = usage.cacheWriteTokens ?? 0;
|
|
49
|
+
const inputTokens = Math.max(0, rawInputTokens - cacheWriteTokens);
|
|
50
|
+
if (inputTokens > 0) {
|
|
51
|
+
setLastInputTokens(inputTokens);
|
|
52
|
+
}
|
|
53
|
+
const outputTokens = usage.outputTokens ?? 0;
|
|
54
|
+
if (outputTokens > 0) {
|
|
55
|
+
setCumulativeOutputTokens((prev) => prev + outputTokens);
|
|
58
56
|
}
|
|
59
57
|
currentCharCountRef.current = 0;
|
|
60
58
|
setCurrentSegmentEstimate(0);
|