hermes-web-ui 0.3.1 → 0.3.2

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 (79) hide show
  1. package/dist/client/assets/{Add-cXqy3eJz.js → Add-CYFVC6GK.js} +1 -1
  2. package/dist/client/assets/{Button-BeWnBoDR.js → Button-Bls2FkVh.js} +1 -1
  3. package/dist/client/assets/{ChannelsView-Do43S3tP.css → ChannelsView-CSo2o-P4.css} +1 -1
  4. package/dist/client/assets/ChannelsView-hQeWN-ve.js +1 -0
  5. package/dist/client/assets/{ChatView-CqA3Wo54.js → ChatView-C67INFi3.js} +1 -1
  6. package/dist/client/assets/{Close-ySsuLJTC.js → Close-CkAmZwHA.js} +1 -1
  7. package/dist/client/assets/{FormItem-EcbFnIOF.js → FormItem-CO8nEllS.js} +1 -1
  8. package/dist/client/assets/{Input-DP5LDvGa.js → Input-CmTdqaW1.js} +1 -1
  9. package/dist/client/assets/{InputNumber-CU7XKbbt.js → InputNumber-BVqiFQ5W.js} +1 -1
  10. package/dist/client/assets/JobsView-B0LZ2Ep0.js +2 -0
  11. package/dist/client/assets/{JobsView-CvuV9mZY.css → JobsView-CVx2Yv-y.css} +1 -1
  12. package/dist/client/assets/{LoginView-CDJXoOEZ.js → LoginView-BjqBXdDl.js} +1 -1
  13. package/dist/client/assets/{LogsView-DS_E9xkh.js → LogsView-CXiJ_mte.js} +1 -1
  14. package/dist/client/assets/{MarkdownRenderer-BntkPd0f.js → MarkdownRenderer-CtI0yse1.js} +1 -1
  15. package/dist/client/assets/{MemoryView-CCCXW1tv.js → MemoryView-CjPn1pVR.js} +1 -1
  16. package/dist/client/assets/{Modal-D_vF9k8c.js → Modal-apmj2qGK.js} +1 -1
  17. package/dist/client/assets/ModelsView-DXvahVC_.js +1 -0
  18. package/dist/client/assets/{Popconfirm-IKYJxM7n.js → Popconfirm-B9XSMaYA.js} +1 -1
  19. package/dist/client/assets/{Popover-BLBLYanQ.js → Popover-CjCb_fJl.js} +1 -1
  20. package/dist/client/assets/{ProfilesView-qt3NXito.js → ProfilesView-CmMfNg5X.js} +1 -1
  21. package/dist/client/assets/{Scrollbar-DZGif2x4.js → Scrollbar-v6Ok23iG.js} +1 -1
  22. package/dist/client/assets/{Select-3KS3TLPL.js → Select-CDF2CEro.js} +1 -1
  23. package/dist/client/assets/{SettingRow-D26AUezg.js → SettingRow-CSjwu__h.js} +1 -1
  24. package/dist/client/assets/{SettingsView-C78xbLXK.css → SettingsView-BIEQOPzq.css} +1 -1
  25. package/dist/client/assets/{SettingsView-30x1265A.js → SettingsView-BYedQhU5.js} +2 -2
  26. package/dist/client/assets/{SkillsView-qq8Oz7fo.js → SkillsView-B_MA4How.js} +1 -1
  27. package/dist/client/assets/{Spin-C9izy3tZ.js → Spin-UqA8uGuf.js} +1 -1
  28. package/dist/client/assets/{Suffix-CIX5CF-j.js → Suffix-iRME2DUp.js} +1 -1
  29. package/dist/client/assets/{Switch-D9x35tOv.js → Switch-B4za8e-x.js} +1 -1
  30. package/dist/client/assets/{TerminalView-zaRNn2aX.js → TerminalView-C0xlWgsR.js} +1 -1
  31. package/dist/client/assets/{Tooltip-A5--U35v.js → Tooltip-C9kFaGpi.js} +1 -1
  32. package/dist/client/assets/{UsageView-DQ3t8CHE.js → UsageView-Df6TKjYG.js} +1 -1
  33. package/dist/client/assets/{Warning-BZfjWCrB.js → Warning-C--exCXL.js} +1 -1
  34. package/dist/client/assets/{_plugin-vue_export-helper-B4hqCVU_.js → _plugin-vue_export-helper-BPCSidQI.js} +1 -1
  35. package/dist/client/assets/{app-DG_zFxqi.js → app-BEBfTlZP.js} +1 -1
  36. package/dist/client/assets/app-DoAgSphx.js +1 -0
  37. package/dist/client/assets/{browser-BanYmQkE.js → browser-OtgUKGth.js} +1 -1
  38. package/dist/client/assets/{chat-C6pq-bYQ.js → chat-B8_g1FhX.js} +2 -2
  39. package/dist/client/assets/composables-VZZHak9F.js +1 -0
  40. package/dist/client/assets/{fade-in-scale-up.cssr-B100njI2.js → fade-in-scale-up.cssr-BbYEGcju.js} +1 -1
  41. package/dist/client/assets/{index-DtDTIaVj.js → index-DY7SeRWD.js} +1 -1
  42. package/dist/client/assets/{jobs-DK_GVjqW.js → jobs-BRLhuQpK.js} +1 -1
  43. package/dist/client/assets/{light-CeMZM90j.js → light-8G-BZ0JM.js} +1 -1
  44. package/dist/client/assets/{light-BT2gqEar.js → light-B3QvGN97.js} +1 -1
  45. package/dist/client/assets/{light-Dav3NshO.js → light-B83Z4vA9.js} +1 -1
  46. package/dist/client/assets/{light-B8HxMQKs.js → light-Bmu6b0jg.js} +1 -1
  47. package/dist/client/assets/{light-BfPLur6t.js → light-BtLlDltU.js} +1 -1
  48. package/dist/client/assets/{light-CDN7aXQb.js → light-DDEUT7ek.js} +1 -1
  49. package/dist/client/assets/{pinia-DEKB7D30.js → pinia-F-uLzgMS.js} +1 -1
  50. package/dist/client/assets/{profiles-BSAOLUpt.js → profiles-DIJT1P0i.js} +1 -1
  51. package/dist/client/assets/{router-Zpu1Tghg.js → router-Drg4uUER.js} +2 -2
  52. package/dist/client/assets/{sessions-1rFjfO8M.js → sessions-BwtYroiN.js} +1 -1
  53. package/dist/client/assets/{skills-Bu5JdqX-.js → skills-BLhNwqgu.js} +1 -1
  54. package/dist/client/assets/use-compitable-BgSV79Sl.js +1 -0
  55. package/dist/client/assets/{use-message-CFWjMwGX.js → use-message-xhQoRXQV.js} +1 -1
  56. package/dist/client/assets/{useTheme-CHkzsMnk.js → useTheme-Dd5YNF4O.js} +1 -1
  57. package/dist/client/index.html +27 -27
  58. package/dist/server/index.js +2 -2
  59. package/dist/server/routes/hermes/config.js +15 -3
  60. package/dist/server/routes/hermes/filesystem.js +25 -5
  61. package/dist/server/routes/hermes/logs.js +1 -1
  62. package/dist/server/routes/hermes/profiles.js +1 -1
  63. package/dist/server/routes/hermes/sessions.js +1 -1
  64. package/dist/server/routes/hermes/weixin.js +2 -2
  65. package/dist/server/routes/webhook.js +1 -1
  66. package/dist/server/services/hermes/hermes-cli.d.ts +125 -0
  67. package/dist/server/services/hermes/hermes-cli.js +488 -0
  68. package/dist/server/services/hermes/hermes-profile.d.ts +22 -0
  69. package/dist/server/services/hermes/hermes-profile.js +60 -0
  70. package/dist/server/services/hermes/hermes.d.ts +40 -0
  71. package/dist/server/services/hermes/hermes.js +118 -0
  72. package/dist/server/shared/providers.js +2 -2
  73. package/package.json +4 -1
  74. package/dist/client/assets/ChannelsView-tUAkDoSF.js +0 -1
  75. package/dist/client/assets/JobsView-g3zcs8_m.js +0 -2
  76. package/dist/client/assets/ModelsView-C8rPRq6p.js +0 -1
  77. package/dist/client/assets/app-DVQEsGHs.js +0 -1
  78. package/dist/client/assets/composables-xsQwqT-T.js +0 -1
  79. package/dist/client/assets/use-compitable-Dl0AqAGv.js +0 -1
@@ -1 +1 @@
1
- import{o as e}from"./router-Zpu1Tghg.js";async function t(t,n){let r=new URLSearchParams;t&&r.set(`source`,t),n&&r.set(`limit`,String(n));let i=r.toString();return(await e(`/api/hermes/sessions${i?`?${i}`:``}`)).sessions}async function n(t){try{return(await e(`/api/hermes/sessions/${t}`)).session}catch{return null}}async function r(t){try{return await e(`/api/hermes/sessions/${t}`,{method:`DELETE`}),!0}catch{return!1}}async function i(t,n){try{return await e(`/api/hermes/sessions/${t}/rename`,{method:`POST`,body:JSON.stringify({title:n})}),!0}catch{return!1}}export{i,n,t as r,r as t};
1
+ import{o as e}from"./router-Drg4uUER.js";async function t(t,n){let r=new URLSearchParams;t&&r.set(`source`,t),n&&r.set(`limit`,String(n));let i=r.toString();return(await e(`/api/hermes/sessions${i?`?${i}`:``}`)).sessions}async function n(t){try{return(await e(`/api/hermes/sessions/${t}`)).session}catch{return null}}async function r(t){try{return await e(`/api/hermes/sessions/${t}`,{method:`DELETE`}),!0}catch{return!1}}async function i(t,n){try{return await e(`/api/hermes/sessions/${t}/rename`,{method:`POST`,body:JSON.stringify({title:n})}),!0}catch{return!1}}export{i,n,t as r,r as t};
@@ -1 +1 @@
1
- import{o as e}from"./router-Zpu1Tghg.js";async function t(){return(await e(`/api/hermes/skills`)).categories}async function n(t){return(await e(`/api/hermes/skills/${t}`)).content}async function r(t,n){return(await e(`/api/hermes/skills/${t}/${n}/files`)).files}async function i(){return e(`/api/hermes/memory`)}async function a(t,n){await e(`/api/hermes/memory`,{method:`POST`,body:JSON.stringify({section:t,content:n})})}async function o(t,n){await e(`/api/hermes/skills/toggle`,{method:`PUT`,body:JSON.stringify({name:t,enabled:n})})}export{a,t as i,n,o,r,i as t};
1
+ import{o as e}from"./router-Drg4uUER.js";async function t(){return(await e(`/api/hermes/skills`)).categories}async function n(t){return(await e(`/api/hermes/skills/${t}`)).content}async function r(t,n){return(await e(`/api/hermes/skills/${t}/${n}/files`)).files}async function i(){return e(`/api/hermes/memory`)}async function a(t,n){await e(`/api/hermes/memory`,{method:`POST`,body:JSON.stringify({section:t,content:n})})}async function o(t,n){await e(`/api/hermes/skills/toggle`,{method:`PUT`,body:JSON.stringify({name:t,enabled:n})})}export{a,t as i,n,o,r,i as t};
@@ -0,0 +1 @@
1
+ import{C as e}from"./router-Drg4uUER.js";function t(t,n){return e(()=>{for(let e of n)if(t[e]!==void 0)return t[e];return t[n[n.length-1]]})}export{t};
@@ -1 +1 @@
1
- import{F as e}from"./router-Zpu1Tghg.js";import{$ as t,Y as n}from"./browser-BanYmQkE.js";var r=t(`n-message-api`),i=t(`n-message-provider`);function a(){let t=e(r,null);return t===null&&n(`use-message`,"No outer <n-message-provider /> founded. See prerequisite in https://www.naiveui.com/en-US/os-theme/components/message for more details. If you want to use `useMessage` outside setup, please check https://www.naiveui.com/zh-CN/os-theme/components/message#Q-&-A."),t}export{r as n,i as r,a as t};
1
+ import{F as e}from"./router-Drg4uUER.js";import{$ as t,Y as n}from"./browser-OtgUKGth.js";var r=t(`n-message-api`),i=t(`n-message-provider`);function a(){let t=e(r,null);return t===null&&n(`use-message`,"No outer <n-message-provider /> founded. See prerequisite in https://www.naiveui.com/en-US/os-theme/components/message for more details. If you want to use `useMessage` outside setup, please check https://www.naiveui.com/zh-CN/os-theme/components/message#Q-&-A."),t}export{r as n,i as r,a as t};
@@ -1 +1 @@
1
- import{X as e,ct as t}from"./router-Zpu1Tghg.js";var n=`hermes_theme`,r=t(localStorage.getItem(n)||`system`),i=t(!1);function a(e){i.value=e,document.documentElement.classList.toggle(`dark`,e)}function o(e){return e===`system`?window.matchMedia(`(prefers-color-scheme: dark)`).matches:e===`dark`}a(o(r.value)),window.matchMedia(`(prefers-color-scheme: dark)`).addEventListener(`change`,()=>{r.value===`system`&&a(o(`system`))}),e(r,e=>{localStorage.setItem(n,e),a(o(e))});function s(){function e(e){r.value=e}function t(){r.value=i.value?`light`:`dark`}return{mode:r,isDark:i,setMode:e,toggleTheme:t}}export{s as t};
1
+ import{X as e,ct as t}from"./router-Drg4uUER.js";var n=`hermes_theme`,r=t(localStorage.getItem(n)||`system`),i=t(!1);function a(e){i.value=e,document.documentElement.classList.toggle(`dark`,e)}function o(e){return e===`system`?window.matchMedia(`(prefers-color-scheme: dark)`).matches:e===`dark`}a(o(r.value)),window.matchMedia(`(prefers-color-scheme: dark)`).addEventListener(`change`,()=>{r.value===`system`&&a(o(`system`))}),e(r,e=>{localStorage.setItem(n,e),a(o(e))});function s(){function e(e){r.value=e}function t(){r.value=i.value?`light`:`dark`}return{mode:r,isDark:i,setMode:e,toggleTheme:t}}export{s as t};
@@ -6,36 +6,36 @@
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>Hermes</title>
9
- <script type="module" crossorigin src="/assets/index-DtDTIaVj.js"></script>
10
- <link rel="modulepreload" crossorigin href="/assets/router-Zpu1Tghg.js">
11
- <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-B4hqCVU_.js">
12
- <link rel="modulepreload" crossorigin href="/assets/browser-BanYmQkE.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Scrollbar-DZGif2x4.js">
14
- <link rel="modulepreload" crossorigin href="/assets/use-compitable-Dl0AqAGv.js">
15
- <link rel="modulepreload" crossorigin href="/assets/Popover-BLBLYanQ.js">
16
- <link rel="modulepreload" crossorigin href="/assets/Close-ySsuLJTC.js">
17
- <link rel="modulepreload" crossorigin href="/assets/Button-BeWnBoDR.js">
18
- <link rel="modulepreload" crossorigin href="/assets/Suffix-CIX5CF-j.js">
19
- <link rel="modulepreload" crossorigin href="/assets/fade-in-scale-up.cssr-B100njI2.js">
20
- <link rel="modulepreload" crossorigin href="/assets/light-B8HxMQKs.js">
9
+ <script type="module" crossorigin src="/assets/index-DY7SeRWD.js"></script>
10
+ <link rel="modulepreload" crossorigin href="/assets/router-Drg4uUER.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-BPCSidQI.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/browser-OtgUKGth.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Scrollbar-v6Ok23iG.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/use-compitable-BgSV79Sl.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/Popover-CjCb_fJl.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/Close-CkAmZwHA.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/Button-Bls2FkVh.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/Suffix-iRME2DUp.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/fade-in-scale-up.cssr-BbYEGcju.js">
20
+ <link rel="modulepreload" crossorigin href="/assets/light-Bmu6b0jg.js">
21
21
  <link rel="modulepreload" crossorigin href="/assets/create-5zWq3BEB.js">
22
- <link rel="modulepreload" crossorigin href="/assets/Select-3KS3TLPL.js">
23
- <link rel="modulepreload" crossorigin href="/assets/Warning-BZfjWCrB.js">
24
- <link rel="modulepreload" crossorigin href="/assets/Modal-D_vF9k8c.js">
25
- <link rel="modulepreload" crossorigin href="/assets/pinia-DEKB7D30.js">
26
- <link rel="modulepreload" crossorigin href="/assets/profiles-BSAOLUpt.js">
22
+ <link rel="modulepreload" crossorigin href="/assets/Select-CDF2CEro.js">
23
+ <link rel="modulepreload" crossorigin href="/assets/Warning-C--exCXL.js">
24
+ <link rel="modulepreload" crossorigin href="/assets/Modal-apmj2qGK.js">
25
+ <link rel="modulepreload" crossorigin href="/assets/pinia-F-uLzgMS.js">
26
+ <link rel="modulepreload" crossorigin href="/assets/profiles-DIJT1P0i.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/omit-1BRB6K75.js">
28
- <link rel="modulepreload" crossorigin href="/assets/sessions-1rFjfO8M.js">
29
- <link rel="modulepreload" crossorigin href="/assets/app-DG_zFxqi.js">
30
- <link rel="modulepreload" crossorigin href="/assets/chat-C6pq-bYQ.js">
31
- <link rel="modulepreload" crossorigin href="/assets/light-BfPLur6t.js">
32
- <link rel="modulepreload" crossorigin href="/assets/light-CeMZM90j.js">
33
- <link rel="modulepreload" crossorigin href="/assets/use-message-CFWjMwGX.js">
34
- <link rel="modulepreload" crossorigin href="/assets/light-Dav3NshO.js">
28
+ <link rel="modulepreload" crossorigin href="/assets/sessions-BwtYroiN.js">
29
+ <link rel="modulepreload" crossorigin href="/assets/app-BEBfTlZP.js">
30
+ <link rel="modulepreload" crossorigin href="/assets/chat-B8_g1FhX.js">
31
+ <link rel="modulepreload" crossorigin href="/assets/light-BtLlDltU.js">
32
+ <link rel="modulepreload" crossorigin href="/assets/light-8G-BZ0JM.js">
33
+ <link rel="modulepreload" crossorigin href="/assets/use-message-xhQoRXQV.js">
34
+ <link rel="modulepreload" crossorigin href="/assets/light-B83Z4vA9.js">
35
35
  <link rel="modulepreload" crossorigin href="/assets/_common-DgdkN_d5.js">
36
- <link rel="modulepreload" crossorigin href="/assets/light-CDN7aXQb.js">
37
- <link rel="modulepreload" crossorigin href="/assets/light-BT2gqEar.js">
38
- <link rel="modulepreload" crossorigin href="/assets/useTheme-CHkzsMnk.js">
36
+ <link rel="modulepreload" crossorigin href="/assets/light-DDEUT7ek.js">
37
+ <link rel="modulepreload" crossorigin href="/assets/light-B3QvGN97.js">
38
+ <link rel="modulepreload" crossorigin href="/assets/useTheme-Dd5YNF4O.js">
39
39
  <link rel="modulepreload" crossorigin href="/assets/logo-Cd-t_oGE.js">
40
40
  <link rel="stylesheet" crossorigin href="/assets/index-JeutuTe0.css">
41
41
  </head>
@@ -49,7 +49,7 @@ const config_1 = require("./config");
49
49
  const hermes_1 = require("./routes/hermes");
50
50
  const upload_1 = require("./routes/upload");
51
51
  const webhook_1 = require("./routes/webhook");
52
- const hermesCli = __importStar(require("./services/hermes-cli"));
52
+ const hermesCli = __importStar(require("./services/hermes/hermes-cli"));
53
53
  const auth_1 = require("./services/auth");
54
54
  function getLocalVersion() {
55
55
  // production: dist/server → ../../package.json
@@ -241,7 +241,7 @@ function bindShutdown() {
241
241
  async function ensureApiServerConfig() {
242
242
  const { readFileSync, writeFileSync, existsSync, copyFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
243
243
  const yaml = (await Promise.resolve().then(() => __importStar(require('js-yaml')))).default;
244
- const { getActiveConfigPath } = await Promise.resolve().then(() => __importStar(require('./services/hermes-profile')));
244
+ const { getActiveConfigPath } = await Promise.resolve().then(() => __importStar(require('./services/hermes/hermes-profile')));
245
245
  const configPath = getActiveConfigPath();
246
246
  const defaults = {
247
247
  enabled: true,
@@ -8,8 +8,8 @@ const router_1 = __importDefault(require("@koa/router"));
8
8
  const promises_1 = require("fs/promises");
9
9
  const promises_2 = require("fs/promises");
10
10
  const js_yaml_1 = __importDefault(require("js-yaml"));
11
- const hermes_cli_1 = require("../../services/hermes-cli");
12
- const hermes_profile_1 = require("../../services/hermes-profile");
11
+ const hermes_cli_1 = require("../../services/hermes/hermes-cli");
12
+ const hermes_profile_1 = require("../../services/hermes/hermes-profile");
13
13
  // Platform sections that require gateway restart after config change
14
14
  const PLATFORM_SECTIONS = new Set([
15
15
  'telegram', 'discord', 'slack', 'whatsapp', 'matrix',
@@ -82,6 +82,18 @@ function getNested(obj, path) {
82
82
  }
83
83
  return cur;
84
84
  }
85
+ function deepMerge(target, source) {
86
+ for (const key of Object.keys(source)) {
87
+ if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) &&
88
+ target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {
89
+ target[key] = deepMerge(target[key], source[key]);
90
+ }
91
+ else {
92
+ target[key] = source[key];
93
+ }
94
+ }
95
+ return target;
96
+ }
85
97
  async function readEnvPlatforms() {
86
98
  try {
87
99
  const raw = await (0, promises_1.readFile)(envPath(), 'utf-8');
@@ -218,7 +230,7 @@ exports.configRoutes.put('/api/hermes/config', async (ctx) => {
218
230
  }
219
231
  try {
220
232
  const config = await readConfig();
221
- config[section] = { ...(config[section] || {}), ...values };
233
+ config[section] = deepMerge(config[section] || {}, values);
222
234
  await writeConfig(config);
223
235
  // Restart gateway for platform/channel config changes
224
236
  if (PLATFORM_SECTIONS.has(section)) {
@@ -41,8 +41,8 @@ const router_1 = __importDefault(require("@koa/router"));
41
41
  const promises_1 = require("fs/promises");
42
42
  const path_1 = require("path");
43
43
  const js_yaml_1 = __importDefault(require("js-yaml"));
44
- const hermes_profile_1 = require("../../services/hermes-profile");
45
- const hermesCli = __importStar(require("../../services/hermes-cli"));
44
+ const hermes_profile_1 = require("../../services/hermes/hermes-profile");
45
+ const hermesCli = __importStar(require("../../services/hermes/hermes-cli"));
46
46
  // --- Provider env var mapping (from hermes providers.py HERMES_OVERLAYS + config.py) ---
47
47
  // Maps provider key → { api_key_envs: all env var aliases for API key, base_url_env: env var for base URL }
48
48
  const PROVIDER_ENV_MAP = {
@@ -480,20 +480,40 @@ exports.fsRoutes.get('/api/hermes/available-models', async (ctx) => {
480
480
  for (const result of results) {
481
481
  if (result.status === 'fulfilled' && result.value.models.length > 0) {
482
482
  const { key, label, base_url, models } = result.value;
483
- groups.push({ provider: key, label, base_url, models });
483
+ groups.push({ provider: key, label, base_url, models: Array.from(new Set(models)) });
484
484
  }
485
485
  else if (result.status === 'rejected') {
486
486
  console.error(`[available-models] Failed: ${result.reason?.message || result.reason}`);
487
487
  }
488
488
  }
489
489
  }
490
+ // Deduplicate models within each group and merge groups with the same provider key
491
+ const dedupedGroups = [];
492
+ const seenProviders = new Map();
493
+ for (const g of groups) {
494
+ g.models = Array.from(new Set(g.models));
495
+ const existingIdx = seenProviders.get(g.provider);
496
+ if (existingIdx !== undefined) {
497
+ // Merge models into existing group
498
+ const existing = dedupedGroups[existingIdx];
499
+ const existingSet = new Set(existing.models);
500
+ for (const m of g.models) {
501
+ if (!existingSet.has(m))
502
+ existing.models.push(m);
503
+ }
504
+ }
505
+ else {
506
+ seenProviders.set(g.provider, dedupedGroups.length);
507
+ dedupedGroups.push(g);
508
+ }
509
+ }
490
510
  // Fallback: if no providers returned models, fall back to config.yaml parsing
491
- if (groups.length === 0) {
511
+ if (dedupedGroups.length === 0) {
492
512
  const fallback = buildModelGroups(config);
493
513
  ctx.body = fallback;
494
514
  return;
495
515
  }
496
- ctx.body = { default: currentDefault, groups };
516
+ ctx.body = { default: currentDefault, groups: dedupedGroups };
497
517
  }
498
518
  catch (err) {
499
519
  ctx.status = 500;
@@ -38,7 +38,7 @@ 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 hermesCli = __importStar(require("../../services/hermes-cli"));
41
+ const hermesCli = __importStar(require("../../services/hermes/hermes-cli"));
42
42
  exports.logRoutes = new router_1.default();
43
43
  // List available log files
44
44
  exports.logRoutes.get('/api/hermes/logs', async (ctx) => {
@@ -43,7 +43,7 @@ const promises_1 = require("fs/promises");
43
43
  const path_1 = require("path");
44
44
  const os_1 = require("os");
45
45
  const js_yaml_1 = __importDefault(require("js-yaml"));
46
- const hermesCli = __importStar(require("../../services/hermes-cli"));
46
+ const hermesCli = __importStar(require("../../services/hermes/hermes-cli"));
47
47
  const apiServerDefaults = {
48
48
  enabled: true,
49
49
  host: '127.0.0.1',
@@ -38,7 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.sessionRoutes = void 0;
40
40
  const router_1 = __importDefault(require("@koa/router"));
41
- const hermesCli = __importStar(require("../../services/hermes-cli"));
41
+ const hermesCli = __importStar(require("../../services/hermes/hermes-cli"));
42
42
  exports.sessionRoutes = new router_1.default();
43
43
  // List sessions from Hermes
44
44
  exports.sessionRoutes.get('/api/hermes/sessions', async (ctx) => {
@@ -8,8 +8,8 @@ const router_1 = __importDefault(require("@koa/router"));
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const promises_1 = require("fs/promises");
10
10
  const promises_2 = require("fs/promises");
11
- const hermes_cli_1 = require("../../services/hermes-cli");
12
- const hermes_profile_1 = require("../../services/hermes-profile");
11
+ const hermes_cli_1 = require("../../services/hermes/hermes-cli");
12
+ const hermes_profile_1 = require("../../services/hermes/hermes-profile");
13
13
  const envPath = () => (0, hermes_profile_1.getActiveEnvPath)();
14
14
  const ILINK_BASE = 'https://ilinkai.weixin.qq.com';
15
15
  exports.weixinRoutes = new router_1.default();
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.webhookRoutes = void 0;
7
7
  const router_1 = __importDefault(require("@koa/router"));
8
- const hermes_1 = require("../services/hermes");
8
+ const hermes_1 = require("../services/hermes/hermes");
9
9
  exports.webhookRoutes = new router_1.default();
10
10
  /**
11
11
  * POST /webhook — receive callbacks from Hermes Agent
@@ -0,0 +1,125 @@
1
+ export interface HermesSession {
2
+ id: string;
3
+ source: string;
4
+ user_id: string | null;
5
+ model: string;
6
+ title: string | null;
7
+ started_at: number;
8
+ ended_at: number | null;
9
+ end_reason: string | null;
10
+ message_count: number;
11
+ tool_call_count: number;
12
+ input_tokens: number;
13
+ output_tokens: number;
14
+ cache_read_tokens: number;
15
+ cache_write_tokens: number;
16
+ reasoning_tokens: number;
17
+ billing_provider: string | null;
18
+ estimated_cost_usd: number;
19
+ actual_cost_usd: number | null;
20
+ cost_status: string;
21
+ messages?: any[];
22
+ }
23
+ /**
24
+ * List sessions from Hermes CLI (without messages)
25
+ */
26
+ export declare function listSessions(source?: string, limit?: number): Promise<HermesSession[]>;
27
+ /**
28
+ * Get a single session with messages from Hermes CLI
29
+ */
30
+ export declare function getSession(id: string): Promise<HermesSession | null>;
31
+ /**
32
+ * Delete a session from Hermes CLI
33
+ */
34
+ export declare function deleteSession(id: string): Promise<boolean>;
35
+ /**
36
+ * Rename a session title via Hermes CLI
37
+ */
38
+ export declare function renameSession(id: string, title: string): Promise<boolean>;
39
+ export interface LogFileInfo {
40
+ name: string;
41
+ size: string;
42
+ modified: string;
43
+ }
44
+ /**
45
+ * Get Hermes version
46
+ */
47
+ export declare function getVersion(): Promise<string>;
48
+ /**
49
+ * Start Hermes gateway (uses launchd/systemd)
50
+ */
51
+ export declare function startGateway(): Promise<string>;
52
+ /**
53
+ * Start Hermes gateway in background (for WSL where launchd/systemd is unavailable)
54
+ * Uses "hermes gateway run" as a detached background process
55
+ */
56
+ export declare function startGatewayBackground(): Promise<number | null>;
57
+ /**
58
+ * Restart Hermes gateway
59
+ */
60
+ export declare function restartGateway(): Promise<string>;
61
+ /**
62
+ * Stop Hermes gateway
63
+ */
64
+ export declare function stopGateway(): Promise<string>;
65
+ /**
66
+ * List available log files
67
+ */
68
+ export declare function listLogFiles(): Promise<LogFileInfo[]>;
69
+ /**
70
+ * Read log lines
71
+ */
72
+ export declare function readLogs(logName?: string, lines?: number, level?: string, session?: string, since?: string): Promise<string>;
73
+ export interface HermesProfile {
74
+ name: string;
75
+ active: boolean;
76
+ model: string;
77
+ gateway: string;
78
+ alias: string;
79
+ }
80
+ export interface HermesProfileDetail {
81
+ name: string;
82
+ path: string;
83
+ model: string;
84
+ provider: string;
85
+ gateway: string;
86
+ skills: number;
87
+ hasEnv: boolean;
88
+ hasSoulMd: boolean;
89
+ }
90
+ /**
91
+ * List all profiles
92
+ */
93
+ export declare function listProfiles(): Promise<HermesProfile[]>;
94
+ /**
95
+ * Get profile details
96
+ */
97
+ export declare function getProfile(name: string): Promise<HermesProfileDetail>;
98
+ /**
99
+ * Create a new profile
100
+ */
101
+ export declare function createProfile(name: string, clone?: boolean): Promise<string>;
102
+ /**
103
+ * Delete a profile
104
+ */
105
+ export declare function deleteProfile(name: string): Promise<boolean>;
106
+ /**
107
+ * Rename a profile
108
+ */
109
+ export declare function renameProfile(oldName: string, newName: string): Promise<boolean>;
110
+ /**
111
+ * Switch active profile
112
+ */
113
+ export declare function useProfile(name: string): Promise<string>;
114
+ /**
115
+ * Export profile to archive
116
+ */
117
+ export declare function exportProfile(name: string, outputPath?: string): Promise<string>;
118
+ /**
119
+ * Run hermes setup --non-interactive --reset to generate default config for current profile
120
+ */
121
+ export declare function setupReset(): Promise<string>;
122
+ /**
123
+ * Import profile from archive
124
+ */
125
+ export declare function importProfile(archivePath: string, name?: string): Promise<string>;