hermes-web-ui 0.3.6 → 0.3.7
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/bin/hermes-web-ui.mjs +15 -1
- package/dist/client/assets/{Add-CKf6ViXR.js → Add-Cc7cgBoB.js} +1 -1
- package/dist/client/assets/{Button-CrrCCorI.js → Button-EoeZgIFH.js} +1 -1
- package/dist/client/assets/{ChannelsView-D4I7hhZO.js → ChannelsView-Bfbq3w7n.js} +1 -1
- package/dist/client/assets/{ChatView-DxyBUK57.js → ChatView-CDdyTo72.js} +1 -1
- package/dist/client/assets/{Close-C9xwy-pW.js → Close-CKHcXisf.js} +1 -1
- package/dist/client/assets/{FormItem-BgJdrTW0.js → FormItem-CvZvjrtr.js} +1 -1
- package/dist/client/assets/{GatewaysView-Cib2JydO.js → GatewaysView-Dp4-TFPE.js} +1 -1
- package/dist/client/assets/{Input-ChENEW-Z.js → Input-Bk7XdoG-.js} +1 -1
- package/dist/client/assets/{InputNumber-Xd6HWSdp.js → InputNumber-Dn0EHi-K.js} +1 -1
- package/dist/client/assets/{JobsView-SnToCbDd.js → JobsView-D4JN73Zz.js} +2 -2
- package/dist/client/assets/{LoginView-BZdmMnsf.js → LoginView--hy5CI5O.js} +1 -1
- package/dist/client/assets/{LogsView-DblvOJIg.js → LogsView-Dz2ZeYad.js} +1 -1
- package/dist/client/assets/{MarkdownRenderer-DJLVk7ei.js → MarkdownRenderer-BbedVxvo.js} +1 -1
- package/dist/client/assets/{MemoryView-exXvRwCc.js → MemoryView-D2EHM35l.js} +1 -1
- package/dist/client/assets/{Modal-B2zvXTrk.js → Modal-C5-Iw50K.js} +1 -1
- package/dist/client/assets/ModelsView-CtrRf4vK.js +1 -0
- package/dist/client/assets/{ModelsView-jbgZP3YF.css → ModelsView-VM-oMq5M.css} +1 -1
- package/dist/client/assets/{Popconfirm-BoZc0kKk.js → Popconfirm-C-M2anVL.js} +1 -1
- package/dist/client/assets/{Popover-Cu52vG3D.js → Popover-mIRPCy7U.js} +1 -1
- package/dist/client/assets/{ProfilesView-D0FY7Jwe.js → ProfilesView-Dy9PivgB.js} +1 -1
- package/dist/client/assets/{Select-BHc7u-Yf.js → Select-uZBC8HC2.js} +2 -2
- package/dist/client/assets/{SettingRow-i-UXlco7.js → SettingRow-D9R65bDj.js} +1 -1
- package/dist/client/assets/{SettingsView-Dhr2wzAB.css → SettingsView-C3sd8K0e.css} +1 -1
- package/dist/client/assets/SettingsView-DWEEXqSY.js +352 -0
- package/dist/client/assets/{SkillsView-B5QBaAzi.js → SkillsView-CdZSRy9_.js} +1 -1
- package/dist/client/assets/{Spin-DsNCRPk9.js → Spin-ChbFBUOD.js} +1 -1
- package/dist/client/assets/{Suffix-3xK0KZGt.js → Suffix-DgzfIwzx.js} +1 -1
- package/dist/client/assets/{Switch-Bf63XXgA.js → Switch--HhY1uSh.js} +1 -1
- package/dist/client/assets/{Tag-Dmbj68Ki.js → Tag-B2zrHMmZ.js} +1 -1
- package/dist/client/assets/{TerminalView-DrJHZ0qI.js → TerminalView-BwfnH803.js} +1 -1
- package/dist/client/assets/{Tooltip-CRbZNhG0.js → Tooltip-9tdvSKGi.js} +1 -1
- package/dist/client/assets/{UsageView-DQ43JasX.js → UsageView-zL3a7F86.js} +1 -1
- package/dist/client/assets/{Warning-kBbRMAif.js → Warning-CXXqHzLa.js} +1 -1
- package/dist/client/assets/{_plugin-vue_export-helper-CnosYBkx.js → _plugin-vue_export-helper-Cnn0Z73x.js} +1 -1
- package/dist/client/assets/app-BMobzABI.js +1 -0
- package/dist/client/assets/app-Bqu9Uz-1.js +1 -0
- package/dist/client/assets/{browser-Djp4tkp3.js → browser-CQRjhbaB.js} +1 -1
- package/dist/client/assets/chat-BIdq6ZXF.js +6 -0
- package/dist/client/assets/composables-ClIU-Ad1.js +1 -0
- package/dist/client/assets/{fade-in.cssr-CIVyTG6A.js → fade-in.cssr-lwO9nLky.js} +1 -1
- package/dist/client/assets/index-Tg6M43Om.js +284 -0
- package/dist/client/assets/{jobs-CcVaCGMJ.js → jobs-Z2HS0j2d.js} +1 -1
- package/dist/client/assets/{light-CSp9-LhE.js → light-CjCy-Dkn.js} +1 -1
- package/dist/client/assets/{light-BJ96fCLC.js → light-DZ0Ns16h.js} +1 -1
- package/dist/client/assets/{light-BF6E9z0k.js → light-DgIst23O.js} +1 -1
- package/dist/client/assets/{light-KCEDTUGE.js → light-Dx6qj2pM.js} +1 -1
- package/dist/client/assets/{light-BPqyaxve.js → light-DzpNsLai.js} +1 -1
- package/dist/client/assets/{light-D9G2GshF.js → light-oE8MEiWL.js} +1 -1
- package/dist/client/assets/models-DLQiHB7r.js +1 -0
- package/dist/client/assets/{pinia-iHE5_ZXa.js → pinia-Dp_b1vdW.js} +1 -1
- package/dist/client/assets/{profiles-CJCR84uQ.js → profiles-CNTHYFZE.js} +1 -1
- package/dist/client/assets/{router-C-NNJUuf.js → router-Dj-Nmg7q.js} +2 -2
- package/dist/client/assets/{sessions-C4bnNvzS.js → sessions-C0kvgvBm.js} +1 -1
- package/dist/client/assets/{skills-B4slZfeZ.js → skills-G7EoEvdS.js} +1 -1
- package/dist/client/assets/{use-message-BIpqgDet.js → use-message-BgToAqhv.js} +1 -1
- package/dist/client/assets/{useTheme-B78N9tyz.js → useTheme-BUShiwRu.js} +1 -1
- package/dist/client/index.html +27 -27
- package/dist/server/routes/hermes/filesystem.js +231 -199
- package/dist/server/routes/hermes/logs.js +50 -11
- package/dist/server/routes/hermes/proxy-handler.js +16 -6
- package/dist/server/services/hermes/gateway-manager.d.ts +2 -0
- package/dist/server/services/hermes/gateway-manager.js +15 -0
- package/dist/server/services/hermes/hermes-profile.d.ts +6 -0
- package/dist/server/services/hermes/hermes-profile.js +12 -0
- package/dist/server/shared/providers.js +1 -13
- package/package.json +1 -1
- package/dist/client/assets/ModelsView-DGs47Cj4.js +0 -1
- package/dist/client/assets/SettingsView-BW6ctYG5.js +0 -352
- package/dist/client/assets/app-BT9yU6N6.js +0 -1
- package/dist/client/assets/app-CjNVVG5x.js +0 -1
- package/dist/client/assets/chat-DlC9S9DK.js +0 -6
- package/dist/client/assets/composables-DCA4Yga5.js +0 -1
- package/dist/client/assets/index-D12ukDT7.js +0 -284
|
@@ -38,28 +38,43 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.logRoutes = void 0;
|
|
40
40
|
const router_1 = __importDefault(require("@koa/router"));
|
|
41
|
+
const fs_1 = require("fs");
|
|
42
|
+
const promises_1 = require("fs/promises");
|
|
43
|
+
const path_1 = require("path");
|
|
44
|
+
const os_1 = require("os");
|
|
41
45
|
const hermesCli = __importStar(require("../../services/hermes/hermes-cli"));
|
|
42
46
|
exports.logRoutes = new router_1.default();
|
|
47
|
+
const WEBUI_LOG_FILE = (0, path_1.join)((0, os_1.homedir)(), '.hermes-web-ui', 'server.log');
|
|
43
48
|
// List available log files
|
|
44
49
|
exports.logRoutes.get('/api/hermes/logs', async (ctx) => {
|
|
45
50
|
const files = await hermesCli.listLogFiles();
|
|
51
|
+
if ((0, fs_1.existsSync)(WEBUI_LOG_FILE)) {
|
|
52
|
+
try {
|
|
53
|
+
const stat = (0, fs_1.statSync)(WEBUI_LOG_FILE);
|
|
54
|
+
const size = stat.size > 1024 * 1024
|
|
55
|
+
? `${(stat.size / 1024 / 1024).toFixed(1)}MB`
|
|
56
|
+
: `${(stat.size / 1024).toFixed(1)}KB`;
|
|
57
|
+
const modified = stat.mtime.toLocaleString();
|
|
58
|
+
files.push({ name: 'webui', size, modified });
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
}
|
|
46
62
|
ctx.body = { files };
|
|
47
63
|
});
|
|
48
64
|
// Parse a single log line into structured entry
|
|
49
65
|
function parseLine(line) {
|
|
50
|
-
// Match: 2026-04-11 20:16:16,289 INFO aiohttp.access: message
|
|
51
|
-
|
|
66
|
+
// Match: 2026-04-11 20:16:16,289 INFO aiohttp.access: message (agent log format)
|
|
67
|
+
let match = line.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+(DEBUG|INFO|WARNING|ERROR|CRITICAL)\s+(\S+?):\s(.*)$/);
|
|
52
68
|
if (match) {
|
|
53
|
-
return {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
69
|
+
return { timestamp: match[1], level: match[2], logger: match[3], message: match[4], raw: line };
|
|
70
|
+
}
|
|
71
|
+
// Match: [Lark] [2026-04-19 18:46:54,864] [INFO] message (gateway log format)
|
|
72
|
+
match = line.match(/^\[(\S+?)\]\s+\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\]\s+\[(DEBUG|INFO|WARNING|ERROR|CRITICAL)\]\s(.*)$/);
|
|
73
|
+
if (match) {
|
|
74
|
+
return { timestamp: match[2], level: match[3], logger: match[1], message: match[4], raw: line };
|
|
60
75
|
}
|
|
61
|
-
// Unparseable line
|
|
62
|
-
return
|
|
76
|
+
// Unparseable line — keep as raw entry so nothing is lost
|
|
77
|
+
return { timestamp: '', level: '', logger: '', message: line, raw: line };
|
|
63
78
|
}
|
|
64
79
|
// Read log lines (parsed)
|
|
65
80
|
exports.logRoutes.get('/api/hermes/logs/:name', async (ctx) => {
|
|
@@ -68,6 +83,30 @@ exports.logRoutes.get('/api/hermes/logs/:name', async (ctx) => {
|
|
|
68
83
|
const level = ctx.query.level || undefined;
|
|
69
84
|
const session = ctx.query.session || undefined;
|
|
70
85
|
const since = ctx.query.since || undefined;
|
|
86
|
+
// Handle hermes-web-ui's own server log
|
|
87
|
+
if (logName === 'webui') {
|
|
88
|
+
try {
|
|
89
|
+
if (!(0, fs_1.existsSync)(WEBUI_LOG_FILE)) {
|
|
90
|
+
ctx.body = { entries: [] };
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const content = await (0, promises_1.readFile)(WEBUI_LOG_FILE, 'utf-8');
|
|
94
|
+
const rawLines = content.split('\n');
|
|
95
|
+
const sliced = rawLines.length > lines ? rawLines.slice(-lines) : rawLines;
|
|
96
|
+
const entries = [];
|
|
97
|
+
for (const line of sliced) {
|
|
98
|
+
if (!line.trim())
|
|
99
|
+
continue;
|
|
100
|
+
entries.push(parseLine(line));
|
|
101
|
+
}
|
|
102
|
+
ctx.body = { entries };
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
ctx.status = 500;
|
|
106
|
+
ctx.body = { error: err.message };
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
71
110
|
try {
|
|
72
111
|
const content = await hermesCli.readLogs(logName, lines, level, session, since);
|
|
73
112
|
const rawLines = content.split('\n');
|
|
@@ -27,22 +27,24 @@ async function waitForGatewayReady(upstream, timeoutMs = 5000) {
|
|
|
27
27
|
}
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
|
+
/** Resolve profile name from request */
|
|
31
|
+
function resolveProfile(ctx) {
|
|
32
|
+
return ctx.get('x-hermes-profile') || ctx.query.profile || 'default';
|
|
33
|
+
}
|
|
30
34
|
/** Resolve upstream URL for a request based on profile header/query */
|
|
31
35
|
function resolveUpstream(ctx) {
|
|
32
36
|
const mgr = (0, gateways_1.getGatewayManager)();
|
|
33
37
|
if (mgr) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (profile) {
|
|
38
|
+
const profile = resolveProfile(ctx);
|
|
39
|
+
if (profile && profile !== 'default') {
|
|
37
40
|
return mgr.getUpstream(profile);
|
|
38
41
|
}
|
|
39
|
-
// Default to active profile's upstream
|
|
40
42
|
return mgr.getUpstream();
|
|
41
43
|
}
|
|
42
|
-
// Fallback: static upstream from config
|
|
43
44
|
return config_1.config.upstream.replace(/\/$/, '');
|
|
44
45
|
}
|
|
45
46
|
async function proxy(ctx) {
|
|
47
|
+
const profile = resolveProfile(ctx);
|
|
46
48
|
const upstream = resolveUpstream(ctx);
|
|
47
49
|
// Rewrite path for upstream gateway:
|
|
48
50
|
// /api/hermes/v1/* -> /v1/* (upstream uses /v1/ prefix)
|
|
@@ -58,7 +60,7 @@ async function proxy(ctx) {
|
|
|
58
60
|
if (lower === 'host') {
|
|
59
61
|
headers['host'] = new URL(upstream).host;
|
|
60
62
|
}
|
|
61
|
-
else if (lower === '
|
|
63
|
+
else if (lower === 'origin' || lower === 'referer' || lower === 'connection') {
|
|
62
64
|
continue;
|
|
63
65
|
}
|
|
64
66
|
else {
|
|
@@ -67,6 +69,14 @@ async function proxy(ctx) {
|
|
|
67
69
|
headers[key] = v;
|
|
68
70
|
}
|
|
69
71
|
}
|
|
72
|
+
// Inject Hermes gateway API key from profile's .env
|
|
73
|
+
const mgr = (0, gateways_1.getGatewayManager)();
|
|
74
|
+
if (mgr) {
|
|
75
|
+
const apiKey = mgr.getApiKey(profile);
|
|
76
|
+
if (apiKey) {
|
|
77
|
+
headers['authorization'] = `Bearer ${apiKey}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
70
80
|
try {
|
|
71
81
|
// Build request body from raw body
|
|
72
82
|
let body;
|
|
@@ -87,6 +87,8 @@ export declare class GatewayManager {
|
|
|
87
87
|
private resolvePort;
|
|
88
88
|
/** 获取指定 profile 的网关 URL(代理路由使用) */
|
|
89
89
|
getUpstream(profileName?: string): string;
|
|
90
|
+
/** 读取 profile 的 API_SERVER_KEY(从 .env 文件) */
|
|
91
|
+
getApiKey(profileName?: string): string | null;
|
|
90
92
|
getActiveProfile(): string;
|
|
91
93
|
setActiveProfile(name: string): void;
|
|
92
94
|
/** 列出所有已知 profile 名称(通过 hermes CLI 或文件系统扫描) */
|
|
@@ -275,6 +275,21 @@ class GatewayManager {
|
|
|
275
275
|
const { port, host } = this.readProfilePort(name);
|
|
276
276
|
return `http://${host}:${port}`;
|
|
277
277
|
}
|
|
278
|
+
/** 读取 profile 的 API_SERVER_KEY(从 .env 文件) */
|
|
279
|
+
getApiKey(profileName) {
|
|
280
|
+
const name = profileName || this.activeProfile;
|
|
281
|
+
try {
|
|
282
|
+
const envPath = (0, path_1.join)(this.profileDir(name), '.env');
|
|
283
|
+
if (!(0, fs_1.existsSync)(envPath))
|
|
284
|
+
return null;
|
|
285
|
+
const content = (0, fs_1.readFileSync)(envPath, 'utf-8');
|
|
286
|
+
const match = content.match(/^API_SERVER_KEY\s*=\s*"?([^"\n]+)"?/m);
|
|
287
|
+
return match?.[1]?.trim() || null;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
278
293
|
getActiveProfile() {
|
|
279
294
|
return this.activeProfile;
|
|
280
295
|
}
|
|
@@ -20,3 +20,9 @@ export declare function getActiveEnvPath(): string;
|
|
|
20
20
|
* Get the active profile name.
|
|
21
21
|
*/
|
|
22
22
|
export declare function getActiveProfileName(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get profile directory by name.
|
|
25
|
+
* default → ~/.hermes/
|
|
26
|
+
* other → ~/.hermes/profiles/{name}/
|
|
27
|
+
*/
|
|
28
|
+
export declare function getProfileDir(name: string): string;
|
|
@@ -5,6 +5,7 @@ exports.getActiveConfigPath = getActiveConfigPath;
|
|
|
5
5
|
exports.getActiveAuthPath = getActiveAuthPath;
|
|
6
6
|
exports.getActiveEnvPath = getActiveEnvPath;
|
|
7
7
|
exports.getActiveProfileName = getActiveProfileName;
|
|
8
|
+
exports.getProfileDir = getProfileDir;
|
|
8
9
|
const path_1 = require("path");
|
|
9
10
|
const os_1 = require("os");
|
|
10
11
|
const fs_1 = require("fs");
|
|
@@ -58,3 +59,14 @@ function getActiveProfileName() {
|
|
|
58
59
|
return 'default';
|
|
59
60
|
}
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Get profile directory by name.
|
|
64
|
+
* default → ~/.hermes/
|
|
65
|
+
* other → ~/.hermes/profiles/{name}/
|
|
66
|
+
*/
|
|
67
|
+
function getProfileDir(name) {
|
|
68
|
+
if (!name || name === 'default')
|
|
69
|
+
return HERMES_BASE;
|
|
70
|
+
const dir = (0, path_1.join)(HERMES_BASE, 'profiles', name);
|
|
71
|
+
return (0, fs_1.existsSync)(dir) ? dir : HERMES_BASE;
|
|
72
|
+
}
|
|
@@ -51,22 +51,10 @@ exports.PROVIDER_PRESETS = [
|
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
label: 'Kimi for Coding',
|
|
54
|
-
value: 'kimi-coding',
|
|
55
|
-
base_url: 'https://api.kimi.com/coding/v1',
|
|
56
|
-
models: [
|
|
57
|
-
'kimi-for-coding',
|
|
58
|
-
'kimi-k2.5',
|
|
59
|
-
'kimi-k2-thinking',
|
|
60
|
-
'kimi-k2-thinking-turbo',
|
|
61
|
-
'kimi-k2-turbo-preview',
|
|
62
|
-
'kimi-k2-0905-preview',
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
label: 'Kimi for Coding (CN)',
|
|
67
54
|
value: 'kimi-coding-cn',
|
|
68
55
|
base_url: 'https://api.kimi.com/coding/v1',
|
|
69
56
|
models: [
|
|
57
|
+
'kimi-for-coding',
|
|
70
58
|
'kimi-k2.5',
|
|
71
59
|
'kimi-k2-thinking',
|
|
72
60
|
'kimi-k2-turbo-preview',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hermes-web-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Web dashboard for Hermes Agent — multi-platform AI chat, session management, scheduled jobs, usage analytics & channel configuration (Telegram, Discord, Slack, WhatsApp)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,C as t,D as n,E as r,G as i,Q as a,T as o,U as s,W as c,X as l,Y as u,ct as d,gt as f,j as p,k as m,mt as h,o as g,pt as _,q as v,w as y,y as b}from"./router-C-NNJUuf.js";import{n as x}from"./pinia-iHE5_ZXa.js";import{r as S,t as C}from"./_plugin-vue_export-helper-CnosYBkx.js";import{t as w}from"./Modal-B2zvXTrk.js";import{n as T,t as E}from"./FormItem-BgJdrTW0.js";import{t as D}from"./Select-BHc7u-Yf.js";import{t as O}from"./Button-CrrCCorI.js";import{t as k}from"./Input-ChENEW-Z.js";import{t as A}from"./composables-DCA4Yga5.js";import{t as j}from"./use-message-BIpqgDet.js";import{t as M}from"./Spin-DsNCRPk9.js";import{a as N,i as P,n as F,r as I,t as L}from"./app-BT9yU6N6.js";var R=x(`models`,()=>{let e=d([]),n=d(``),r=d(!1),i=t(()=>e.value.filter(e=>e.provider.startsWith(`custom:`))),a=t(()=>e.value.filter(e=>!e.provider.startsWith(`custom:`))),o=t(()=>e.value.flatMap(e=>e.models.map(t=>({id:t,provider:e.provider,label:e.label,base_url:e.base_url,isDefault:t===n.value}))));async function s(){r.value=!0;try{let t=await I();e.value=t.groups,n.value=t.default}catch(e){console.error(`Failed to fetch providers:`,e)}finally{r.value=!1}}async function c(e,t){await N({default:e,provider:t}),n.value=e,L().loadModels()}async function l(e){await F(e),await s(),L().loadModels()}async function u(e){await P(e),await s(),L().loadModels()}return{providers:e,defaultModel:n,loading:r,customProviders:i,builtinProviders:a,allModels:o,fetchProviders:s,setDefaultModel:c,addProvider:l,removeProvider:u}}),z={class:`provider-card`},B={class:`card-header`},V={class:`provider-name`},ee={class:`card-body`},te={class:`info-row`},H={class:`info-label`},U={class:`info-value mono`},W={class:`info-row`},G={class:`info-label`},K={class:`info-value mono`},q={class:`card-actions`},J=C(p({__name:`ProviderCard`,props:{provider:{}},setup(r){let o=r,{t:s}=S(),c=R(),l=j(),u=A(),d=t(()=>o.provider.provider.startsWith(`custom:`)),p=t(()=>o.provider.label);async function g(){u.warning({title:s(`models.deleteProvider`),content:s(`models.deleteConfirm`,{name:p.value}),positiveText:s(`common.delete`),negativeText:s(`common.cancel`),onPositiveClick:async()=>{try{await c.removeProvider(o.provider.provider),l.success(s(`models.providerDeleted`))}catch(e){l.error(e.message)}}})}return(t,o)=>(i(),n(`div`,z,[y(`div`,B,[y(`h3`,V,f(p.value),1),y(`span`,{class:h([`type-badge`,d.value?`custom`:`builtin`])},f(d.value?_(s)(`models.customType`):_(s)(`models.builtIn`)),3)]),y(`div`,ee,[y(`div`,te,[y(`span`,H,f(_(s)(`models.provider`)),1),y(`code`,U,f(r.provider.provider),1)]),y(`div`,W,[y(`span`,G,f(_(s)(`models.baseUrl`)),1),y(`code`,K,f(r.provider.base_url),1)])]),y(`div`,q,[e(_(O),{size:`tiny`,quaternary:``,type:`error`,onClick:g},{default:a(()=>[m(f(_(s)(`common.delete`)),1)]),_:1})])]))}}),[[`__scopeId`,`data-v-31916e31`]]),Y={key:0,class:`empty-state`},X={key:1,class:`providers-grid`},Z=C(p({__name:`ProvidersPanel`,setup(e){let{t}=S(),r=R();return(e,a)=>_(r).providers.length===0?(i(),n(`div`,Y,[a[0]||=y(`svg`,{width:`48`,height:`48`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1`,class:`empty-icon`},[y(`path`,{d:`M12 2L2 7l10 5 10-5-10-5z`}),y(`path`,{d:`M2 17l10 5 10-5`}),y(`path`,{d:`M2 12l10 5 10-5`})],-1),y(`p`,null,f(_(t)(`models.noProviders`)),1)])):(i(),n(`div`,X,[(i(!0),n(b,null,v(_(r).providers,e=>(i(),o(J,{key:e.provider,provider:e},null,8,[`provider`]))),128))]))}}),[[`__scopeId`,`data-v-76eec30b`]]),Q=[{label:`Anthropic`,value:`anthropic`,base_url:`https://api.anthropic.com`,models:[`claude-opus-4-7`,`claude-opus-4-6`,`claude-sonnet-4-6`,`claude-opus-4-5-20251101`,`claude-sonnet-4-5-20250929`,`claude-opus-4-20250514`,`claude-sonnet-4-20250514`,`claude-haiku-4-5-20251001`]},{label:`Google AI Studio`,value:`gemini`,base_url:`https://generativelanguage.googleapis.com/v1beta/openai`,models:[`gemini-3.1-pro-preview`,`gemini-3-flash-preview`,`gemini-3.1-flash-lite-preview`,`gemini-2.5-pro`,`gemini-2.5-flash`,`gemini-2.5-flash-lite`,`gemma-4-31b-it`,`gemma-4-26b-it`]},{label:`DeepSeek`,value:`deepseek`,base_url:`https://api.deepseek.com`,models:[`deepseek-chat`,`deepseek-reasoner`]},{label:`Z.AI / GLM`,value:`zai`,base_url:`https://api.z.ai/api/paas/v4`,models:[`glm-5.1`,`glm-5`,`glm-5v-turbo`,`glm-5-turbo`,`glm-4.7`,`glm-4.5`,`glm-4.5-flash`]},{label:`Kimi for Coding`,value:`kimi-coding`,base_url:`https://api.kimi.com/coding/v1`,models:[`kimi-for-coding`,`kimi-k2.5`,`kimi-k2-thinking`,`kimi-k2-thinking-turbo`,`kimi-k2-turbo-preview`,`kimi-k2-0905-preview`]},{label:`Kimi for Coding (CN)`,value:`kimi-coding-cn`,base_url:`https://api.kimi.com/coding/v1`,models:[`kimi-k2.5`,`kimi-k2-thinking`,`kimi-k2-turbo-preview`,`kimi-k2-0905-preview`]},{label:`Moonshot`,value:`moonshot`,base_url:`https://api.moonshot.cn/v1`,models:[`kimi-k2.5`,`kimi-k2-thinking`,`kimi-k2-turbo-preview`,`kimi-k2-0905-preview`]},{label:`xAI`,value:`xai`,base_url:`https://api.x.ai/v1`,models:[`grok-4.20-reasoning`,`grok-4-1-fast-reasoning`]},{label:`MiniMax`,value:`minimax`,base_url:`https://api.minimax.io/anthropic/v1`,models:[`MiniMax-M2.7`,`MiniMax-M2.7-highspeed`,`MiniMax-M2.5`,`MiniMax-M2.5-highspeed`,`MiniMax-M2.1`,`MiniMax-M2.1-highspeed`,`MiniMax-M2`,`MiniMax-M2-highspeed`]},{label:`MiniMax (China)`,value:`minimax-cn`,base_url:`https://api.minimaxi.com/v1`,models:[`MiniMax-M2.7`,`MiniMax-M2.7-highspeed`,`MiniMax-M2.5`,`MiniMax-M2.5-highspeed`,`MiniMax-M2.1`,`MiniMax-M2.1-highspeed`,`MiniMax-M2`,`MiniMax-M2-highspeed`]},{label:`Alibaba Cloud`,value:`alibaba`,base_url:`https://dashscope-intl.aliyuncs.com/compatible-mode/v1`,models:[`qwen3.5-plus`,`qwen3-coder-plus`,`qwen3-coder-next`,`glm-5`,`glm-4.7`,`kimi-k2.5`,`MiniMax-M2.5`]},{label:`Hugging Face`,value:`huggingface`,base_url:`https://router.huggingface.co/v1`,models:[`Qwen/Qwen3.5-397B-A17B`,`Qwen/Qwen3.5-35B-A3B`,`deepseek-ai/DeepSeek-V3.2`,`moonshotai/Kimi-K2.5`,`MiniMaxAI/MiniMax-M2.5`,`zai-org/GLM-5`,`XiaomiMiMo/MiMo-V2-Flash`,`moonshotai/Kimi-K2-Thinking`]},{label:`Xiaomi MiMo`,value:`xiaomi`,base_url:`https://api.xiaomimimo.com/v1`,models:[`mimo-v2-pro`,`mimo-v2-omni`,`mimo-v2-flash`]},{label:`Kilo Code`,value:`kilocode`,base_url:`https://api.kilo.ai/api/gateway`,models:[`anthropic/claude-opus-4.6`,`anthropic/claude-sonnet-4.6`,`openai/gpt-5.4`,`google/gemini-3-pro-preview`,`google/gemini-3-flash-preview`]},{label:`Vercel AI Gateway`,value:`ai-gateway`,base_url:`https://ai-gateway.vercel.sh/v1`,models:[`anthropic/claude-opus-4.6`,`anthropic/claude-sonnet-4.6`,`anthropic/claude-sonnet-4.5`,`anthropic/claude-haiku-4.5`,`openai/gpt-5`,`openai/gpt-4.1`,`openai/gpt-4.1-mini`,`google/gemini-3-pro-preview`,`google/gemini-3-flash`,`google/gemini-2.5-pro`,`google/gemini-2.5-flash`,`deepseek/deepseek-v3.2`]},{label:`OpenCode Zen`,value:`opencode-zen`,base_url:`https://opencode.ai/zen/v1`,models:`gpt-5.4-pro,gpt-5.4,gpt-5.3-codex,gpt-5.3-codex-spark,gpt-5.2,gpt-5.2-codex,gpt-5.1,gpt-5.1-codex,gpt-5.1-codex-max,gpt-5.1-codex-mini,gpt-5,gpt-5-codex,gpt-5-nano,claude-opus-4-6,claude-opus-4-5,claude-opus-4-1,claude-sonnet-4-6,claude-sonnet-4-5,claude-sonnet-4,claude-haiku-4-5,claude-3-5-haiku,gemini-3.1-pro,gemini-3-pro,gemini-3-flash,minimax-m2.7,minimax-m2.5,minimax-m2.5-free,minimax-m2.1,glm-5,glm-4.7,glm-4.6,kimi-k2.5,kimi-k2-thinking,kimi-k2,qwen3-coder,big-pickle`.split(`,`)},{label:`OpenCode Go`,value:`opencode-go`,base_url:`https://opencode.ai/zen/go/v1`,models:[`glm-5.1`,`glm-5`,`kimi-k2.5`,`mimo-v2-pro`,`mimo-v2-omni`,`minimax-m2.7`,`minimax-m2.5`]},{label:`OpenAI Codex`,value:`openai-codex`,base_url:`https://chatgpt.com/backend-api/codex`,models:[`gpt-5.4-mini`,`gpt-5.4`,`gpt-5.3-codex`,`gpt-5.2-codex`,`gpt-5.1-codex-max`,`gpt-5.1-codex-mini`]},{label:`Arcee AI`,value:`arcee`,base_url:`https://api.arcee.ai/v1`,models:[`trinity-large-thinking`,`trinity-large-preview`,`trinity-mini`]},{label:`OpenRouter`,value:`openrouter`,base_url:`https://openrouter.ai/api/v1`,models:[]}];async function ne(){return g(`/api/hermes/auth/codex/start`,{method:`POST`})}async function re(e){return g(`/api/hermes/auth/codex/poll/${e}`)}var ie={class:`codex-login`},ae={key:0,class:`codex-login__state`},oe={key:1,class:`codex-login__state`},se={class:`codex-login__hint`},ce={class:`codex-login__code-text`},le={key:2,class:`codex-login__state codex-login__state--success`},ue={key:3,class:`codex-login__state`},de={class:`codex-login__error`},fe={key:4,class:`codex-login__state`},pe={class:`codex-login__error`},me={class:`modal-footer`},he=C(p({__name:`CodexLoginModal`,emits:[`close`,`success`],setup(t,{emit:s}){let{t:l}=S(),p=s,h=j(),g=d(!0),v=d(`idle`),b=d(``),x=d(``),C=d(``),T=d(``),E=null;async function D(){v.value=`loading`,T.value=``;try{let e=await ne();b.value=e.user_code,x.value=e.verification_url,C.value=e.session_id,v.value=`waiting`,k()}catch(e){v.value=`error`;let t=e.message||``;try{let e=t.match(/\{[\s\S]*\}$/);e?T.value=JSON.parse(e[0]).error||t:T.value=t}catch{T.value=t}h.error(T.value)}}function k(){A(),E=setTimeout(async()=>{try{let e=await re(C.value);e.status===`pending`?k():e.status===`approved`?(v.value=`approved`,h.success(l(`models.codexApproved`)),setTimeout(()=>{g.value=!1,setTimeout(()=>p(`success`),200)},1e3)):e.status===`expired`?v.value=`expired`:e.status===`error`&&(v.value=`error`,T.value=e.error||`Unknown error`)}catch{k()}},3e3)}function A(){E&&=(clearTimeout(E),null)}function M(){A(),g.value=!1,setTimeout(()=>p(`close`),200)}function N(){navigator.clipboard.writeText(b.value),h.success(l(`models.codexCopyCode`))}function P(){window.open(x.value,`_blank`)}function F(){v.value=`idle`,b.value=``,x.value=``,C.value=``,T.value=``,D()}return c(()=>{A()}),D(),(t,s)=>{let c=u(`NSpin`);return i(),o(_(w),{show:g.value,"onUpdate:show":s[0]||=e=>g.value=e,preset:`card`,title:_(l)(`models.codexLoginTitle`),style:{width:`min(440px, calc(100vw - 32px))`},"mask-closable":v.value!==`waiting`,onAfterLeave:s[1]||=e=>p(`close`)},{footer:a(()=>[y(`div`,me,[e(_(O),{disabled:v.value===`waiting`,onClick:M},{default:a(()=>[m(f(_(l)(`common.cancel`)),1)]),_:1},8,[`disabled`])])]),default:a(()=>[y(`div`,ie,[v.value===`idle`||v.value===`loading`?(i(),n(`div`,ae,[e(c,{size:`small`})])):v.value===`waiting`?(i(),n(`div`,oe,[y(`p`,se,f(_(l)(`models.codexWaiting`)),1),y(`div`,{class:`codex-login__code`,onClick:N},[y(`span`,ce,f(b.value),1),s[2]||=y(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[y(`rect`,{x:`9`,y:`9`,width:`13`,height:`13`,rx:`2`}),y(`path`,{d:`M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1`})],-1)]),e(_(O),{type:`primary`,block:``,onClick:P},{icon:a(()=>[...s[3]||=[y(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[y(`path`,{d:`M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6`}),y(`polyline`,{points:`15 3 21 3 21 9`}),y(`line`,{x1:`10`,y1:`14`,x2:`21`,y2:`3`})],-1)]]),default:a(()=>[m(` `+f(_(l)(`models.codexOpenLink`)),1)]),_:1})])):v.value===`approved`?(i(),n(`div`,le,[s[4]||=y(`svg`,{width:`40`,height:`40`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[y(`path`,{d:`M22 11.08V12a10 10 0 11-5.93-9.14`}),y(`polyline`,{points:`22 4 12 14.01 9 11.01`})],-1),y(`p`,null,f(_(l)(`models.codexApproved`)),1)])):v.value===`expired`?(i(),n(`div`,ue,[y(`p`,de,f(_(l)(`models.codexExpired`)),1),e(_(O),{size:`small`,onClick:F},{default:a(()=>[m(f(_(l)(`common.retry`)),1)]),_:1})])):v.value===`error`?(i(),n(`div`,fe,[y(`p`,pe,f(T.value),1),e(_(O),{size:`small`,onClick:F},{default:a(()=>[m(f(_(l)(`common.retry`)),1)]),_:1})])):r(``,!0)])]),_:1},8,[`show`,`title`,`mask-closable`])}}}),[[`__scopeId`,`data-v-3639ba5a`]]),ge={style:{display:`flex`,gap:`12px`}},_e={style:{display:`flex`,gap:`8px`,width:`100%`}},ve={class:`modal-footer`},ye=`openai-codex`,$=C(p({__name:`ProviderFormModal`,emits:[`close`,`saved`],setup(n,{emit:s}){let{t:c}=S(),u=s,p=R(),h=j(),g=d(!0),v=d(!1),b=d(!1),x=d(!1),C=d(`preset`),A=d(null),M=d({name:``,base_url:``,api_key:``,model:``}),N=d([]),P=Q,F=t(()=>A.value===ye);function I(e){let t=e.replace(/^https?:\/\//,``).replace(/\/v1\/?$/,``).split(`/`)[0];return t.includes(`localhost`)||t.includes(`127.0.0.1`)?c(`models.local`,{host:t}):t.charAt(0).toUpperCase()+t.slice(1)}l(A,e=>{if(M.value.model=``,e){let t=P.find(t=>t.value===e);t&&(M.value.name=t.label,M.value.base_url=t.base_url,N.value=t.models.map(e=>({label:e,value:e})),t.models.length>0&&(M.value.model=t.models[0]))}}),l(()=>M.value.base_url,e=>{C.value===`custom`&&e.trim()&&(M.value.name=I(e.trim()))}),l(C,()=>{N.value=[],M.value={name:``,base_url:``,api_key:``,model:``},A.value=null});async function L(){let{base_url:e}=M.value;if(!e.trim()){h.warning(c(`models.enterBaseUrl`));return}b.value=!0;try{let t=e.replace(/\/+$/,``)+`/models`,n={};M.value.api_key.trim()&&(n.Authorization=`Bearer ${M.value.api_key.trim()}`);let r=await fetch(t,{headers:n,signal:AbortSignal.timeout(8e3)});if(!r.ok)throw Error(`HTTP ${r.status}`);let i=await r.json();if(!Array.isArray(i.data))throw Error(c(`models.unexpectedFormat`));N.value=i.data.map(e=>({label:e.id,value:e.id})),N.value.length>0&&!M.value.model&&(M.value.model=N.value[0].value),h.success(c(`models.foundModels`,{count:N.value.length}))}catch(e){h.error(c(`models.fetchFailed`)+`: `+e.message)}finally{b.value=!1}}async function z(){if(C.value===`preset`&&!A.value){h.warning(c(`models.selectProviderRequired`));return}if(F.value){x.value=!0;return}if(!M.value.base_url.trim()){h.warning(c(`models.baseUrlRequired`));return}if(!M.value.api_key.trim()){h.warning(c(`models.apiKeyRequired`));return}if(!M.value.model){h.warning(c(`models.modelRequired`));return}v.value=!0;try{let e=C.value===`preset`&&P.find(e=>e.value===A.value)?.value||null;await p.addProvider({name:M.value.name.trim(),base_url:M.value.base_url.trim(),api_key:M.value.api_key.trim(),model:M.value.model,providerKey:e}),h.success(c(`models.providerAdded`)),u(`saved`)}catch(e){h.error(e.message)}finally{v.value=!1}}async function B(){x.value=!1,h.success(c(`models.providerAdded`)),u(`saved`)}function V(){g.value=!1,setTimeout(()=>u(`close`),200)}return(t,n)=>(i(),o(_(w),{show:g.value,"onUpdate:show":n[8]||=e=>g.value=e,preset:`card`,title:_(c)(`models.addProvider`),style:{width:`min(520px, calc(100vw - 32px))`},"mask-closable":!v.value&&!x.value,onAfterLeave:n[9]||=e=>u(`close`)},{footer:a(()=>[y(`div`,ve,[e(_(O),{onClick:V},{default:a(()=>[m(f(_(c)(`common.cancel`)),1)]),_:1}),e(_(O),{type:`primary`,loading:v.value,onClick:z},{default:a(()=>[m(f(_(c)(`common.add`)),1)]),_:1},8,[`loading`])])]),default:a(()=>[e(_(T),{"label-placement":`top`},{default:a(()=>[e(_(E),{label:_(c)(`models.providerType`)},{default:a(()=>[y(`div`,ge,[e(_(O),{type:C.value===`preset`?`primary`:`default`,size:`small`,onClick:n[0]||=e=>C.value=`preset`},{default:a(()=>[m(f(_(c)(`models.preset`)),1)]),_:1},8,[`type`]),e(_(O),{type:C.value===`custom`?`primary`:`default`,size:`small`,onClick:n[1]||=e=>C.value=`custom`},{default:a(()=>[m(f(_(c)(`models.custom`)),1)]),_:1},8,[`type`])])]),_:1},8,[`label`]),C.value===`preset`?(i(),o(_(E),{key:0,label:_(c)(`models.selectProvider`),required:``},{default:a(()=>[e(_(D),{value:A.value,"onUpdate:value":n[2]||=e=>A.value=e,options:_(P),placeholder:_(c)(`models.chooseProvider`),filterable:``},null,8,[`value`,`options`,`placeholder`])]),_:1},8,[`label`])):r(``,!0),C.value===`custom`?(i(),o(_(E),{key:1,label:_(c)(`models.name`)},{default:a(()=>[e(_(k),{value:M.value.name,"onUpdate:value":n[3]||=e=>M.value.name=e,placeholder:_(c)(`models.autoGeneratedName`),disabled:``},null,8,[`value`,`placeholder`])]),_:1},8,[`label`])):r(``,!0),F.value?r(``,!0):(i(),o(_(E),{key:2,label:_(c)(`models.baseUrl`),required:``},{default:a(()=>[e(_(k),{value:M.value.base_url,"onUpdate:value":n[4]||=e=>M.value.base_url=e,placeholder:_(c)(`models.baseUrlPlaceholder`),disabled:C.value===`preset`},null,8,[`value`,`placeholder`,`disabled`])]),_:1},8,[`label`])),F.value?r(``,!0):(i(),o(_(E),{key:3,label:_(c)(`models.apiKey`),required:``},{default:a(()=>[e(_(k),{value:M.value.api_key,"onUpdate:value":n[5]||=e=>M.value.api_key=e,type:`password`,"show-password-on":`click`,placeholder:_(c)(`models.apiKeyPlaceholder`),autocomplete:`off`},null,8,[`value`,`placeholder`])]),_:1},8,[`label`])),e(_(E),{label:_(c)(`models.defaultModel`),required:``},{default:a(()=>[y(`div`,_e,[e(_(D),{value:M.value.model,"onUpdate:value":n[6]||=e=>M.value.model=e,options:N.value,filterable:``,tag:``,placeholder:_(c)(`models.selectOrInput`),style:{flex:`1`}},null,8,[`value`,`options`,`placeholder`]),C.value===`custom`||C.value===`preset`&&N.value.length===0?(i(),o(_(O),{key:0,loading:b.value,onClick:L},{default:a(()=>[m(f(_(c)(`common.fetch`)),1)]),_:1},8,[`loading`])):r(``,!0)])]),_:1},8,[`label`])]),_:1}),x.value?(i(),o(he,{key:0,onClose:n[7]||=e=>x.value=!1,onSuccess:B})):r(``,!0)]),_:1},8,[`show`,`title`,`mask-closable`]))}}),[[`__scopeId`,`data-v-89084223`]]),be={class:`models-view`},xe={class:`page-header`},Se={class:`header-title`},Ce={class:`models-content`},we=C(p({__name:`ModelsView`,setup(t){let{t:c}=S(),l=R(),u=L(),p=d(!1);s(()=>{l.fetchProviders()});function h(){p.value=!0}function g(){p.value=!1}async function v(){await l.fetchProviders(),u.loadModels(),g()}return(t,s)=>(i(),n(`div`,be,[y(`header`,xe,[y(`h2`,Se,f(_(c)(`models.title`)),1),e(_(O),{type:`primary`,size:`small`,onClick:h},{icon:a(()=>[...s[0]||=[y(`svg`,{width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`},[y(`line`,{x1:`12`,y1:`5`,x2:`12`,y2:`19`}),y(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`})],-1)]]),default:a(()=>[m(` `+f(_(c)(`models.addProvider`)),1)]),_:1})]),y(`div`,Ce,[e(_(M),{show:_(l).loading&&_(l).providers.length===0},{default:a(()=>[e(Z)]),_:1},8,[`show`])]),p.value?(i(),o($,{key:0,onClose:g,onSaved:v})):r(``,!0)]))}}),[[`__scopeId`,`data-v-84eaeb4c`]]);export{we as default};
|