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.
Files changed (74) hide show
  1. package/bin/hermes-web-ui.mjs +15 -1
  2. package/dist/client/assets/{Add-CKf6ViXR.js → Add-Cc7cgBoB.js} +1 -1
  3. package/dist/client/assets/{Button-CrrCCorI.js → Button-EoeZgIFH.js} +1 -1
  4. package/dist/client/assets/{ChannelsView-D4I7hhZO.js → ChannelsView-Bfbq3w7n.js} +1 -1
  5. package/dist/client/assets/{ChatView-DxyBUK57.js → ChatView-CDdyTo72.js} +1 -1
  6. package/dist/client/assets/{Close-C9xwy-pW.js → Close-CKHcXisf.js} +1 -1
  7. package/dist/client/assets/{FormItem-BgJdrTW0.js → FormItem-CvZvjrtr.js} +1 -1
  8. package/dist/client/assets/{GatewaysView-Cib2JydO.js → GatewaysView-Dp4-TFPE.js} +1 -1
  9. package/dist/client/assets/{Input-ChENEW-Z.js → Input-Bk7XdoG-.js} +1 -1
  10. package/dist/client/assets/{InputNumber-Xd6HWSdp.js → InputNumber-Dn0EHi-K.js} +1 -1
  11. package/dist/client/assets/{JobsView-SnToCbDd.js → JobsView-D4JN73Zz.js} +2 -2
  12. package/dist/client/assets/{LoginView-BZdmMnsf.js → LoginView--hy5CI5O.js} +1 -1
  13. package/dist/client/assets/{LogsView-DblvOJIg.js → LogsView-Dz2ZeYad.js} +1 -1
  14. package/dist/client/assets/{MarkdownRenderer-DJLVk7ei.js → MarkdownRenderer-BbedVxvo.js} +1 -1
  15. package/dist/client/assets/{MemoryView-exXvRwCc.js → MemoryView-D2EHM35l.js} +1 -1
  16. package/dist/client/assets/{Modal-B2zvXTrk.js → Modal-C5-Iw50K.js} +1 -1
  17. package/dist/client/assets/ModelsView-CtrRf4vK.js +1 -0
  18. package/dist/client/assets/{ModelsView-jbgZP3YF.css → ModelsView-VM-oMq5M.css} +1 -1
  19. package/dist/client/assets/{Popconfirm-BoZc0kKk.js → Popconfirm-C-M2anVL.js} +1 -1
  20. package/dist/client/assets/{Popover-Cu52vG3D.js → Popover-mIRPCy7U.js} +1 -1
  21. package/dist/client/assets/{ProfilesView-D0FY7Jwe.js → ProfilesView-Dy9PivgB.js} +1 -1
  22. package/dist/client/assets/{Select-BHc7u-Yf.js → Select-uZBC8HC2.js} +2 -2
  23. package/dist/client/assets/{SettingRow-i-UXlco7.js → SettingRow-D9R65bDj.js} +1 -1
  24. package/dist/client/assets/{SettingsView-Dhr2wzAB.css → SettingsView-C3sd8K0e.css} +1 -1
  25. package/dist/client/assets/SettingsView-DWEEXqSY.js +352 -0
  26. package/dist/client/assets/{SkillsView-B5QBaAzi.js → SkillsView-CdZSRy9_.js} +1 -1
  27. package/dist/client/assets/{Spin-DsNCRPk9.js → Spin-ChbFBUOD.js} +1 -1
  28. package/dist/client/assets/{Suffix-3xK0KZGt.js → Suffix-DgzfIwzx.js} +1 -1
  29. package/dist/client/assets/{Switch-Bf63XXgA.js → Switch--HhY1uSh.js} +1 -1
  30. package/dist/client/assets/{Tag-Dmbj68Ki.js → Tag-B2zrHMmZ.js} +1 -1
  31. package/dist/client/assets/{TerminalView-DrJHZ0qI.js → TerminalView-BwfnH803.js} +1 -1
  32. package/dist/client/assets/{Tooltip-CRbZNhG0.js → Tooltip-9tdvSKGi.js} +1 -1
  33. package/dist/client/assets/{UsageView-DQ43JasX.js → UsageView-zL3a7F86.js} +1 -1
  34. package/dist/client/assets/{Warning-kBbRMAif.js → Warning-CXXqHzLa.js} +1 -1
  35. package/dist/client/assets/{_plugin-vue_export-helper-CnosYBkx.js → _plugin-vue_export-helper-Cnn0Z73x.js} +1 -1
  36. package/dist/client/assets/app-BMobzABI.js +1 -0
  37. package/dist/client/assets/app-Bqu9Uz-1.js +1 -0
  38. package/dist/client/assets/{browser-Djp4tkp3.js → browser-CQRjhbaB.js} +1 -1
  39. package/dist/client/assets/chat-BIdq6ZXF.js +6 -0
  40. package/dist/client/assets/composables-ClIU-Ad1.js +1 -0
  41. package/dist/client/assets/{fade-in.cssr-CIVyTG6A.js → fade-in.cssr-lwO9nLky.js} +1 -1
  42. package/dist/client/assets/index-Tg6M43Om.js +284 -0
  43. package/dist/client/assets/{jobs-CcVaCGMJ.js → jobs-Z2HS0j2d.js} +1 -1
  44. package/dist/client/assets/{light-CSp9-LhE.js → light-CjCy-Dkn.js} +1 -1
  45. package/dist/client/assets/{light-BJ96fCLC.js → light-DZ0Ns16h.js} +1 -1
  46. package/dist/client/assets/{light-BF6E9z0k.js → light-DgIst23O.js} +1 -1
  47. package/dist/client/assets/{light-KCEDTUGE.js → light-Dx6qj2pM.js} +1 -1
  48. package/dist/client/assets/{light-BPqyaxve.js → light-DzpNsLai.js} +1 -1
  49. package/dist/client/assets/{light-D9G2GshF.js → light-oE8MEiWL.js} +1 -1
  50. package/dist/client/assets/models-DLQiHB7r.js +1 -0
  51. package/dist/client/assets/{pinia-iHE5_ZXa.js → pinia-Dp_b1vdW.js} +1 -1
  52. package/dist/client/assets/{profiles-CJCR84uQ.js → profiles-CNTHYFZE.js} +1 -1
  53. package/dist/client/assets/{router-C-NNJUuf.js → router-Dj-Nmg7q.js} +2 -2
  54. package/dist/client/assets/{sessions-C4bnNvzS.js → sessions-C0kvgvBm.js} +1 -1
  55. package/dist/client/assets/{skills-B4slZfeZ.js → skills-G7EoEvdS.js} +1 -1
  56. package/dist/client/assets/{use-message-BIpqgDet.js → use-message-BgToAqhv.js} +1 -1
  57. package/dist/client/assets/{useTheme-B78N9tyz.js → useTheme-BUShiwRu.js} +1 -1
  58. package/dist/client/index.html +27 -27
  59. package/dist/server/routes/hermes/filesystem.js +231 -199
  60. package/dist/server/routes/hermes/logs.js +50 -11
  61. package/dist/server/routes/hermes/proxy-handler.js +16 -6
  62. package/dist/server/services/hermes/gateway-manager.d.ts +2 -0
  63. package/dist/server/services/hermes/gateway-manager.js +15 -0
  64. package/dist/server/services/hermes/hermes-profile.d.ts +6 -0
  65. package/dist/server/services/hermes/hermes-profile.js +12 -0
  66. package/dist/server/shared/providers.js +1 -13
  67. package/package.json +1 -1
  68. package/dist/client/assets/ModelsView-DGs47Cj4.js +0 -1
  69. package/dist/client/assets/SettingsView-BW6ctYG5.js +0 -352
  70. package/dist/client/assets/app-BT9yU6N6.js +0 -1
  71. package/dist/client/assets/app-CjNVVG5x.js +0 -1
  72. package/dist/client/assets/chat-DlC9S9DK.js +0 -6
  73. package/dist/client/assets/composables-DCA4Yga5.js +0 -1
  74. 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
- const 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(.*)$/);
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
- timestamp: match[1],
55
- level: match[2],
56
- logger: match[3],
57
- message: match[4],
58
- raw: line,
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 (e.g. traceback continuation)
62
- return null;
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
- // Check X-Hermes-Profile header or ?profile= query param
35
- const profile = ctx.get('x-hermes-profile') || ctx.query.profile;
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 === 'authorization' || lower === 'origin' || lower === 'referer' || lower === 'connection') {
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.6",
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};