@hsupu/copilot-api 0.7.2 → 0.7.4

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/main.js CHANGED
@@ -12,40 +12,12 @@ import { getProxyForUrl } from "proxy-from-env";
12
12
  import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
13
13
  import { execSync } from "node:child_process";
14
14
  import process$1 from "node:process";
15
- import { Box, Text, render, useInput, useStdout } from "ink";
16
- import React, { useEffect, useState } from "react";
17
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
+ import pc from "picocolors";
18
16
  import { Hono } from "hono";
19
17
  import { cors } from "hono/cors";
20
18
  import { streamSSE } from "hono/streaming";
21
19
  import { events } from "fetch-event-stream";
22
20
 
23
- //#region rolldown:runtime
24
- var __create = Object.create;
25
- var __defProp = Object.defineProperty;
26
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
27
- var __getOwnPropNames = Object.getOwnPropertyNames;
28
- var __getProtoOf = Object.getPrototypeOf;
29
- var __hasOwnProp = Object.prototype.hasOwnProperty;
30
- var __commonJS = (cb, mod) => function() {
31
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
32
- };
33
- var __copyProps = (to, from, except, desc) => {
34
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
35
- key = keys[i];
36
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
37
- get: ((k) => from[k]).bind(null, key),
38
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
39
- });
40
- }
41
- return to;
42
- };
43
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
44
- value: mod,
45
- enumerable: true
46
- }) : target, mod));
47
-
48
- //#endregion
49
21
  //#region src/lib/paths.ts
50
22
  const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
51
23
  const GITHUB_TOKEN_PATH = path.join(APP_DIR, "github_token");
@@ -154,9 +126,24 @@ function formatTokenLimitError(current, limit) {
154
126
  }
155
127
  };
156
128
  }
129
+ /** Format Anthropic-compatible error for request too large (413) */
130
+ function formatRequestTooLargeError() {
131
+ return {
132
+ type: "error",
133
+ error: {
134
+ type: "invalid_request_error",
135
+ message: "Request body too large. The HTTP request exceeds the server's size limit. Try reducing the conversation history or removing large content like images."
136
+ }
137
+ };
138
+ }
157
139
  async function forwardError(c, error) {
158
140
  consola.error("Error occurred:", error);
159
141
  if (error instanceof HTTPError) {
142
+ if (error.status === 413) {
143
+ const formattedError = formatRequestTooLargeError();
144
+ consola.debug("Returning formatted 413 error:", formattedError);
145
+ return c.json(formattedError, 413);
146
+ }
160
147
  let errorJson;
161
148
  try {
162
149
  errorJson = JSON.parse(error.responseText);
@@ -831,7 +818,7 @@ function initProxyFromEnv() {
831
818
  //#endregion
832
819
  //#region src/lib/shell.ts
833
820
  function getShell() {
834
- const { platform, ppid, env: env$1 } = process$1;
821
+ const { platform, ppid, env } = process$1;
835
822
  if (platform === "win32") {
836
823
  try {
837
824
  const command = `wmic process get ParentProcessId,Name | findstr "${ppid}"`;
@@ -841,7 +828,7 @@ function getShell() {
841
828
  }
842
829
  return "cmd";
843
830
  } else {
844
- const shellPath = env$1.SHELL;
831
+ const shellPath = env.SHELL;
845
832
  if (shellPath) {
846
833
  if (shellPath.endsWith("zsh")) return "zsh";
847
834
  if (shellPath.endsWith("fish")) return "fish";
@@ -881,91 +868,27 @@ function generateEnvScript(envVars, commandToRun = "") {
881
868
  return commandBlock || commandToRun;
882
869
  }
883
870
 
884
- //#endregion
885
- //#region node_modules/picocolors/picocolors.js
886
- var require_picocolors = /* @__PURE__ */ __commonJS({ "node_modules/picocolors/picocolors.js": ((exports, module) => {
887
- let p = process || {}, argv = p.argv || [], env = p.env || {};
888
- let isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
889
- let formatter = (open, close, replace = open) => (input) => {
890
- let string = "" + input, index = string.indexOf(close, open.length);
891
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
892
- };
893
- let replaceClose = (string, close, replace, index) => {
894
- let result = "", cursor = 0;
895
- do {
896
- result += string.substring(cursor, index) + replace;
897
- cursor = index + close.length;
898
- index = string.indexOf(close, cursor);
899
- } while (~index);
900
- return result + string.substring(cursor);
901
- };
902
- let createColors = (enabled = isColorSupported) => {
903
- let f = enabled ? formatter : () => String;
904
- return {
905
- isColorSupported: enabled,
906
- reset: f("\x1B[0m", "\x1B[0m"),
907
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
908
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
909
- italic: f("\x1B[3m", "\x1B[23m"),
910
- underline: f("\x1B[4m", "\x1B[24m"),
911
- inverse: f("\x1B[7m", "\x1B[27m"),
912
- hidden: f("\x1B[8m", "\x1B[28m"),
913
- strikethrough: f("\x1B[9m", "\x1B[29m"),
914
- black: f("\x1B[30m", "\x1B[39m"),
915
- red: f("\x1B[31m", "\x1B[39m"),
916
- green: f("\x1B[32m", "\x1B[39m"),
917
- yellow: f("\x1B[33m", "\x1B[39m"),
918
- blue: f("\x1B[34m", "\x1B[39m"),
919
- magenta: f("\x1B[35m", "\x1B[39m"),
920
- cyan: f("\x1B[36m", "\x1B[39m"),
921
- white: f("\x1B[37m", "\x1B[39m"),
922
- gray: f("\x1B[90m", "\x1B[39m"),
923
- bgBlack: f("\x1B[40m", "\x1B[49m"),
924
- bgRed: f("\x1B[41m", "\x1B[49m"),
925
- bgGreen: f("\x1B[42m", "\x1B[49m"),
926
- bgYellow: f("\x1B[43m", "\x1B[49m"),
927
- bgBlue: f("\x1B[44m", "\x1B[49m"),
928
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
929
- bgCyan: f("\x1B[46m", "\x1B[49m"),
930
- bgWhite: f("\x1B[47m", "\x1B[49m"),
931
- blackBright: f("\x1B[90m", "\x1B[39m"),
932
- redBright: f("\x1B[91m", "\x1B[39m"),
933
- greenBright: f("\x1B[92m", "\x1B[39m"),
934
- yellowBright: f("\x1B[93m", "\x1B[39m"),
935
- blueBright: f("\x1B[94m", "\x1B[39m"),
936
- magentaBright: f("\x1B[95m", "\x1B[39m"),
937
- cyanBright: f("\x1B[96m", "\x1B[39m"),
938
- whiteBright: f("\x1B[97m", "\x1B[39m"),
939
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
940
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
941
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
942
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
943
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
944
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
945
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
946
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
947
- };
948
- };
949
- module.exports = createColors();
950
- module.exports.createColors = createColors;
951
- }) });
952
-
953
871
  //#endregion
954
872
  //#region src/lib/tui/console-renderer.ts
955
- var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
956
873
  const CLEAR_LINE = "\x1B[2K\r";
957
- function formatDuration$1(ms) {
874
+ function formatTime(date = /* @__PURE__ */ new Date()) {
875
+ const h = String(date.getHours()).padStart(2, "0");
876
+ const m = String(date.getMinutes()).padStart(2, "0");
877
+ const s = String(date.getSeconds()).padStart(2, "0");
878
+ return `${h}:${m}:${s}`;
879
+ }
880
+ function formatDuration(ms) {
958
881
  if (ms < 1e3) return `${ms}ms`;
959
882
  return `${(ms / 1e3).toFixed(1)}s`;
960
883
  }
961
- function formatNumber$1(n) {
884
+ function formatNumber(n) {
962
885
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
963
886
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
964
887
  return String(n);
965
888
  }
966
- function formatTokens$1(input, output) {
889
+ function formatTokens(input, output) {
967
890
  if (input === void 0 || output === void 0) return "-";
968
- return `${formatNumber$1(input)}/${formatNumber$1(output)}`;
891
+ return `${formatNumber(input)}/${formatNumber(output)}`;
969
892
  }
970
893
  /**
971
894
  * Console renderer that shows request lifecycle with apt-get style footer
@@ -996,7 +919,7 @@ var ConsoleRenderer = class {
996
919
  const activeCount = this.activeRequests.size;
997
920
  if (activeCount === 0) return "";
998
921
  const plural = activeCount === 1 ? "" : "s";
999
- return import_picocolors.default.dim(`[....] ${activeCount} request${plural} in progress...`);
922
+ return pc.dim(`[....] ${activeCount} request${plural} in progress...`);
1000
923
  }
1001
924
  /**
1002
925
  * Render footer in-place on current line (no newline)
@@ -1030,16 +953,17 @@ var ConsoleRenderer = class {
1030
953
  */
1031
954
  printLog(message, isGray = false) {
1032
955
  this.clearFooterForLog();
1033
- if (isGray) consola.log(import_picocolors.default.dim(message));
956
+ if (isGray) consola.log(pc.dim(message));
1034
957
  else consola.log(message);
1035
958
  this.renderFooter();
1036
959
  }
1037
960
  onRequestStart(request) {
1038
961
  this.activeRequests.set(request.id, request);
1039
962
  if (this.showActive) {
963
+ const time = formatTime();
1040
964
  const modelInfo = request.model ? ` ${request.model}` : "";
1041
965
  const queueInfo = request.queuePosition !== void 0 && request.queuePosition > 0 ? ` [q#${request.queuePosition}]` : "";
1042
- const message = `[....] ${request.method} ${request.path}${modelInfo}${queueInfo}`;
966
+ const message = `${time} [....] ${request.method} ${request.path}${modelInfo}${queueInfo}`;
1043
967
  this.printLog(message, request.isHistoryAccess);
1044
968
  }
1045
969
  }
@@ -1048,21 +972,23 @@ var ConsoleRenderer = class {
1048
972
  if (!request) return;
1049
973
  Object.assign(request, update);
1050
974
  if (this.showActive && update.status === "streaming") {
975
+ const time = formatTime();
1051
976
  const modelInfo = request.model ? ` ${request.model}` : "";
1052
- const message = `[<-->] ${request.method} ${request.path}${modelInfo} streaming...`;
977
+ const message = `${time} [<-->] ${request.method} ${request.path}${modelInfo} streaming...`;
1053
978
  this.printLog(message, request.isHistoryAccess);
1054
979
  }
1055
980
  }
1056
981
  onRequestComplete(request) {
1057
982
  this.activeRequests.delete(request.id);
983
+ const time = formatTime();
1058
984
  const status = request.statusCode ?? 0;
1059
- const duration = formatDuration$1(request.durationMs ?? 0);
1060
- const tokens = request.model ? formatTokens$1(request.inputTokens, request.outputTokens) : "";
985
+ const duration = formatDuration(request.durationMs ?? 0);
986
+ const tokens = request.model ? formatTokens(request.inputTokens, request.outputTokens) : "";
1061
987
  const modelInfo = request.model ? ` ${request.model}` : "";
1062
988
  const isError = request.status === "error" || status >= 400;
1063
989
  const prefix = isError ? "[FAIL]" : "[ OK ]";
1064
990
  const tokensPart = tokens ? ` ${tokens}` : "";
1065
- let content = `${prefix} ${request.method} ${request.path} ${status} ${duration}${tokensPart}${modelInfo}`;
991
+ let content = `${time} ${prefix} ${request.method} ${request.path} ${status} ${duration}${tokensPart}${modelInfo}`;
1066
992
  if (isError) {
1067
993
  const errorInfo = request.error ? `: ${request.error}` : "";
1068
994
  content += errorInfo;
@@ -1078,337 +1004,6 @@ var ConsoleRenderer = class {
1078
1004
  }
1079
1005
  };
1080
1006
 
1081
- //#endregion
1082
- //#region src/lib/tui/fullscreen-renderer.tsx
1083
- const tuiState = {
1084
- activeRequests: /* @__PURE__ */ new Map(),
1085
- completedRequests: [],
1086
- errorRequests: []
1087
- };
1088
- const listeners = [];
1089
- function notifyListeners() {
1090
- for (const listener of listeners) listener();
1091
- }
1092
- function formatDuration(ms) {
1093
- if (ms < 1e3) return `${ms}ms`;
1094
- return `${(ms / 1e3).toFixed(1)}s`;
1095
- }
1096
- function formatNumber(n) {
1097
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
1098
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
1099
- return String(n);
1100
- }
1101
- function formatTokens(input, output) {
1102
- if (input === void 0 || output === void 0) return "-";
1103
- return `${formatNumber(input)}/${formatNumber(output)}`;
1104
- }
1105
- function getElapsedTime(startTime) {
1106
- return formatDuration(Date.now() - startTime);
1107
- }
1108
- function TabHeader({ currentTab, counts }) {
1109
- const tabs = [
1110
- {
1111
- key: "active",
1112
- label: "Active",
1113
- count: counts.active
1114
- },
1115
- {
1116
- key: "completed",
1117
- label: "Completed",
1118
- count: counts.completed
1119
- },
1120
- {
1121
- key: "errors",
1122
- label: "Errors",
1123
- count: counts.errors
1124
- }
1125
- ];
1126
- return /* @__PURE__ */ jsxs(Box, {
1127
- borderStyle: "single",
1128
- paddingX: 1,
1129
- children: [tabs.map((tab, idx) => /* @__PURE__ */ jsxs(React.Fragment, { children: [idx > 0 && /* @__PURE__ */ jsx(Text, { children: " │ " }), /* @__PURE__ */ jsxs(Text, {
1130
- bold: currentTab === tab.key,
1131
- color: currentTab === tab.key ? "cyan" : void 0,
1132
- inverse: currentTab === tab.key,
1133
- children: [
1134
- " ",
1135
- "[",
1136
- idx + 1,
1137
- "] ",
1138
- tab.label,
1139
- " (",
1140
- tab.count,
1141
- ")",
1142
- " "
1143
- ]
1144
- })] }, tab.key)), /* @__PURE__ */ jsx(Text, {
1145
- dimColor: true,
1146
- children: " │ Press 1/2/3 to switch tabs, q to quit"
1147
- })]
1148
- });
1149
- }
1150
- function getStatusColor(status) {
1151
- if (status === "streaming") return "yellow";
1152
- if (status === "queued") return "gray";
1153
- return "blue";
1154
- }
1155
- function getStatusIcon(status) {
1156
- if (status === "streaming") return "⟳";
1157
- if (status === "queued") return "◷";
1158
- return "●";
1159
- }
1160
- function ActiveRequestRow({ request }) {
1161
- const [, setTick] = useState(0);
1162
- useEffect(() => {
1163
- const interval = setInterval(() => setTick((t) => t + 1), 1e3);
1164
- return () => clearInterval(interval);
1165
- }, []);
1166
- const statusColor = getStatusColor(request.status);
1167
- const statusIcon = getStatusIcon(request.status);
1168
- return /* @__PURE__ */ jsxs(Box, { children: [
1169
- /* @__PURE__ */ jsxs(Text, {
1170
- color: statusColor,
1171
- children: [statusIcon, " "]
1172
- }),
1173
- /* @__PURE__ */ jsx(Text, {
1174
- bold: true,
1175
- children: request.method
1176
- }),
1177
- /* @__PURE__ */ jsxs(Text, { children: [
1178
- " ",
1179
- request.path,
1180
- " "
1181
- ] }),
1182
- /* @__PURE__ */ jsxs(Text, {
1183
- dimColor: true,
1184
- children: [getElapsedTime(request.startTime), " "]
1185
- }),
1186
- request.queuePosition !== void 0 && request.queuePosition > 0 && /* @__PURE__ */ jsxs(Text, {
1187
- color: "gray",
1188
- children: [
1189
- "[queue #",
1190
- request.queuePosition,
1191
- "] "
1192
- ]
1193
- }),
1194
- /* @__PURE__ */ jsx(Text, {
1195
- color: "magenta",
1196
- children: request.model
1197
- })
1198
- ] });
1199
- }
1200
- function CompletedRequestRow({ request }) {
1201
- const isError = request.status === "error" || (request.statusCode ?? 0) >= 400;
1202
- return /* @__PURE__ */ jsxs(Box, { children: [
1203
- /* @__PURE__ */ jsxs(Text, {
1204
- color: isError ? "red" : "green",
1205
- children: [isError ? "✗" : "✓", " "]
1206
- }),
1207
- /* @__PURE__ */ jsx(Text, {
1208
- bold: true,
1209
- children: request.method
1210
- }),
1211
- /* @__PURE__ */ jsxs(Text, { children: [
1212
- " ",
1213
- request.path,
1214
- " "
1215
- ] }),
1216
- /* @__PURE__ */ jsxs(Text, {
1217
- color: isError ? "red" : "green",
1218
- children: [request.statusCode ?? "-", " "]
1219
- }),
1220
- /* @__PURE__ */ jsxs(Text, {
1221
- dimColor: true,
1222
- children: [formatDuration(request.durationMs ?? 0), " "]
1223
- }),
1224
- /* @__PURE__ */ jsxs(Text, { children: [formatTokens(request.inputTokens, request.outputTokens), " "] }),
1225
- /* @__PURE__ */ jsx(Text, {
1226
- color: "magenta",
1227
- children: request.model
1228
- })
1229
- ] });
1230
- }
1231
- function ErrorRequestRow({ request }) {
1232
- return /* @__PURE__ */ jsxs(Box, {
1233
- flexDirection: "column",
1234
- children: [/* @__PURE__ */ jsxs(Box, { children: [
1235
- /* @__PURE__ */ jsx(Text, {
1236
- color: "red",
1237
- children: "✗ "
1238
- }),
1239
- /* @__PURE__ */ jsx(Text, {
1240
- bold: true,
1241
- children: request.method
1242
- }),
1243
- /* @__PURE__ */ jsxs(Text, { children: [
1244
- " ",
1245
- request.path,
1246
- " "
1247
- ] }),
1248
- /* @__PURE__ */ jsxs(Text, {
1249
- color: "red",
1250
- children: [request.statusCode ?? "-", " "]
1251
- }),
1252
- /* @__PURE__ */ jsxs(Text, {
1253
- dimColor: true,
1254
- children: [formatDuration(request.durationMs ?? 0), " "]
1255
- }),
1256
- /* @__PURE__ */ jsx(Text, {
1257
- color: "magenta",
1258
- children: request.model
1259
- })
1260
- ] }), request.error && /* @__PURE__ */ jsx(Box, {
1261
- marginLeft: 2,
1262
- children: /* @__PURE__ */ jsxs(Text, {
1263
- color: "red",
1264
- dimColor: true,
1265
- children: ["└─ ", request.error]
1266
- })
1267
- })]
1268
- });
1269
- }
1270
- function ContentPanel({ currentTab, activeList, completedList, errorList, contentHeight }) {
1271
- if (currentTab === "active") {
1272
- if (activeList.length === 0) return /* @__PURE__ */ jsx(Text, {
1273
- dimColor: true,
1274
- children: "No active requests"
1275
- });
1276
- return /* @__PURE__ */ jsx(Fragment, { children: activeList.slice(0, contentHeight).map((req) => /* @__PURE__ */ jsx(ActiveRequestRow, { request: req }, req.id)) });
1277
- }
1278
- if (currentTab === "completed") {
1279
- if (completedList.length === 0) return /* @__PURE__ */ jsx(Text, {
1280
- dimColor: true,
1281
- children: "No completed requests"
1282
- });
1283
- return /* @__PURE__ */ jsx(Fragment, { children: completedList.slice(-contentHeight).reverse().map((req) => /* @__PURE__ */ jsx(CompletedRequestRow, { request: req }, req.id)) });
1284
- }
1285
- if (errorList.length === 0) return /* @__PURE__ */ jsx(Text, {
1286
- dimColor: true,
1287
- children: "No errors"
1288
- });
1289
- return /* @__PURE__ */ jsx(Fragment, { children: errorList.slice(-contentHeight).reverse().map((req) => /* @__PURE__ */ jsx(ErrorRequestRow, { request: req }, req.id)) });
1290
- }
1291
- function TuiApp() {
1292
- const [currentTab, setCurrentTab] = useState("active");
1293
- const [, forceUpdate] = useState(0);
1294
- const { stdout } = useStdout();
1295
- useEffect(() => {
1296
- const listener = () => forceUpdate((n) => n + 1);
1297
- listeners.push(listener);
1298
- return () => {
1299
- const idx = listeners.indexOf(listener);
1300
- if (idx !== -1) listeners.splice(idx, 1);
1301
- };
1302
- }, []);
1303
- useInput((input, key) => {
1304
- switch (input) {
1305
- case "1":
1306
- setCurrentTab("active");
1307
- break;
1308
- case "2":
1309
- setCurrentTab("completed");
1310
- break;
1311
- case "3":
1312
- setCurrentTab("errors");
1313
- break;
1314
- default: if (input === "q" || key.ctrl && input === "c") process.exit(0);
1315
- }
1316
- });
1317
- const activeList = Array.from(tuiState.activeRequests.values());
1318
- const completedList = tuiState.completedRequests;
1319
- const errorList = tuiState.errorRequests;
1320
- const counts = {
1321
- active: activeList.length,
1322
- completed: completedList.length,
1323
- errors: errorList.length
1324
- };
1325
- const terminalHeight = stdout.rows || 24;
1326
- const contentHeight = terminalHeight - 3 - 1 - 2;
1327
- return /* @__PURE__ */ jsxs(Box, {
1328
- flexDirection: "column",
1329
- height: terminalHeight,
1330
- children: [
1331
- /* @__PURE__ */ jsx(TabHeader, {
1332
- currentTab,
1333
- counts
1334
- }),
1335
- /* @__PURE__ */ jsx(Box, {
1336
- flexDirection: "column",
1337
- height: contentHeight,
1338
- borderStyle: "single",
1339
- paddingX: 1,
1340
- overflow: "hidden",
1341
- children: /* @__PURE__ */ jsx(ContentPanel, {
1342
- currentTab,
1343
- activeList,
1344
- completedList,
1345
- errorList,
1346
- contentHeight
1347
- })
1348
- }),
1349
- /* @__PURE__ */ jsx(Box, {
1350
- paddingX: 1,
1351
- children: /* @__PURE__ */ jsxs(Text, {
1352
- dimColor: true,
1353
- children: [
1354
- "copilot-api │ Active: ",
1355
- counts.active,
1356
- " │ Completed: ",
1357
- counts.completed,
1358
- " ",
1359
- "│ Errors: ",
1360
- counts.errors
1361
- ]
1362
- })
1363
- })
1364
- ]
1365
- });
1366
- }
1367
- /**
1368
- * Fullscreen TUI renderer using Ink
1369
- * Provides interactive terminal interface with tabs
1370
- */
1371
- var FullscreenRenderer = class {
1372
- inkInstance = null;
1373
- maxHistory = 100;
1374
- constructor(options) {
1375
- if (options?.maxHistory !== void 0) this.maxHistory = options.maxHistory;
1376
- }
1377
- start() {
1378
- if (this.inkInstance) return;
1379
- this.inkInstance = render(/* @__PURE__ */ jsx(TuiApp, {}), {});
1380
- }
1381
- onRequestStart(request) {
1382
- tuiState.activeRequests.set(request.id, { ...request });
1383
- notifyListeners();
1384
- }
1385
- onRequestUpdate(id, update) {
1386
- const request = tuiState.activeRequests.get(id);
1387
- if (!request) return;
1388
- Object.assign(request, update);
1389
- notifyListeners();
1390
- }
1391
- onRequestComplete(request) {
1392
- tuiState.activeRequests.delete(request.id);
1393
- if (request.status === "error" || (request.statusCode ?? 0) >= 400) {
1394
- tuiState.errorRequests.push({ ...request });
1395
- while (tuiState.errorRequests.length > this.maxHistory) tuiState.errorRequests.shift();
1396
- }
1397
- tuiState.completedRequests.push({ ...request });
1398
- while (tuiState.completedRequests.length > this.maxHistory) tuiState.completedRequests.shift();
1399
- notifyListeners();
1400
- }
1401
- destroy() {
1402
- if (this.inkInstance) {
1403
- this.inkInstance.unmount();
1404
- this.inkInstance = null;
1405
- }
1406
- tuiState.activeRequests.clear();
1407
- tuiState.completedRequests = [];
1408
- tuiState.errorRequests = [];
1409
- }
1410
- };
1411
-
1412
1007
  //#endregion
1413
1008
  //#region src/lib/tui/tracker.ts
1414
1009
  function generateId() {
@@ -1572,16 +1167,9 @@ function tuiLogger() {
1572
1167
  //#region src/lib/tui/index.ts
1573
1168
  /**
1574
1169
  * Initialize the TUI system
1575
- * @param options.mode - "console" for simple log output (default), "fullscreen" for interactive TUI
1576
1170
  */
1577
1171
  function initTui(options) {
1578
- const enabled = options?.enabled ?? process.stdout.isTTY;
1579
- const mode = options?.mode ?? "console";
1580
- if (enabled) if (mode === "fullscreen") {
1581
- const renderer = new FullscreenRenderer({ maxHistory: options?.historySize ?? 100 });
1582
- requestTracker.setRenderer(renderer);
1583
- renderer.start();
1584
- } else {
1172
+ if (options?.enabled ?? process.stdout.isTTY) {
1585
1173
  const renderer = new ConsoleRenderer();
1586
1174
  requestTracker.setRenderer(renderer);
1587
1175
  }
@@ -1675,7 +1263,7 @@ const getEncodeChatFunction = async (encoding) => {
1675
1263
  * Get tokenizer type from model information
1676
1264
  */
1677
1265
  const getTokenizerFromModel = (model) => {
1678
- return model.capabilities.tokenizer || "o200k_base";
1266
+ return model.capabilities?.tokenizer || "o200k_base";
1679
1267
  };
1680
1268
  /**
1681
1269
  * Get model-specific constants for token calculation.
@@ -1813,7 +1401,7 @@ const DEFAULT_CONFIG = {
1813
1401
  */
1814
1402
  async function checkNeedsCompaction(payload, model, safetyMarginPercent = 10) {
1815
1403
  const currentTokens = (await getTokenCount(payload, model)).input;
1816
- const rawLimit = model.capabilities.limits.max_prompt_tokens ?? 128e3;
1404
+ const rawLimit = model.capabilities?.limits?.max_prompt_tokens ?? 128e3;
1817
1405
  const limit = Math.floor(rawLimit * (1 - safetyMarginPercent / 100));
1818
1406
  return {
1819
1407
  needed: currentTokens > limit,
@@ -1892,7 +1480,7 @@ async function autoCompact(payload, model, config = {}) {
1892
1480
  ...config
1893
1481
  };
1894
1482
  const originalTokens = (await getTokenCount(payload, model)).input;
1895
- const rawLimit = model.capabilities.limits.max_prompt_tokens ?? 128e3;
1483
+ const rawLimit = model.capabilities?.limits?.max_prompt_tokens ?? 128e3;
1896
1484
  const limit = Math.floor(rawLimit * (1 - cfg.safetyMarginPercent / 100));
1897
1485
  if (originalTokens <= limit) return {
1898
1486
  payload,
@@ -2051,6 +1639,9 @@ const createChatCompletions = async (payload) => {
2051
1639
 
2052
1640
  //#endregion
2053
1641
  //#region src/routes/chat-completions/handler.ts
1642
+ function getModelMaxOutputTokens(model) {
1643
+ return model?.capabilities?.limits?.max_output_tokens;
1644
+ }
2054
1645
  async function handleCompletion$1(c) {
2055
1646
  const originalPayload = await c.req.json();
2056
1647
  consola.debug("Request payload:", JSON.stringify(originalPayload).slice(-400));
@@ -2078,7 +1669,7 @@ async function handleCompletion$1(c) {
2078
1669
  if (compactResult) ctx.compactResult = compactResult;
2079
1670
  const payload = isNullish(finalPayload.max_tokens) ? {
2080
1671
  ...finalPayload,
2081
- max_tokens: selectedModel?.capabilities.limits.max_output_tokens
1672
+ max_tokens: getModelMaxOutputTokens(selectedModel)
2082
1673
  } : finalPayload;
2083
1674
  if (isNullish(originalPayload.max_tokens)) consola.debug("Set max_tokens to:", JSON.stringify(payload.max_tokens));
2084
1675
  if (state.manualApprove) await awaitApproval();
@@ -4460,20 +4051,20 @@ modelRoutes.get("/", async (c) => {
4460
4051
  created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
4461
4052
  owned_by: model.vendor,
4462
4053
  display_name: model.name,
4463
- capabilities: {
4054
+ capabilities: model.capabilities ? {
4464
4055
  family: model.capabilities.family,
4465
4056
  type: model.capabilities.type,
4466
4057
  tokenizer: model.capabilities.tokenizer,
4467
4058
  limits: {
4468
- max_context_window_tokens: model.capabilities.limits.max_context_window_tokens,
4469
- max_output_tokens: model.capabilities.limits.max_output_tokens,
4470
- max_prompt_tokens: model.capabilities.limits.max_prompt_tokens
4059
+ max_context_window_tokens: model.capabilities.limits?.max_context_window_tokens,
4060
+ max_output_tokens: model.capabilities.limits?.max_output_tokens,
4061
+ max_prompt_tokens: model.capabilities.limits?.max_prompt_tokens
4471
4062
  },
4472
4063
  supports: {
4473
- tool_calls: model.capabilities.supports.tool_calls,
4474
- parallel_tool_calls: model.capabilities.supports.parallel_tool_calls
4064
+ tool_calls: model.capabilities.supports?.tool_calls,
4065
+ parallel_tool_calls: model.capabilities.supports?.parallel_tool_calls
4475
4066
  }
4476
- }
4067
+ } : void 0
4477
4068
  }));
4478
4069
  return c.json({
4479
4070
  object: "list",
@@ -4539,6 +4130,14 @@ server.route("/history", historyRoutes);
4539
4130
 
4540
4131
  //#endregion
4541
4132
  //#region src/start.ts
4133
+ function formatModelInfo(model) {
4134
+ const limits = model.capabilities?.limits;
4135
+ const contextK = limits?.max_prompt_tokens ? `${Math.round(limits.max_prompt_tokens / 1e3)}k` : "?";
4136
+ const outputK = limits?.max_output_tokens ? `${Math.round(limits.max_output_tokens / 1e3)}k` : "?";
4137
+ const features = [model.capabilities?.supports?.tool_calls && "tools", model.preview && "preview"].filter(Boolean).join(", ");
4138
+ const featureStr = features ? ` (${features})` : "";
4139
+ return ` - ${model.id.padEnd(28)} context: ${contextK.padStart(5)}, output: ${outputK.padStart(4)}${featureStr}`;
4140
+ }
4542
4141
  async function runServer(options) {
4543
4142
  if (options.proxyEnv) initProxyFromEnv();
4544
4143
  if (options.verbose) {
@@ -4558,10 +4157,7 @@ async function runServer(options) {
4558
4157
  const limitText = options.historyLimit === 0 ? "unlimited" : `max ${options.historyLimit}`;
4559
4158
  consola.info(`History recording enabled (${limitText} entries)`);
4560
4159
  }
4561
- initTui({
4562
- enabled: true,
4563
- mode: options.tui
4564
- });
4160
+ initTui({ enabled: true });
4565
4161
  await ensurePaths();
4566
4162
  await cacheVSCodeVersion();
4567
4163
  if (options.githubToken) {
@@ -4570,7 +4166,7 @@ async function runServer(options) {
4570
4166
  } else await setupGitHubToken();
4571
4167
  await setupCopilotToken();
4572
4168
  await cacheModels();
4573
- consola.info(`Available models: \n${state.models?.data.map((model) => `- ${model.id}`).join("\n")}`);
4169
+ consola.info(`Available models:\n${state.models?.data.map((m) => formatModelInfo(m)).join("\n")}`);
4574
4170
  const serverUrl = `http://${options.host ?? "localhost"}:${options.port}`;
4575
4171
  if (options.claudeCode) {
4576
4172
  invariant(state.models, "Models should be loaded by now");
@@ -4683,11 +4279,6 @@ const start = defineCommand({
4683
4279
  default: "1000",
4684
4280
  description: "Maximum number of history entries to keep in memory (0 = unlimited)"
4685
4281
  },
4686
- tui: {
4687
- type: "string",
4688
- default: "console",
4689
- description: "TUI mode: 'console' for simple log output, 'fullscreen' for interactive terminal UI with tabs"
4690
- },
4691
4282
  "auto-compact": {
4692
4283
  type: "boolean",
4693
4284
  default: false,
@@ -4711,7 +4302,6 @@ const start = defineCommand({
4711
4302
  proxyEnv: args["proxy-env"],
4712
4303
  history: args.history,
4713
4304
  historyLimit: Number.parseInt(args["history-limit"], 10),
4714
- tui: args.tui,
4715
4305
  autoCompact: args["auto-compact"]
4716
4306
  });
4717
4307
  }
@@ -4719,7 +4309,7 @@ const start = defineCommand({
4719
4309
 
4720
4310
  //#endregion
4721
4311
  //#region src/main.ts
4722
- consola.options.formatOptions.date = true;
4312
+ consola.options.formatOptions.date = false;
4723
4313
  const main = defineCommand({
4724
4314
  meta: {
4725
4315
  name: "copilot-api",