@bitseek/hermes-webui 0.1.0-beta.0 → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/vendor/agent-frontend-shell/.bitseek-source.json +2 -2
- package/vendor/agent-frontend-shell/CHANGELOG.md +178 -1
- package/vendor/agent-frontend-shell/CONTRIBUTORS.md +5 -5
- package/vendor/agent-frontend-shell/api/agent_health.py +134 -0
- package/vendor/agent-frontend-shell/api/config.py +145 -104
- package/vendor/agent-frontend-shell/api/gateway_chat.py +56 -12
- package/vendor/agent-frontend-shell/api/helpers.py +4 -2
- package/vendor/agent-frontend-shell/api/models.py +202 -20
- package/vendor/agent-frontend-shell/api/paths.py +77 -0
- package/vendor/agent-frontend-shell/api/plugins.py +185 -0
- package/vendor/agent-frontend-shell/api/profiles.py +95 -16
- package/vendor/agent-frontend-shell/api/routes.py +831 -30
- package/vendor/agent-frontend-shell/api/run_journal.py +1 -0
- package/vendor/agent-frontend-shell/api/state_sync.py +5 -4
- package/vendor/agent-frontend-shell/api/streaming.py +211 -56
- package/vendor/agent-frontend-shell/api/todo_state.py +122 -0
- package/vendor/agent-frontend-shell/api/updates.py +30 -3
- package/vendor/agent-frontend-shell/api/upload.py +251 -18
- package/vendor/agent-frontend-shell/api/workspace.py +323 -65
- package/vendor/agent-frontend-shell/bitseek_docs/BitSeek_Claw_Operation_Manual_EN.docx +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/BitSeek_Claw_Operation_Manual_ZH.docx +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/00-Installation.md +174 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/01-Overview.md +128 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/02-Page-Operations.md +461 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/README.md +61 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/ai-colleagues.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/chat-area.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/kanban.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/main-page.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/memory-notes.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/memory-overview.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/memory-profile.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/memory-soul.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/memory.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/navigation-bar.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-appearance.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-conversation.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-overview.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-plugins.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-preferences.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-providers.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings-system.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/settings.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/sidebar.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/skills.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/tasks.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/en/images/workspace-panel.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/md_to_docx.py +351 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/00-/345/256/211/350/243/205/345/220/257/345/212/250.md +174 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/01-/346/225/264/344/275/223/346/246/202/350/247/210.md +128 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/02-/351/241/265/351/235/242/346/223/215/344/275/234.md +463 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/README.md +61 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/ai-colleagues.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/chat-area.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/kanban.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/main-page.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/memory-notes.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/memory-overview.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/memory-profile.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/memory-soul.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/memory.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/navigation-bar.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-appearance.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-conversation.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-overview.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-plugins.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-preferences.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-providers.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings-system.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/settings.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/sidebar.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/skills.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/tasks.png +0 -0
- package/vendor/agent-frontend-shell/bitseek_docs/zh/images/workspace-panel.png +0 -0
- package/vendor/agent-frontend-shell/build-release.sh +62 -0
- package/vendor/agent-frontend-shell/ctl.sh +1 -0
- package/vendor/agent-frontend-shell/docker-compose.local.yml +33 -0
- package/vendor/agent-frontend-shell/docker-compose.yml +8 -0
- package/vendor/agent-frontend-shell/docker_init.bash +1 -0
- package/vendor/agent-frontend-shell/docs/rfcs/hermes-run-adapter-contract.md +74 -15
- package/vendor/agent-frontend-shell/extensions/common/index.css +6 -0
- package/vendor/agent-frontend-shell/extensions/manifest.json +6 -0
- package/vendor/agent-frontend-shell/extensions/pages/ai-teammates/page.js +60 -14
- package/vendor/agent-frontend-shell/readme-simple.md +103 -0
- package/vendor/agent-frontend-shell/requirements.txt +5 -0
- package/vendor/agent-frontend-shell/server.py +7 -0
- package/vendor/agent-frontend-shell/static/boot.js +53 -1
- package/vendor/agent-frontend-shell/static/commands.js +20 -10
- package/vendor/agent-frontend-shell/static/i18n.js +1142 -1016
- package/vendor/agent-frontend-shell/static/index.html +13 -3
- package/vendor/agent-frontend-shell/static/messages.js +48 -3
- package/vendor/agent-frontend-shell/static/panels.js +199 -30
- package/vendor/agent-frontend-shell/static/sessions.js +249 -39
- package/vendor/agent-frontend-shell/static/style.css +46 -2
- package/vendor/agent-frontend-shell/static/ui.js +323 -79
- package/vendor/agent-frontend-shell/static/workspace.js +185 -7
- package/vendor/agent-frontend-shell/README-CUSTOM.md +0 -76
- package/vendor/agent-frontend-shell/docker-compose.custom.yml +0 -26
|
@@ -27,6 +27,8 @@ services:
|
|
|
27
27
|
- ${HERMES_HOME:-${HOME}/.hermes}:/home/hermeswebui/.hermes
|
|
28
28
|
# Your workspace directory shown on first launch (adapt if yours is different, the container will use the mounted /workspace)
|
|
29
29
|
- ${HERMES_WORKSPACE:-${HOME}/workspace}:/workspace
|
|
30
|
+
# Mount extensions directory for custom themes/scripts
|
|
31
|
+
- ./extensions:/app/extensions
|
|
30
32
|
environment:
|
|
31
33
|
# Set to your host user ID: run `id -u` and `id -g` to find them.
|
|
32
34
|
# On macOS, UIDs start at 501 (not 1000), so set UID and GID in a .env file:
|
|
@@ -44,6 +46,12 @@ services:
|
|
|
44
46
|
# - HERMES_WEBUI_DEFAULT_WORKSPACE=/workspace
|
|
45
47
|
# Optional: set a password for remote access
|
|
46
48
|
# - HERMES_WEBUI_PASSWORD=your-secret-password
|
|
49
|
+
# Extension configuration
|
|
50
|
+
- HERMES_WEBUI_EXTENSION_DIR=/app/extensions
|
|
51
|
+
- HERMES_WEBUI_EXTENSION_STYLESHEET_URLS=${HERMES_WEBUI_EXTENSION_STYLESHEET_URLS}
|
|
52
|
+
- HERMES_WEBUI_EXTENSION_SCRIPT_URLS=${HERMES_WEBUI_EXTENSION_SCRIPT_URLS}
|
|
53
|
+
- HERMES_WEBUI_BOT_NAME=${HERMES_WEBUI_BOT_NAME}
|
|
54
|
+
- HERMES_WEBUI_SKIP_ONBOARDING=${HERMES_WEBUI_SKIP_ONBOARDING}
|
|
47
55
|
#
|
|
48
56
|
# Bind-mount permission handling (fixes #1389, #1399):
|
|
49
57
|
# When you mount an EXISTING ~/.hermes directory (the common case),
|
|
@@ -956,28 +956,34 @@ Non-goals for Slice 4e:
|
|
|
956
956
|
|
|
957
957
|
#### Slice 4f: Supervised local runner client backend gate
|
|
958
958
|
|
|
959
|
-
Status as of 2026-05-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
959
|
+
Status as of 2026-05-31: shipped in v0.51.188 via #3073 / #3274. The client
|
|
960
|
+
transport is now implemented behind `HERMES_WEBUI_RUNNER_BASE_URL` and remains
|
|
961
|
+
default-off. With no endpoint configured, `runner-local` still returns the
|
|
962
|
+
bounded not-configured path and the live in-process `_run_agent_streaming` path
|
|
963
|
+
is unchanged. When configured, WebUI uses a JSON HTTP client boundary for start /
|
|
964
|
+
observe / status / controls and bridges observed runner events through the
|
|
965
|
+
existing SSE stream route rather than adding main-process runner-owned maps.
|
|
966
|
+
|
|
967
|
+
The release added two security hardening checks while absorbing #3073:
|
|
968
|
+
`HttpRunnerClient` rejects non-`http(s)` base URL schemes and uses an opener that
|
|
969
|
+
does not follow redirects, so a misconfigured or compromised runner cannot leak a
|
|
970
|
+
Bearer token to a redirected host. The release gate reported full pytest passing
|
|
971
|
+
and independent default-off/inert-path review.
|
|
972
|
+
|
|
967
973
|
This bridge is intentionally a WebUI consumer transport seam: the configured
|
|
968
974
|
runner must emit events that are already compatible with the browser SSE event
|
|
969
975
|
names/payloads, or a later runner-owned normalization layer must translate
|
|
970
976
|
Hermes runtime families such as `token.delta`, `tool.started`, and `done` before
|
|
971
977
|
they reach this route.
|
|
972
978
|
|
|
973
|
-
After the
|
|
974
|
-
`runner-local` the default. It is to define the first
|
|
975
|
-
runner
|
|
976
|
-
|
|
977
|
-
|
|
979
|
+
After the configured runner-client boundary ships, the next reviewable step is
|
|
980
|
+
not to make `runner-local` the default. It is to define the first supervised
|
|
981
|
+
runner process harness that can actually own `AIAgent` execution behind that
|
|
982
|
+
client boundary and prove restart/reattach with a real local runner, not just a
|
|
983
|
+
configured external endpoint or fake-runner fixture.
|
|
978
984
|
|
|
979
|
-
This slice
|
|
980
|
-
minimum runner client behavior so the implementation
|
|
985
|
+
This slice was the client-boundary implementation gate. The goal was to pin the
|
|
986
|
+
minimum runner client behavior so the implementation could not become a renamed
|
|
981
987
|
`STREAMS` / `CANCEL_FLAGS` / cached `AIAgent` surrogate inside `api/routes.py`.
|
|
982
988
|
|
|
983
989
|
Scope:
|
|
@@ -1027,6 +1033,59 @@ Non-goals for Slice 4f:
|
|
|
1027
1033
|
- no permanent WebUI-owned active-run discovery cache that duplicates runner or
|
|
1028
1034
|
future Hermes Runtime API responsibility.
|
|
1029
1035
|
|
|
1036
|
+
#### Slice 4g: Supervised local runner process harness gate
|
|
1037
|
+
|
|
1038
|
+
After #3073 / #3274, WebUI has an explicit configured-runner HTTP client and SSE
|
|
1039
|
+
consumer bridge, but it still does not ship the supervised runner process itself.
|
|
1040
|
+
The next gate should define the smallest local runner harness that can own
|
|
1041
|
+
`AIAgent` execution outside the main WebUI request process while being consumed
|
|
1042
|
+
through the already-shipped `runner-local` client boundary.
|
|
1043
|
+
|
|
1044
|
+
Scope:
|
|
1045
|
+
|
|
1046
|
+
- define the local runner process lifecycle: spawn/start, health check, run
|
|
1047
|
+
ownership, graceful shutdown, crash classification, and cleanup;
|
|
1048
|
+
- keep WebUI as a client of `HERMES_WEBUI_RUNNER_BASE_URL`, not the owner of
|
|
1049
|
+
process-local runner execution state;
|
|
1050
|
+
- persist run/session lookup, ordered events, terminal state, and active controls
|
|
1051
|
+
in runner-owned or journal-backed state that a restarted WebUI can discover;
|
|
1052
|
+
- carry explicit profile, workspace, attachments, provider/model, toolset,
|
|
1053
|
+
source, and metadata payloads into the runner without WebUI process-global
|
|
1054
|
+
environment mutation;
|
|
1055
|
+
- prove cancel as the first live control for active runner-owned runs, with
|
|
1056
|
+
approval, clarify, goal, and queue either mapped to explicit runner
|
|
1057
|
+
capabilities or returned as bounded unsupported/conflict `ControlResult`
|
|
1058
|
+
values.
|
|
1059
|
+
|
|
1060
|
+
Acceptance tests for Slice 4g:
|
|
1061
|
+
|
|
1062
|
+
1. **Process ownership moved.** A local runner process, not `hermes-webui`, owns
|
|
1063
|
+
`AIAgent` construction/reuse and active run execution for `runner-local` runs.
|
|
1064
|
+
2. **Restart/reattach with a real runner.** Start a non-trivial `runner-local`
|
|
1065
|
+
run, restart only `hermes-webui`, reload the session, rediscover the active or
|
|
1066
|
+
terminal runner-owned run, replay/catch up from cursor without duplicate
|
|
1067
|
+
transcript/tool/reasoning state, and preserve cancel if still active.
|
|
1068
|
+
3. **No runtime-surrogate globals in WebUI.** The main WebUI server still does not
|
|
1069
|
+
gain new module-level maps for runner-owned streams, cancel flags,
|
|
1070
|
+
approval/clarify callbacks, cached agents, child process run registries, goal
|
|
1071
|
+
state, or queue schedulers.
|
|
1072
|
+
4. **Default-off and reversible.** Unset `HERMES_WEBUI_RUNNER_BASE_URL` or switch
|
|
1073
|
+
the adapter mode back to legacy and the existing in-process path remains
|
|
1074
|
+
available without session or journal migration.
|
|
1075
|
+
5. **Runner health and failure are observable.** A missing, unhealthy, or crashed
|
|
1076
|
+
runner returns bounded diagnostics and terminal/interrupted state rather than
|
|
1077
|
+
silently falling back to WebUI-owned execution for a runner-selected run.
|
|
1078
|
+
|
|
1079
|
+
Non-goals for Slice 4g:
|
|
1080
|
+
|
|
1081
|
+
- no default-on runner mode;
|
|
1082
|
+
- no removal of `legacy-direct` or `legacy-journal`;
|
|
1083
|
+
- no server-side queue scheduler just for adapter symmetry;
|
|
1084
|
+
- no broad WebUI product-surface migration;
|
|
1085
|
+
- no claim that this is the canonical Hermes Agent Runtime API; if Hermes Agent
|
|
1086
|
+
later ships `/v1/runs`, this local runner remains a replaceable backend behind
|
|
1087
|
+
the same adapter/client boundary.
|
|
1088
|
+
|
|
1030
1089
|
## First Meaningful Success Criteria
|
|
1031
1090
|
|
|
1032
1091
|
The first meaningful milestones are deliberately split.
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
ai_teammates_create_title: 'Create AI Teammate',
|
|
27
27
|
ai_teammates_confirm_delete: 'Are you sure you want to delete this AI teammate?',
|
|
28
28
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
29
|
+
ai_teammates_cat_hr_ops: 'HR & Operations',
|
|
30
|
+
ai_teammates_cat_finance_tax: 'Finance & Tax',
|
|
31
|
+
ai_teammates_cat_biz_growth: 'Business Growth',
|
|
32
|
+
ai_teammates_cat_compliance: 'Policy & Compliance',
|
|
33
|
+
ai_teammates_cat_im: 'IM & Collaboration',
|
|
29
34
|
});
|
|
30
35
|
|
|
31
36
|
addTranslations('zh', {
|
|
@@ -43,6 +48,11 @@
|
|
|
43
48
|
ai_teammates_create_title: '创建 AI 同事',
|
|
44
49
|
ai_teammates_confirm_delete: '确定要删除这个 AI 同事吗?',
|
|
45
50
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
51
|
+
ai_teammates_cat_hr_ops: '人力资源与运营',
|
|
52
|
+
ai_teammates_cat_finance_tax: '财务与税务',
|
|
53
|
+
ai_teammates_cat_biz_growth: '业务增长',
|
|
54
|
+
ai_teammates_cat_compliance: '合规与政策',
|
|
55
|
+
ai_teammates_cat_im: '即时通讯',
|
|
46
56
|
});
|
|
47
57
|
|
|
48
58
|
addTranslations('ja', {
|
|
@@ -60,6 +70,11 @@
|
|
|
60
70
|
ai_teammates_create_title: 'AI同僚を作成',
|
|
61
71
|
ai_teammates_confirm_delete: 'このAI同僚を削除してもよろしいですか?',
|
|
62
72
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
73
|
+
ai_teammates_cat_hr_ops: '人事・オペレーション',
|
|
74
|
+
ai_teammates_cat_finance_tax: '財務・税務',
|
|
75
|
+
ai_teammates_cat_biz_growth: '事業成長',
|
|
76
|
+
ai_teammates_cat_compliance: 'コンプライアンス',
|
|
77
|
+
ai_teammates_cat_im: 'インスタントメッセージ',
|
|
63
78
|
});
|
|
64
79
|
|
|
65
80
|
addTranslations('ru', {
|
|
@@ -77,6 +92,11 @@
|
|
|
77
92
|
ai_teammates_create_title: 'Создать AI коллегу',
|
|
78
93
|
ai_teammates_confirm_delete: 'Вы уверены, что хотите удалить этого AI коллегу?',
|
|
79
94
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
95
|
+
ai_teammates_cat_hr_ops: 'HR и операции',
|
|
96
|
+
ai_teammates_cat_finance_tax: 'Финансы и налоги',
|
|
97
|
+
ai_teammates_cat_biz_growth: 'Рост бизнеса',
|
|
98
|
+
ai_teammates_cat_compliance: 'Политика и комплаенс',
|
|
99
|
+
ai_teammates_cat_im: 'Мгновенные сообщения',
|
|
80
100
|
});
|
|
81
101
|
|
|
82
102
|
addTranslations('es', {
|
|
@@ -94,6 +114,11 @@
|
|
|
94
114
|
ai_teammates_create_title: 'Crear colega AI',
|
|
95
115
|
ai_teammates_confirm_delete: '¿Estás seguro de que quieres eliminar este colega AI?',
|
|
96
116
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
117
|
+
ai_teammates_cat_hr_ops: 'RRHH y Operaciones',
|
|
118
|
+
ai_teammates_cat_finance_tax: 'Finanzas y Fiscalidad',
|
|
119
|
+
ai_teammates_cat_biz_growth: 'Crecimiento del Negocio',
|
|
120
|
+
ai_teammates_cat_compliance: 'Política y Cumplimiento',
|
|
121
|
+
ai_teammates_cat_im: 'Mensajería Instantánea',
|
|
97
122
|
});
|
|
98
123
|
|
|
99
124
|
addTranslations('de', {
|
|
@@ -111,6 +136,11 @@
|
|
|
111
136
|
ai_teammates_create_title: 'AI-Kollegen erstellen',
|
|
112
137
|
ai_teammates_confirm_delete: 'Sind Sie sicher, dass Sie diesen AI-Kollegen löschen möchten?',
|
|
113
138
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
139
|
+
ai_teammates_cat_hr_ops: 'Personal & Betrieb',
|
|
140
|
+
ai_teammates_cat_finance_tax: 'Finanzen & Steuern',
|
|
141
|
+
ai_teammates_cat_biz_growth: 'Unternehmenswachstum',
|
|
142
|
+
ai_teammates_cat_compliance: 'Richtlinien & Compliance',
|
|
143
|
+
ai_teammates_cat_im: 'Instant Messaging',
|
|
114
144
|
});
|
|
115
145
|
|
|
116
146
|
addTranslations('it', {
|
|
@@ -128,6 +158,11 @@
|
|
|
128
158
|
ai_teammates_create_title: 'Crea collega AI',
|
|
129
159
|
ai_teammates_confirm_delete: 'Sei sicuro di voler eliminare questo collega AI?',
|
|
130
160
|
ai_teammates_profile_prefix: 'bitseek_',
|
|
161
|
+
ai_teammates_cat_hr_ops: 'Risorse Umane & Operazioni',
|
|
162
|
+
ai_teammates_cat_finance_tax: 'Finanza & Fiscalità',
|
|
163
|
+
ai_teammates_cat_biz_growth: 'Crescita Aziendale',
|
|
164
|
+
ai_teammates_cat_compliance: 'Politica & Conformità',
|
|
165
|
+
ai_teammates_cat_im: 'Messaggistica',
|
|
131
166
|
});
|
|
132
167
|
}
|
|
133
168
|
|
|
@@ -155,9 +190,14 @@
|
|
|
155
190
|
}
|
|
156
191
|
|
|
157
192
|
/**
|
|
158
|
-
* Parse a bitseek profile name into { category, displayName, initials }
|
|
193
|
+
* Parse a bitseek profile name into { category, categoryDisplay, displayName, initials }
|
|
159
194
|
* Pattern: bitseek_[category]_[displayName]
|
|
160
|
-
* e.g. bitseek_collaboration_dingtalk → { category: '
|
|
195
|
+
* e.g. bitseek_collaboration_dingtalk → { category: 'ai_teammates_cat_im', displayName: 'Dingtalk' }
|
|
196
|
+
* Categories: hr/operations/support → HR & Operations
|
|
197
|
+
* collaboration → IM & Collaboration
|
|
198
|
+
* finance → Finance & Tax
|
|
199
|
+
* marketing/sales/product → Business Growth
|
|
200
|
+
* tech/data → Policy & Compliance
|
|
161
201
|
*/
|
|
162
202
|
function parseBitseekName(name) {
|
|
163
203
|
var prefix = 'bitseek_';
|
|
@@ -171,22 +211,25 @@
|
|
|
171
211
|
var rawCategory = parts[0];
|
|
172
212
|
var rawDisplayName = parts.slice(1).join('_');
|
|
173
213
|
|
|
174
|
-
// Map English category keys to
|
|
214
|
+
// Map English category keys to i18n category keys
|
|
175
215
|
var categoryMap = {
|
|
176
|
-
'
|
|
177
|
-
'
|
|
178
|
-
'
|
|
179
|
-
'
|
|
180
|
-
'
|
|
181
|
-
'
|
|
182
|
-
'
|
|
183
|
-
'
|
|
184
|
-
'
|
|
185
|
-
'data':
|
|
216
|
+
'hr': 'ai_teammates_cat_hr_ops',
|
|
217
|
+
'operations': 'ai_teammates_cat_hr_ops',
|
|
218
|
+
'support': 'ai_teammates_cat_hr_ops',
|
|
219
|
+
'im': 'ai_teammates_cat_im',
|
|
220
|
+
'finance': 'ai_teammates_cat_finance_tax',
|
|
221
|
+
'marketing': 'ai_teammates_cat_biz_growth',
|
|
222
|
+
'sales': 'ai_teammates_cat_biz_growth',
|
|
223
|
+
'product': 'ai_teammates_cat_biz_growth',
|
|
224
|
+
'tech': 'ai_teammates_cat_compliance',
|
|
225
|
+
'data': 'ai_teammates_cat_compliance',
|
|
186
226
|
};
|
|
187
227
|
|
|
188
228
|
var category = categoryMap[rawCategory] || rawCategory;
|
|
189
229
|
|
|
230
|
+
// Resolve i18n key to display name
|
|
231
|
+
var categoryDisplay = (category.indexOf('ai_teammates_cat_') === 0) ? t(category) : category;
|
|
232
|
+
|
|
190
233
|
// Convert raw display name to readable (snake_case → title case as fallback)
|
|
191
234
|
var displayName = rawDisplayName
|
|
192
235
|
.replace(/_/g, ' ')
|
|
@@ -197,6 +240,7 @@
|
|
|
197
240
|
|
|
198
241
|
return {
|
|
199
242
|
category: category,
|
|
243
|
+
categoryDisplay: categoryDisplay,
|
|
200
244
|
displayName: displayName,
|
|
201
245
|
initials: initials,
|
|
202
246
|
rawName: name,
|
|
@@ -265,6 +309,7 @@
|
|
|
265
309
|
return {
|
|
266
310
|
name: p.name,
|
|
267
311
|
category: parsed.category,
|
|
312
|
+
categoryDisplay: parsed.categoryDisplay,
|
|
268
313
|
displayName: parsed.displayName,
|
|
269
314
|
initials: getInitials(parsed.displayName),
|
|
270
315
|
description: p.description || '',
|
|
@@ -343,11 +388,12 @@
|
|
|
343
388
|
} else {
|
|
344
389
|
_categoryOrder.forEach(function(category) {
|
|
345
390
|
var roles = _groupedRoles[category];
|
|
391
|
+
var categoryLabel = (category.indexOf('ai_teammates_cat_') === 0) ? t(category) : category;
|
|
346
392
|
|
|
347
393
|
html += '<div class="at-category">';
|
|
348
394
|
html += ' <div class="at-category-header">';
|
|
349
395
|
html += ' <span class="at-category-dot"></span>';
|
|
350
|
-
html += ' <span class="at-category-name">' + esc(
|
|
396
|
+
html += ' <span class="at-category-name">' + esc(categoryLabel) + '</span>';
|
|
351
397
|
html += ' <span class="at-category-count">' + esc(t('ai_teammates_role_count', roles.length)) + '</span>';
|
|
352
398
|
html += ' </div>';
|
|
353
399
|
html += ' <div class="at-role-grid">';
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Hermes Web UI (Simplified) / 简化版说明
|
|
2
|
+
|
|
3
|
+
> **Repository / 仓库**: [https://github.com/adv-org/agent-frontend-shell](https://github.com/adv-org/agent-frontend-shell)
|
|
4
|
+
|
|
5
|
+
A lightweight web interface for Hermes Agent. No build step, no framework — just Python and vanilla JS.
|
|
6
|
+
|
|
7
|
+
Hermes Agent 的轻量级 Web 界面。无需构建步骤,无框架依赖 —— 仅使用 Python 和原生 JavaScript。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Start / 快速开始
|
|
12
|
+
|
|
13
|
+
### 1. Clone / 克隆
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/adv-org/agent-frontend-shell.git
|
|
17
|
+
cd agent-frontend-shell
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Local Run / 本地运行
|
|
21
|
+
|
|
22
|
+
**Requirements / 环境要求:** Python 3.12+
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Option 1: Direct Python / 方式一:直接运行 Python
|
|
26
|
+
python3 bootstrap.py
|
|
27
|
+
|
|
28
|
+
# Option 2: Shell wrapper (same as above) / 方式二:包装脚本(效果相同)
|
|
29
|
+
./start.sh
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Access at / 访问地址: **http://127.0.0.1:8787**
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Docker Run / Docker 运行
|
|
37
|
+
|
|
38
|
+
### Single container / 单容器模式
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Edit .env first / 先编辑 .env
|
|
42
|
+
cp .env.example .env
|
|
43
|
+
# Modify HERMES_HOME, HERMES_WORKSPACE, UID, GID as needed
|
|
44
|
+
# 按需修改 HERMES_HOME、HERMES_WORKSPACE、UID、GID
|
|
45
|
+
|
|
46
|
+
docker compose -f docker-compose.local.yml up -d --build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Two-container (WebUI + Agent) / 双容器模式
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
docker compose -f docker-compose.two-container.yml up -d
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Three-container (WebUI + Agent + DB) / 三容器模式
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
docker compose -f docker-compose.three-container.yml up -d
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Configuration / 配置
|
|
64
|
+
|
|
65
|
+
Key environment variables / 关键环境变量:
|
|
66
|
+
|
|
67
|
+
| Variable | Description / 说明 | Default / 默认值 |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `HERMES_WEBUI_PORT` | Server port / 服务端口 | `8787` |
|
|
70
|
+
| `HERMES_WEBUI_PASSWORD` | Access password / 访问密码 | (none) |
|
|
71
|
+
| `HERMES_HOME` | Hermes data dir / 数据目录 | `~/.hermes` |
|
|
72
|
+
| `HERMES_WORKSPACE` | Workspace path / 工作区路径 | `~/workspace` |
|
|
73
|
+
| `UID` / `GID` | User/Group ID for permissions / 权限映射 | `1000` |
|
|
74
|
+
|
|
75
|
+
Full config reference / 完整配置参考: [README.md](README.md) → Configuration section
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Common Commands / 常用命令
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Check health / 健康检查
|
|
83
|
+
curl http://127.0.0.1:8787/health
|
|
84
|
+
|
|
85
|
+
# View logs / 查看日志
|
|
86
|
+
docker logs -f hermes-webui-custom
|
|
87
|
+
|
|
88
|
+
# Stop / 停止
|
|
89
|
+
docker compose -f docker-compose.local.yml down
|
|
90
|
+
|
|
91
|
+
# Rebuild / 重新构建
|
|
92
|
+
docker compose -f docker-compose.local.yml up -d --build
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Architecture / 架构
|
|
98
|
+
|
|
99
|
+
- **Backend / 后端**: Python (Flask-like), file-based state
|
|
100
|
+
- **Frontend / 前端**: Vanilla JS, no bundler
|
|
101
|
+
- **State / 状态**: Local filesystem (`~/.hermes`)
|
|
102
|
+
|
|
103
|
+
For full details / 完整详情: [ARCHITECTURE.md](ARCHITECTURE.md) | [TESTING.md](TESTING.md)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Hermes Web UI -- minimal Python dependencies
|
|
2
2
|
# The server uses PyYAML plus cryptography for optional local passkey/WebAuthn support.
|
|
3
3
|
# All heavy ML/agent deps live in the Hermes agent venv.
|
|
4
|
+
#
|
|
5
|
+
# OPTIONAL: the Edge TTS speech engine (Settings -> Voice -> TTS Engine -> "Edge TTS")
|
|
6
|
+
# needs `edge-tts`. It is intentionally NOT a hard dependency — the /api/tts
|
|
7
|
+
# endpoint returns 503 with an install hint when it's absent. Install it only if
|
|
8
|
+
# you want server-side Microsoft neural voices: pip install edge-tts
|
|
4
9
|
pyyaml>=6.0
|
|
5
10
|
cryptography>=42.0
|
|
@@ -581,6 +581,13 @@ def main() -> None:
|
|
|
581
581
|
except Exception as e:
|
|
582
582
|
print(f'[!!] WARNING: Gateway watcher failed to start: {e}', flush=True)
|
|
583
583
|
|
|
584
|
+
# Load WebUI dashboard plugins
|
|
585
|
+
try:
|
|
586
|
+
from api.plugins import load_plugins
|
|
587
|
+
load_plugins()
|
|
588
|
+
except Exception as e:
|
|
589
|
+
print(f'[!!] WARNING: Plugin loading failed: {e}', flush=True)
|
|
590
|
+
|
|
584
591
|
httpd = QuietHTTPServer((HOST, PORT), Handler)
|
|
585
592
|
|
|
586
593
|
# ── TLS/HTTPS setup (optional) ─────────────────────────────────────────
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Early boot initialization that must run before any other code.
|
|
2
|
+
// These run during script evaluation to handle server-stopped state
|
|
3
|
+
// and cross-tab shutdown broadcasts as early as possible.
|
|
1
4
|
(function(){
|
|
2
5
|
// Clear stale stop-server flag on successful page load (server is reachable)
|
|
3
6
|
try{localStorage.removeItem('hermes-webui-server-stopped');}catch(_){}
|
|
@@ -889,7 +892,56 @@ window._micPendingSend=window._micPendingSend||false;
|
|
|
889
892
|
.trim();
|
|
890
893
|
}
|
|
891
894
|
if(!clean){ _startListening(); return; }
|
|
892
|
-
|
|
895
|
+
const engine=localStorage.getItem("hermes-tts-engine")||"browser";
|
|
896
|
+
if(engine==="edge"){
|
|
897
|
+
const voice=localStorage.getItem("hermes-tts-voice")||"zh-CN-XiaoxiaoNeural";
|
|
898
|
+
const savedRate=parseFloat(localStorage.getItem("hermes-tts-rate"));
|
|
899
|
+
const savedPitch=parseFloat(localStorage.getItem("hermes-tts-pitch"));
|
|
900
|
+
let rate='', pitch='';
|
|
901
|
+
if(!isNaN(savedRate)){const pct=Math.round((savedRate-1)*100);const sign=pct>=0?'+':'';rate=sign+pct+'%';}
|
|
902
|
+
if(!isNaN(savedPitch)){const hz=Math.round((savedPitch-1)*50);const sign=hz>=0?'+':'';pitch=sign+hz+'Hz';}
|
|
903
|
+
_ttsSpeaking=true;
|
|
904
|
+
fetch(new URL('api/tts', document.baseURI || location.href).href, {
|
|
905
|
+
method: 'POST',
|
|
906
|
+
headers: {'Content-Type': 'application/json'},
|
|
907
|
+
body: JSON.stringify({text: clean, voice, rate, pitch})
|
|
908
|
+
})
|
|
909
|
+
.then(r => {
|
|
910
|
+
if(!r.ok) throw new Error('TTS request failed: ' + r.status);
|
|
911
|
+
return r.blob();
|
|
912
|
+
})
|
|
913
|
+
.then(blob => {
|
|
914
|
+
const url = URL.createObjectURL(blob);
|
|
915
|
+
const audio = new Audio(url);
|
|
916
|
+
// Register with the shared handle (declared in ui.js, same global scope;
|
|
917
|
+
// both scripts are fully evaluated before any voice interaction) so
|
|
918
|
+
// stopTTS() — called from _deactivate() — can actually pause hands-free
|
|
919
|
+
// Edge playback. Without this the audio is local here and unstoppable.
|
|
920
|
+
_playingEdgeAudio=audio;
|
|
921
|
+
audio.onended = () => {
|
|
922
|
+
_ttsSpeaking=false;
|
|
923
|
+
if(_playingEdgeAudio===audio) _playingEdgeAudio=null;
|
|
924
|
+
URL.revokeObjectURL(url);
|
|
925
|
+
if(_voiceModeActive) setTimeout(()=>_startListening(),500);
|
|
926
|
+
};
|
|
927
|
+
audio.onerror = () => {
|
|
928
|
+
_ttsSpeaking=false;
|
|
929
|
+
if(_playingEdgeAudio===audio) _playingEdgeAudio=null;
|
|
930
|
+
URL.revokeObjectURL(url);
|
|
931
|
+
if(_voiceModeActive) setTimeout(()=>_startListening(),1000);
|
|
932
|
+
};
|
|
933
|
+
audio.play().catch(e => {
|
|
934
|
+
_ttsSpeaking=false;
|
|
935
|
+
if(_playingEdgeAudio===audio) _playingEdgeAudio=null;
|
|
936
|
+
if(_voiceModeActive) setTimeout(()=>_startListening(),1000);
|
|
937
|
+
});
|
|
938
|
+
})
|
|
939
|
+
.catch(() => {
|
|
940
|
+
_ttsSpeaking=false;
|
|
941
|
+
if(_voiceModeActive) setTimeout(()=>_startListening(),1000);
|
|
942
|
+
});
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
893
945
|
const utter=new SpeechSynthesisUtterance(clean);
|
|
894
946
|
|
|
895
947
|
// Apply saved voice preferences
|
|
@@ -322,6 +322,24 @@ function cmdClear(){
|
|
|
322
322
|
showToast(t('conversation_cleared'));
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
// Find the best matching model <option> for a slash-command query.
|
|
326
|
+
// Returns an exact id/label match if present, otherwise the shortest option
|
|
327
|
+
// whose value or label contains the query. Preferring the shortest match keeps
|
|
328
|
+
// a specific query like "mimo-v2.5" from being shadowed by a longer variant
|
|
329
|
+
// such as "mimo-v2.5-pro". See issue #3368.
|
|
330
|
+
function _bestModelMatch(options,query){
|
|
331
|
+
let best=null;
|
|
332
|
+
for(const opt of options){
|
|
333
|
+
const value=opt.value.toLowerCase();
|
|
334
|
+
const text=opt.textContent.toLowerCase();
|
|
335
|
+
if(value===query||text===query) return opt.value;
|
|
336
|
+
if(value.includes(query)||text.includes(query)){
|
|
337
|
+
if(best===null||opt.value.length<best.length) best=opt.value;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return best;
|
|
341
|
+
}
|
|
342
|
+
|
|
325
343
|
async function cmdModel(args){
|
|
326
344
|
if(!args){showToast(t('model_usage'));return;}
|
|
327
345
|
const sel=$('modelSelect');
|
|
@@ -348,21 +366,13 @@ async function cmdModel(args){
|
|
|
348
366
|
let match=(typeof _findModelInDropdown==='function')?_findModelInDropdown(q,sel,preferred):null;
|
|
349
367
|
// Fallback: fuzzy match across all options
|
|
350
368
|
if(!match){
|
|
351
|
-
|
|
352
|
-
if(opt.value.toLowerCase().includes(q)||opt.textContent.toLowerCase().includes(q)){
|
|
353
|
-
match=opt.value;break;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
369
|
+
match=_bestModelMatch(sel.options,q);
|
|
356
370
|
}
|
|
357
371
|
// Fallback: if q has provider/ prefix (e.g. "deepseek/deepseek-v4-flash"),
|
|
358
372
|
// try the bare model name (which is how options appear for the active provider)
|
|
359
373
|
if(!match && q.includes('/')){
|
|
360
374
|
const bare=q.slice(q.lastIndexOf('/')+1);
|
|
361
|
-
|
|
362
|
-
if(opt.value.toLowerCase().includes(bare)||opt.textContent.toLowerCase().includes(bare)){
|
|
363
|
-
match=opt.value;break;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
375
|
+
match=_bestModelMatch(sel.options,bare);
|
|
366
376
|
// Cross-provider fallback: if still no match, the model is from a
|
|
367
377
|
// different provider not in the dropdown. Call /api/session/update directly.
|
|
368
378
|
if(!match && S&&S.session&&S.session.session_id){
|