@quatcode/agent 0.2.0 → 0.2.1
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/cli.js +34 -3
- package/dist/cli.js.map +1 -1
- package/dist/input.d.ts +5 -0
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +24 -3
- package/dist/input.js.map +1 -1
- package/dist/models.d.ts +27 -7
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +215 -93
- package/dist/models.js.map +1 -1
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +28 -13
- package/dist/picker.js.map +1 -1
- package/dist/screen.d.ts +2 -0
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +9 -0
- package/dist/screen.js.map +1 -1
- package/dist/store.d.ts +10 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js.map +1 -1
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +351 -98
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImagePart } from "@quatcode/core";
|
|
1
2
|
export type TuiOptions = {
|
|
2
3
|
dir: string;
|
|
3
4
|
model?: string;
|
|
@@ -13,4 +14,9 @@ export type TuiOptions = {
|
|
|
13
14
|
};
|
|
14
15
|
};
|
|
15
16
|
export declare function runTui(options: TuiOptions): Promise<number>;
|
|
17
|
+
export declare function nextImageIndex(text: string): number;
|
|
18
|
+
export declare function extractInputImages(text: string, images: ReadonlyMap<number, ImagePart>): {
|
|
19
|
+
text: string;
|
|
20
|
+
images: ImagePart[];
|
|
21
|
+
};
|
|
16
22
|
//# sourceMappingURL=tui.d.ts.map
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAEV,SAAS,EAMV,MAAM,gBAAgB,CAAC;AAoFxB,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,EAAE,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAA;KAAE,CAAC;CAC/D,CAAC;AAwCF,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAWjE;AAmlFD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,GACrC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,CAavC"}
|
package/dist/tui.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import {
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { Session, ToolRegistry, addUsage, emptyUsage, estimateCost, runAgent, } from "@quatcode/core";
|
|
4
5
|
import { analyzeCommand, createProjectTools, McpManager } from "@quatcode/tools";
|
|
5
6
|
import { buildProjectContext, createBrainTools, scanProject } from "@quatcode/brain";
|
|
6
7
|
import { Keyboard } from "./keyboard.js";
|
|
@@ -10,7 +11,7 @@ import { Screen } from "./screen.js";
|
|
|
10
11
|
import { TurnController, fmtCost, fmtDuration, fmtTokens } from "./turn.js";
|
|
11
12
|
import { renderBanner } from "./logo.js";
|
|
12
13
|
import { renderMarkdown } from "./markdown.js";
|
|
13
|
-
import {
|
|
14
|
+
import { ADD_PROVIDER, allProviders, buildProvider, defaultModelFor, effortsForModel, hasKey, keyEnvFor, probeProviderModels, providerEnvKey, providerMeta, providerSlug, registerCustomProvider, removeCustomProvider, resolveProviderForModel, } from "./models.js";
|
|
14
15
|
import { activeThemeId, bg, bold, buildColorRemap, clipAnsi, fg, getThemes, glyphs, padEndTo, palette, remapColors, setTheme, stringWidth, stripAnsi, tone, } from "./theme.js";
|
|
15
16
|
import { listSessionsForDir, loadConfig, makeSessionId, saveConfig, saveSession, deleteSession } from "./store.js";
|
|
16
17
|
import { configFile, conversationKey, deleteConversation, displayTitle, latestPerConversation, messagesForStorage, sortConversations, updateConversation, } from "./store.js";
|
|
@@ -22,6 +23,7 @@ const COMMAND_INFO = [
|
|
|
22
23
|
{ name: "/help", desc: "show this help" },
|
|
23
24
|
{ name: "/new", desc: "new conversation (clears the screen)" },
|
|
24
25
|
{ name: "/model", args: "[id]", desc: "pick or set the model" },
|
|
26
|
+
{ name: "/provider", args: "[add|list|remove]", desc: "connect a provider by API key" },
|
|
25
27
|
{ name: "/effort", args: "[level]", desc: "reasoning effort (minimal…high)" },
|
|
26
28
|
{ name: "/key", desc: "enter the API key for the current provider" },
|
|
27
29
|
{ name: "/dir", args: "[path]", desc: "change the project directory" },
|
|
@@ -123,7 +125,7 @@ class TuiApp {
|
|
|
123
125
|
lastTurn = null;
|
|
124
126
|
turnUndo = null;
|
|
125
127
|
pendingInitial = null;
|
|
126
|
-
pendingImages =
|
|
128
|
+
pendingImages = new Map();
|
|
127
129
|
userMarkers = [];
|
|
128
130
|
messageCursor = -1;
|
|
129
131
|
selection = null;
|
|
@@ -164,6 +166,17 @@ class TuiApp {
|
|
|
164
166
|
if (value && process.env[name] === undefined)
|
|
165
167
|
process.env[name] = value;
|
|
166
168
|
}
|
|
169
|
+
for (const [id, custom] of Object.entries(this.config.customProviders ?? {})) {
|
|
170
|
+
registerCustomProvider({
|
|
171
|
+
id,
|
|
172
|
+
label: custom.label,
|
|
173
|
+
envKey: custom.envKey,
|
|
174
|
+
kind: "openai",
|
|
175
|
+
baseUrl: custom.baseUrl,
|
|
176
|
+
defaultModel: custom.models[0]?.id ?? "",
|
|
177
|
+
models: custom.models,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
167
180
|
this.effort = this.opts.effort ?? this.config.effort ?? null;
|
|
168
181
|
setTheme(this.config.theme ?? "quatcode");
|
|
169
182
|
this.screen.applyBackground();
|
|
@@ -216,10 +229,12 @@ class TuiApp {
|
|
|
216
229
|
this.append([` ${tone.mist("// cancelled")}`]);
|
|
217
230
|
continue;
|
|
218
231
|
}
|
|
219
|
-
const
|
|
220
|
-
this.
|
|
221
|
-
const
|
|
222
|
-
|
|
232
|
+
const extracted = extractInputImages(result.text, this.pendingImages);
|
|
233
|
+
this.pendingImages = new Map();
|
|
234
|
+
const input = extracted.text;
|
|
235
|
+
const images = extracted.images;
|
|
236
|
+
if (input)
|
|
237
|
+
this.buffer.addHistory(input);
|
|
223
238
|
const isCommand = input.startsWith("/");
|
|
224
239
|
if (!isCommand)
|
|
225
240
|
this.clearSplash();
|
|
@@ -305,7 +320,11 @@ class TuiApp {
|
|
|
305
320
|
onKeys = (keys) => {
|
|
306
321
|
for (const key of keys) {
|
|
307
322
|
if (key.type === "resize") {
|
|
323
|
+
this.screen.applyBackground();
|
|
308
324
|
this.scheduleRender();
|
|
325
|
+
const settle = setTimeout(() => this.scheduleRender(), 150);
|
|
326
|
+
if (typeof settle.unref === "function")
|
|
327
|
+
settle.unref();
|
|
309
328
|
continue;
|
|
310
329
|
}
|
|
311
330
|
if (key.type === "mouse") {
|
|
@@ -458,7 +477,8 @@ class TuiApp {
|
|
|
458
477
|
this.buffer.killToEnd();
|
|
459
478
|
break;
|
|
460
479
|
case "w":
|
|
461
|
-
this.
|
|
480
|
+
if (!this.deleteImageTokenBefore())
|
|
481
|
+
this.buffer.deleteWordBefore();
|
|
462
482
|
break;
|
|
463
483
|
case "p":
|
|
464
484
|
this.buffer.historyPrev();
|
|
@@ -478,8 +498,14 @@ class TuiApp {
|
|
|
478
498
|
this.buffer.moveWord(-1);
|
|
479
499
|
else if (key.ch === "f" || key.ch === "F")
|
|
480
500
|
this.buffer.moveWord(1);
|
|
481
|
-
else if (key.ch === "d" || key.ch === "D")
|
|
482
|
-
this.
|
|
501
|
+
else if (key.ch === "d" || key.ch === "D") {
|
|
502
|
+
if (!this.deleteImageTokenAfter())
|
|
503
|
+
this.buffer.deleteWordAfter();
|
|
504
|
+
}
|
|
505
|
+
else if (key.ch === "v" || key.ch === "V") {
|
|
506
|
+
void this.pasteFromClipboard();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
483
509
|
break;
|
|
484
510
|
case "nav":
|
|
485
511
|
if ((key.dir === "up" || key.dir === "down") &&
|
|
@@ -555,10 +581,12 @@ class TuiApp {
|
|
|
555
581
|
this.toggleMode();
|
|
556
582
|
break;
|
|
557
583
|
case "backspace":
|
|
558
|
-
this.
|
|
584
|
+
if (!this.deleteImageTokenBefore())
|
|
585
|
+
this.buffer.backspace();
|
|
559
586
|
break;
|
|
560
587
|
case "delete":
|
|
561
|
-
this.
|
|
588
|
+
if (!this.deleteImageTokenAfter())
|
|
589
|
+
this.buffer.deleteForward();
|
|
562
590
|
break;
|
|
563
591
|
case "escape":
|
|
564
592
|
this.finishLine({ kind: "cancel" });
|
|
@@ -745,21 +773,44 @@ class TuiApp {
|
|
|
745
773
|
async pasteFromClipboard() {
|
|
746
774
|
const image = readClipboardImage();
|
|
747
775
|
if (image) {
|
|
748
|
-
this.
|
|
749
|
-
const kb = Math.max(1, Math.round((image.data.length * 3) / 4 / 1024));
|
|
750
|
-
this.append([
|
|
751
|
-
` ${tone.accent(glyphs.diamond)} ${tone.mist(`// image attached (${image.mediaType} · ${kb} KB) · it will be sent with the next message`)}`,
|
|
752
|
-
]);
|
|
776
|
+
this.attachImageMarker(image);
|
|
753
777
|
return;
|
|
754
778
|
}
|
|
755
779
|
const text = readClipboardText();
|
|
756
780
|
if (text && text.length > 0) {
|
|
781
|
+
const fromPath = await imageFromPath(text);
|
|
782
|
+
if (fromPath) {
|
|
783
|
+
this.attachImageMarker(fromPath);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
757
786
|
this.buffer.insert(text.replace(/\r\n?/g, "\n"));
|
|
758
787
|
this.scheduleRender();
|
|
759
788
|
return;
|
|
760
789
|
}
|
|
761
790
|
this.append([` ${tone.mist("// clipboard is empty or unavailable")}`]);
|
|
762
791
|
}
|
|
792
|
+
deleteImageTokenBefore() {
|
|
793
|
+
const length = imageTokenBefore(this.buffer.cursorLineBefore());
|
|
794
|
+
if (length <= 0)
|
|
795
|
+
return false;
|
|
796
|
+
this.buffer.deleteBefore(length);
|
|
797
|
+
return true;
|
|
798
|
+
}
|
|
799
|
+
deleteImageTokenAfter() {
|
|
800
|
+
const length = imageTokenAfter(this.buffer.cursorLineAfter());
|
|
801
|
+
if (length <= 0)
|
|
802
|
+
return false;
|
|
803
|
+
this.buffer.deleteAfter(length);
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
attachImageMarker(image) {
|
|
807
|
+
const index = nextImageIndex(this.buffer.text());
|
|
808
|
+
this.pendingImages.set(index, image);
|
|
809
|
+
const current = this.buffer.text();
|
|
810
|
+
const needsSpace = current.length > 0 && !/\s$/.test(current);
|
|
811
|
+
this.buffer.insert(`${needsSpace ? " " : ""}[Image ${index}] `);
|
|
812
|
+
this.scheduleRender();
|
|
813
|
+
}
|
|
763
814
|
copySelection() {
|
|
764
815
|
const text = this.selectionText();
|
|
765
816
|
this.selection = null;
|
|
@@ -976,6 +1027,7 @@ class TuiApp {
|
|
|
976
1027
|
prompt: this.inputPrompt,
|
|
977
1028
|
placeholder: this.inputPlaceholder,
|
|
978
1029
|
mask: this.inputMask,
|
|
1030
|
+
style: styleInputLine,
|
|
979
1031
|
});
|
|
980
1032
|
this.lastInputRender = rendered;
|
|
981
1033
|
const suggestions = this.suggestions();
|
|
@@ -1104,40 +1156,33 @@ class TuiApp {
|
|
|
1104
1156
|
return `${tone.silver(`${this.providerId} · ${this.model}`)}${keyState}`;
|
|
1105
1157
|
}
|
|
1106
1158
|
detectProvider() {
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
if (process.env.GEMINI_API_KEY)
|
|
1112
|
-
return "gemini";
|
|
1159
|
+
for (const provider of allProviders()) {
|
|
1160
|
+
if (process.env[provider.envKey])
|
|
1161
|
+
return provider.id;
|
|
1162
|
+
}
|
|
1113
1163
|
return null;
|
|
1114
1164
|
}
|
|
1115
1165
|
detectEnvSetup() {
|
|
1166
|
+
const envModelFor = (id) => {
|
|
1167
|
+
const meta = providerMeta(id);
|
|
1168
|
+
if (!meta)
|
|
1169
|
+
return undefined;
|
|
1170
|
+
return process.env[`${meta.envKey.replace(/_API_KEY$/, "")}_MODEL`];
|
|
1171
|
+
};
|
|
1172
|
+
const pick = (id) => ({
|
|
1173
|
+
id,
|
|
1174
|
+
model: envModelFor(id) ?? defaultModelFor(id),
|
|
1175
|
+
});
|
|
1116
1176
|
const override = process.env.QUATCODE_PROVIDER?.toLowerCase();
|
|
1117
|
-
if (override
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
}[override];
|
|
1123
|
-
return { id: override, model: envModel ?? defaultModelFor(override) };
|
|
1124
|
-
}
|
|
1125
|
-
if (process.env.ANTHROPIC_MODEL)
|
|
1126
|
-
return { id: "anthropic", model: process.env.ANTHROPIC_MODEL };
|
|
1127
|
-
if (process.env.OPENAI_MODEL)
|
|
1128
|
-
return { id: "openai", model: process.env.OPENAI_MODEL };
|
|
1129
|
-
if (process.env.GEMINI_MODEL)
|
|
1130
|
-
return { id: "gemini", model: process.env.GEMINI_MODEL };
|
|
1131
|
-
try {
|
|
1132
|
-
const provider = createProviderFromEnv();
|
|
1133
|
-
const id = provider.id;
|
|
1134
|
-
if (provider.defaultModel &&
|
|
1135
|
-
(id === "anthropic" || id === "openai" || id === "gemini")) {
|
|
1136
|
-
return { id, model: provider.defaultModel };
|
|
1137
|
-
}
|
|
1177
|
+
if (override && providerMeta(override))
|
|
1178
|
+
return pick(override);
|
|
1179
|
+
for (const provider of allProviders()) {
|
|
1180
|
+
if (envModelFor(provider.id))
|
|
1181
|
+
return pick(provider.id);
|
|
1138
1182
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1183
|
+
for (const provider of allProviders()) {
|
|
1184
|
+
if (process.env[provider.envKey])
|
|
1185
|
+
return pick(provider.id);
|
|
1141
1186
|
}
|
|
1142
1187
|
return null;
|
|
1143
1188
|
}
|
|
@@ -1227,65 +1272,195 @@ class TuiApp {
|
|
|
1227
1272
|
return null;
|
|
1228
1273
|
}
|
|
1229
1274
|
}
|
|
1230
|
-
async
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1275
|
+
async changeModel() {
|
|
1276
|
+
for (;;) {
|
|
1277
|
+
const pickerEntries = [
|
|
1278
|
+
{ kind: "header", label: "setup" },
|
|
1279
|
+
{
|
|
1280
|
+
kind: "item",
|
|
1281
|
+
value: ADD_PROVIDER,
|
|
1282
|
+
label: "add a provider…",
|
|
1283
|
+
hint: "connect by API key",
|
|
1284
|
+
},
|
|
1285
|
+
];
|
|
1286
|
+
for (const provider of allProviders()) {
|
|
1287
|
+
if (provider.models.length === 0)
|
|
1288
|
+
continue;
|
|
1289
|
+
pickerEntries.push({
|
|
1290
|
+
kind: "header",
|
|
1291
|
+
label: `${provider.label} · ${hasKey(provider.id) ? "key set" : "no key"}${provider.custom ? " · added" : ""}`,
|
|
1292
|
+
});
|
|
1293
|
+
for (const model of provider.models) {
|
|
1294
|
+
pickerEntries.push({
|
|
1295
|
+
kind: "item",
|
|
1296
|
+
value: `${provider.id}:${model.id}`,
|
|
1297
|
+
label: model.id,
|
|
1298
|
+
hint: model.label,
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1239
1301
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1302
|
+
const chosen = await this.openPicker(new Picker({ title: "select a model", entries: pickerEntries, filterable: true }));
|
|
1303
|
+
if (!chosen)
|
|
1304
|
+
return false;
|
|
1305
|
+
if (chosen === ADD_PROVIDER) {
|
|
1306
|
+
const added = await this.addProviderFlow();
|
|
1307
|
+
if (added) {
|
|
1308
|
+
this.renderNow();
|
|
1309
|
+
await this.pause(650);
|
|
1310
|
+
}
|
|
1311
|
+
continue;
|
|
1242
1312
|
}
|
|
1313
|
+
const separator = chosen.indexOf(":");
|
|
1314
|
+
const model = chosen.slice(separator + 1);
|
|
1315
|
+
this.applyModel(chosen.slice(0, separator), model);
|
|
1316
|
+
await this.chooseEffortForModel(model);
|
|
1317
|
+
return true;
|
|
1243
1318
|
}
|
|
1244
|
-
this.setStatus(null);
|
|
1245
|
-
return result;
|
|
1246
1319
|
}
|
|
1247
|
-
async
|
|
1248
|
-
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
pickerEntries.push({
|
|
1262
|
-
kind: "item",
|
|
1263
|
-
value: `${provider.id}:${model.id}`,
|
|
1264
|
-
label: model.id,
|
|
1265
|
-
hint: model.label,
|
|
1266
|
-
});
|
|
1320
|
+
async providerCommand(arg) {
|
|
1321
|
+
const parts = arg.split(/\s+/).filter(Boolean);
|
|
1322
|
+
const sub = (parts[0] ?? "").toLowerCase();
|
|
1323
|
+
const rest = parts.slice(1).join(" ").trim();
|
|
1324
|
+
if (!sub || sub === "add" || sub === "connect") {
|
|
1325
|
+
await this.addProviderFlow();
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
if (sub === "list" || sub === "ls") {
|
|
1329
|
+
const lines = [` ${tone.mist("// PROVIDERS")}`];
|
|
1330
|
+
for (const provider of allProviders()) {
|
|
1331
|
+
const state = hasKey(provider.id) ? tone.accent("key set") : tone.mist("no key");
|
|
1332
|
+
lines.push(` ${padEndTo(tone.bone(provider.label), 18)}${tone.silver(`${provider.models.length} models`)} ${state}${provider.custom ? tone.mist(" · added") : ""}`);
|
|
1333
|
+
lines.push(` ${tone.mist(`${provider.envKey}${provider.baseUrl ? ` · ${provider.baseUrl}` : ""}`)}`);
|
|
1267
1334
|
}
|
|
1335
|
+
lines.push("");
|
|
1336
|
+
lines.push(` ${tone.mist("// add: /provider add (or /model → add a provider…) · remove: /provider remove <name>")}`);
|
|
1337
|
+
this.append(lines);
|
|
1338
|
+
return;
|
|
1268
1339
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1340
|
+
if (sub === "remove" || sub === "rm") {
|
|
1341
|
+
if (!rest) {
|
|
1342
|
+
this.append([` ${tone.mist("// usage: /provider remove <name>")}`]);
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
const meta = providerMeta(rest);
|
|
1346
|
+
if (!meta) {
|
|
1347
|
+
this.append([` ${tone.red(`// no provider named ${rest}`)}`]);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
if (!meta.custom) {
|
|
1351
|
+
this.append([` ${tone.red(`// ${rest} is a built-in provider and cannot be removed`)}`]);
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
const confirmed = await this.confirm(`remove provider "${rest}"?`);
|
|
1355
|
+
if (!confirmed) {
|
|
1356
|
+
this.append([` ${tone.mist("// cancelled")}`]);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
removeCustomProvider(rest);
|
|
1360
|
+
if (meta.envKey) {
|
|
1361
|
+
const keys = { ...(this.config.keys ?? {}) };
|
|
1362
|
+
if (keys[meta.envKey]) {
|
|
1363
|
+
delete keys[meta.envKey];
|
|
1364
|
+
this.config.keys = keys;
|
|
1365
|
+
}
|
|
1366
|
+
delete process.env[meta.envKey];
|
|
1367
|
+
}
|
|
1368
|
+
if (this.config.customProviders?.[rest]) {
|
|
1369
|
+
const next = { ...this.config.customProviders };
|
|
1370
|
+
delete next[rest];
|
|
1371
|
+
this.config.customProviders = next;
|
|
1372
|
+
}
|
|
1373
|
+
if (this.providerId === rest) {
|
|
1374
|
+
this.applyModel("anthropic", defaultModelFor("anthropic"));
|
|
1375
|
+
this.append([` ${tone.mist(`// MODEL → ${this.providerId} · ${this.model}`)}`]);
|
|
1376
|
+
}
|
|
1377
|
+
await saveConfig({ ...this.config }).catch(() => undefined);
|
|
1378
|
+
this.append([
|
|
1379
|
+
` ${tone.accent(glyphs.diamond)} ${tone.mist(`// PROVIDER REMOVED → ${rest}`)}`,
|
|
1380
|
+
]);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
this.append([` ${tone.mist("// usage: /provider [add|list|remove <name>]")}`]);
|
|
1384
|
+
}
|
|
1385
|
+
async addProviderFlow() {
|
|
1386
|
+
const nameResult = await this.readLine({
|
|
1387
|
+
prompt: ` ${tone.bone("PROVIDER NAME")} ${tone.mist(glyphs.prompt)} `,
|
|
1388
|
+
placeholder: "e.g. together, fireworks, cerebras",
|
|
1389
|
+
});
|
|
1390
|
+
if (nameResult.kind !== "submit" || !nameResult.text.trim()) {
|
|
1391
|
+
this.append([` ${tone.mist("// cancelled")}`]);
|
|
1272
1392
|
return false;
|
|
1273
|
-
if (chosen === CUSTOM_MODEL) {
|
|
1274
|
-
const result = await this.readLine({
|
|
1275
|
-
prompt: ` ${tone.bone("MODEL ID")} ${tone.mist(glyphs.prompt)} `,
|
|
1276
|
-
placeholder: "e.g. claude-sonnet-5-5",
|
|
1277
|
-
});
|
|
1278
|
-
if (result.kind !== "submit" || !result.text.trim())
|
|
1279
|
-
return false;
|
|
1280
|
-
const id = result.text.trim();
|
|
1281
|
-
this.applyModel(resolveProviderForModel(id) ?? this.providerId, id);
|
|
1282
|
-
await this.chooseEffortForModel(id);
|
|
1283
|
-
return true;
|
|
1284
1393
|
}
|
|
1285
|
-
const
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1394
|
+
const id = providerSlug(nameResult.text);
|
|
1395
|
+
const existing = providerMeta(id);
|
|
1396
|
+
if (existing && !existing.custom) {
|
|
1397
|
+
this.append([` ${tone.red(`// ${id} is already a built-in provider — pick it from the list`)}`]);
|
|
1398
|
+
return false;
|
|
1399
|
+
}
|
|
1400
|
+
const urlResult = await this.readLine({
|
|
1401
|
+
prompt: ` ${tone.bone("BASE URL")} ${tone.mist(glyphs.prompt)} `,
|
|
1402
|
+
placeholder: "https://api.example.com/v1",
|
|
1403
|
+
});
|
|
1404
|
+
if (urlResult.kind !== "submit" || !urlResult.text.trim()) {
|
|
1405
|
+
this.append([` ${tone.mist("// cancelled")}`]);
|
|
1406
|
+
return false;
|
|
1407
|
+
}
|
|
1408
|
+
const baseUrl = urlResult.text.trim().replace(/\/+$/, "");
|
|
1409
|
+
if (!/^https?:\/\//i.test(baseUrl)) {
|
|
1410
|
+
this.append([` ${tone.red("// base url must start with http:// or https://")}`]);
|
|
1411
|
+
return false;
|
|
1412
|
+
}
|
|
1413
|
+
const keyResult = await this.readLine({
|
|
1414
|
+
prompt: ` ${tone.bone("API KEY")} ${tone.mist(glyphs.prompt)} `,
|
|
1415
|
+
mask: true,
|
|
1416
|
+
placeholder: "",
|
|
1417
|
+
});
|
|
1418
|
+
if (keyResult.kind !== "submit" || !keyResult.text.trim()) {
|
|
1419
|
+
this.append([` ${tone.mist("// cancelled")}`]);
|
|
1420
|
+
return false;
|
|
1421
|
+
}
|
|
1422
|
+
const apiKey = keyResult.text.trim();
|
|
1423
|
+
this.setStatus({ label: `CHECKING ${id.toUpperCase()}` });
|
|
1424
|
+
let models = [];
|
|
1425
|
+
try {
|
|
1426
|
+
models = await probeProviderModels(baseUrl, apiKey);
|
|
1427
|
+
}
|
|
1428
|
+
catch (err) {
|
|
1429
|
+
this.setStatus(null);
|
|
1430
|
+
this.append([
|
|
1431
|
+
` ${tone.red(`// ${errorMessage(err)}`)}`,
|
|
1432
|
+
` ${tone.mist("// the provider must expose an OpenAI-compatible GET /models")}`,
|
|
1433
|
+
]);
|
|
1434
|
+
return false;
|
|
1435
|
+
}
|
|
1436
|
+
this.setStatus(null);
|
|
1437
|
+
if (models.length === 0) {
|
|
1438
|
+
this.append([` ${tone.red("// no chat models found at this endpoint")}`]);
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
const envKey = providerEnvKey(id);
|
|
1442
|
+
registerCustomProvider({
|
|
1443
|
+
id,
|
|
1444
|
+
label: id,
|
|
1445
|
+
envKey,
|
|
1446
|
+
kind: "openai",
|
|
1447
|
+
baseUrl,
|
|
1448
|
+
defaultModel: models[0]?.id ?? "",
|
|
1449
|
+
models,
|
|
1450
|
+
custom: true,
|
|
1451
|
+
});
|
|
1452
|
+
process.env[envKey] = apiKey;
|
|
1453
|
+
this.config.keys = { ...(this.config.keys ?? {}), [envKey]: apiKey };
|
|
1454
|
+
this.config.customProviders = {
|
|
1455
|
+
...(this.config.customProviders ?? {}),
|
|
1456
|
+
[id]: { label: id, baseUrl, envKey, models },
|
|
1457
|
+
};
|
|
1458
|
+
await saveConfig({ ...this.config }).catch(() => undefined);
|
|
1459
|
+
this.append([
|
|
1460
|
+
` ${tone.accent(glyphs.diamond)} ${tone.mist(`// PROVIDER ADDED → ${id} · ${models.length} model${models.length === 1 ? "" : "s"}`)}`,
|
|
1461
|
+
` ${tone.silver(baseUrl)}`,
|
|
1462
|
+
` ${tone.mist(clipAnsi(models.slice(0, 6).map((model) => model.id).join(" · "), Math.max(20, this.contentWidth() - 6)))}`,
|
|
1463
|
+
]);
|
|
1289
1464
|
return true;
|
|
1290
1465
|
}
|
|
1291
1466
|
effortEntries(efforts, current) {
|
|
@@ -1622,6 +1797,7 @@ class TuiApp {
|
|
|
1622
1797
|
this.session = new Session(this.system);
|
|
1623
1798
|
this.conversationId = makeSessionId();
|
|
1624
1799
|
this.lastTurn = null;
|
|
1800
|
+
this.pendingImages = new Map();
|
|
1625
1801
|
this.transcript = [];
|
|
1626
1802
|
this.userMarkers = [];
|
|
1627
1803
|
this.messageCursor = -1;
|
|
@@ -1643,6 +1819,9 @@ class TuiApp {
|
|
|
1643
1819
|
}
|
|
1644
1820
|
}
|
|
1645
1821
|
return false;
|
|
1822
|
+
case "provider":
|
|
1823
|
+
await this.providerCommand(arg);
|
|
1824
|
+
return false;
|
|
1646
1825
|
case "effort":
|
|
1647
1826
|
await this.effortCommand(arg);
|
|
1648
1827
|
return false;
|
|
@@ -2328,7 +2507,7 @@ class TuiApp {
|
|
|
2328
2507
|
const keys = [
|
|
2329
2508
|
["enter", "send"],
|
|
2330
2509
|
["ctrl+enter", "newline (shift+enter, ctrl+space, ctrl+j, \\ + enter too)"],
|
|
2331
|
-
["ctrl+v", "paste text or an image"],
|
|
2510
|
+
["ctrl+v / alt+v", "paste text or an image — alt+v works even if the terminal eats ctrl+v"],
|
|
2332
2511
|
["mouse drag", "select text · ctrl+c copies"],
|
|
2333
2512
|
["permission card", "← → select · enter confirm · mouse click"],
|
|
2334
2513
|
["sessions picker", "ctrl+r rename · ctrl+p pin · ctrl+d delete"],
|
|
@@ -2437,6 +2616,80 @@ function shortenHome(dir) {
|
|
|
2437
2616
|
const home = homedir();
|
|
2438
2617
|
return dir.startsWith(home) ? `~${dir.slice(home.length)}` : dir;
|
|
2439
2618
|
}
|
|
2619
|
+
const IMAGE_EXTENSIONS = {
|
|
2620
|
+
".png": "image/png",
|
|
2621
|
+
".jpg": "image/jpeg",
|
|
2622
|
+
".jpeg": "image/jpeg",
|
|
2623
|
+
".webp": "image/webp",
|
|
2624
|
+
".gif": "image/gif",
|
|
2625
|
+
".bmp": "image/bmp",
|
|
2626
|
+
};
|
|
2627
|
+
const IMAGE_MARKER_RE = /\[Image (\d+)\]/g;
|
|
2628
|
+
export function nextImageIndex(text) {
|
|
2629
|
+
const used = new Set();
|
|
2630
|
+
for (const match of text.matchAll(IMAGE_MARKER_RE)) {
|
|
2631
|
+
const index = Number(match[1]);
|
|
2632
|
+
if (Number.isInteger(index) && index > 0)
|
|
2633
|
+
used.add(index);
|
|
2634
|
+
}
|
|
2635
|
+
let index = 1;
|
|
2636
|
+
while (used.has(index))
|
|
2637
|
+
index += 1;
|
|
2638
|
+
return index;
|
|
2639
|
+
}
|
|
2640
|
+
export function extractInputImages(text, images) {
|
|
2641
|
+
const used = [];
|
|
2642
|
+
const cleaned = text
|
|
2643
|
+
.replace(IMAGE_MARKER_RE, (match, raw) => {
|
|
2644
|
+
const image = images.get(Number(raw));
|
|
2645
|
+
if (!image)
|
|
2646
|
+
return match;
|
|
2647
|
+
used.push(image);
|
|
2648
|
+
return "";
|
|
2649
|
+
})
|
|
2650
|
+
.replace(/[ \t]{2,}/g, " ")
|
|
2651
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
2652
|
+
.trim();
|
|
2653
|
+
return { text: cleaned, images: used };
|
|
2654
|
+
}
|
|
2655
|
+
function imageTokenBefore(before) {
|
|
2656
|
+
const match = /(?:\[Image \d+\][ \t]*)+$/.exec(before);
|
|
2657
|
+
return match ? match[0].length : 0;
|
|
2658
|
+
}
|
|
2659
|
+
function imageTokenAfter(after) {
|
|
2660
|
+
const match = /^(?:\[Image \d+\][ \t]*)+/.exec(after);
|
|
2661
|
+
return match ? match[0].length : 0;
|
|
2662
|
+
}
|
|
2663
|
+
function styleInputLine(text) {
|
|
2664
|
+
const parts = text.split(/(\[Image \d+\])/);
|
|
2665
|
+
if (parts.length === 1)
|
|
2666
|
+
return tone.bone(text);
|
|
2667
|
+
return parts
|
|
2668
|
+
.map((part) => /^\[Image \d+\]$/.test(part) ? tone.onBone(part) : tone.bone(part))
|
|
2669
|
+
.join("");
|
|
2670
|
+
}
|
|
2671
|
+
async function imageFromPath(raw) {
|
|
2672
|
+
const lines = raw
|
|
2673
|
+
.split(/\r?\n/)
|
|
2674
|
+
.map((line) => line.trim().replace(/^["']|["']$/g, "").trim())
|
|
2675
|
+
.filter(Boolean);
|
|
2676
|
+
if (lines.length !== 1)
|
|
2677
|
+
return null;
|
|
2678
|
+
const file = lines[0];
|
|
2679
|
+
const mediaType = IMAGE_EXTENSIONS[path.extname(file).toLowerCase()];
|
|
2680
|
+
if (!mediaType)
|
|
2681
|
+
return null;
|
|
2682
|
+
try {
|
|
2683
|
+
const info = await stat(file);
|
|
2684
|
+
if (!info.isFile() || info.size === 0 || info.size > 12 * 1024 * 1024)
|
|
2685
|
+
return null;
|
|
2686
|
+
const data = await readFile(file);
|
|
2687
|
+
return { type: "image", mediaType, data: data.toString("base64") };
|
|
2688
|
+
}
|
|
2689
|
+
catch {
|
|
2690
|
+
return null;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2440
2693
|
function errorMessage(err) {
|
|
2441
2694
|
return err instanceof Error ? err.message : String(err);
|
|
2442
2695
|
}
|