9d1da73434d73f90f0658337b22643d244b4174c
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2ae7e7ad1b |
修复: Profile clone 时智能清理独占平台凭据 + 平台设置独占警告 (#283)
* 修复: profile clone 时智能清理独占平台凭据,避免 gateway 健康检查超时 # 问题 `hermes profile create <name> --clone` 完整复制 .env + config.yaml(含独占型平台凭据 如 WEIXIN_TOKEN / TELEGRAM_BOT_TOKEN 等),导致多个 profile 共享同一身份 token。 hermes-agent 在 platform adapter 初始化或 scoped lock 获取阶段失败,gateway 健康检查 持续 15s 超时,前端报 'API Error 500: Gateway health check timed out'。 # 修复 在 web-ui 后端 clone 完成后自动: 1. 从 <profile>/.env 删除匹配独占平台的环境变量(写 .env.bak.* 备份) 2. 在 <profile>/config.yaml 中把 platforms.<exclusive>.enabled 置为 false 3. 清理节点直挂 + extra 子节点下的敏感字段(token / app_secret / account_id 等) 前端 toast 提示被剥离的凭据、被禁用的平台、被剥离的 config 字段,便于用户后续手动 重新填入新身份再启用。 # EXCLUSIVE_PLATFORMS 列表来源 精确对齐 hermes-agent gateway/platforms/*.py 中调用 _acquire_platform_lock 的 7 个 adapter: telegram, discord, slack, whatsapp, signal, weixin, feishu。 未来上游加新独占平台时用 `grep -l _acquire_platform_lock gateway/platforms/*.py` 验证。 # 测试 新增 tests/server/profile-credentials.test.ts(12 用例全过),覆盖: - isExclusivePlatformKey 命中/未命中边界 - env 文件剥离 + 备份 - config.yaml 平台禁用 + 节点凭据清理 - 已 disabled 平台仍清理残留凭据(防止后续 re-enable 复用旧身份) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(平台设置): 独占平台显示 token 隔离警告 在 PlatformSettings 中为使用 token 互斥锁的 6 个平台 (telegram, discord, slack, whatsapp, feishu, weixin) 添加视觉警告,提示用户每个 profile 必须使用不同的身份 token,避免与其他 profile 冲突。 # 背景 hermes-agent 的 acquire_scoped_lock 是 token-level(不是 platform-level),所以 设计上支持多 profile 各自配不同身份的同一平台(如 default 用个人微信、staging 用公司微信)。但用户从 UI 配置时容易误填同一 token,导致 gateway 启动失败。 # 实现 - PlatformCard 新增 exclusive 可选 prop,开启时 body 顶部用 NAlert (warning) 展示提示 - PlatformSettings 在 6 个独占平台数组项标记 exclusive: true 并传给 PlatformCard - 8 个 i18n locale 新增 platform.exclusiveTokenWarning 翻译 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
610f3eb9d0 |
feat(copilot): integrate GitHub Copilot provider with dynamic model list / 集成 GitHub Copilot provider 与动态模型列表 (#239)
* feat(copilot): integrate GitHub Copilot provider with dynamic model list 集成 GitHub Copilot provider 与动态模型列表 EN: - New copilot-models service: fetch live model list from GitHub /models API - Filter noise IDs (accounts/, text-embedding, rerank prefixes) - Pass through preview/disabled metadata to frontend - Cache isolated per OAuth token (FNV-1a hash key) to prevent cross-account leak - Multi-source token resolution: env > apps.json > gh CLI - ModelSelector renders PREVIEW (orange) and UNAVAILABLE (gray, non-selectable) badges with tooltips - ProviderFormModal exposes Copilot OAuth login entry - New CopilotLoginModal component: guides gh auth login device flow - ProviderCard hides delete button for OAuth-only builtin providers (copilot/codex/nous) since their credentials live outside auth.json ZH: - 新增 copilot-models 服务:从 GitHub /models live API 拉取模型列表 - 噪音 ID 过滤(accounts/、text-embedding、rerank 前缀) - preview/disabled 元数据透传至前端 - 缓存按 OAuth token 隔离(FNV-1a hash key),避免切换 profile 串账号 - 多源 token 解析优先级:env > apps.json > gh CLI - ModelSelector 渲染 PREVIEW(橙色)/ UNAVAILABLE(灰色、不可选)badge,附 tooltip - ProviderFormModal 提供 Copilot OAuth 登录入口 - 新增 CopilotLoginModal 组件:引导 gh auth login 设备流程 - ProviderCard 对 OAuth-only builtin(copilot/codex/nous)隐藏删除按钮 其凭证不在 auth.json,删除按钮原本无效 Tests / 测试: new copilot-models suite (cache isolation, noise filter, preview/disabled passthrough) + copilot-login-modal — 24/24 passed. Pre-existing sessions-db-lineage failure on upstream/main is unrelated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(copilot): switch to explicit opt-in per maintainer feedback 回应 PR #239 review:上一版会自动把系统级 GitHub OAuth 凭证(VS Code Copilot 插件、gh CLI 登录态)当作 hermes provider 拉到列表里,对未在 hermes 中注册过 Copilot 的用户造成困扰。本次改为显式 opt-in:用户必须通过 Add Provider 主动添加, 删除时按 token 来源决定是否清 ~/.hermes/.env,并避免误清理 VS Code / gh CLI 用户的 全局凭证。 Address PR #239 review feedback. Previously Copilot would silently appear in the provider list whenever the host had any GitHub OAuth token (VS Code plugin, gh CLI login). This caused confusion for users who never explicitly registered Copilot in hermes. Now Copilot requires explicit opt-in via Add Provider; on delete we only clear ~/.hermes/.env when the token actually originated there, leaving VS Code / gh CLI credentials untouched. What changed - 新增 ~/.hermes-web-ui/config.json 的 copilotEnabled flag 控制可见性 - 即便能解析到 token,未启用时也不在列表中显示 - resolveCopilotOAuthTokenWithSource 区分 token 来源(env / gh-cli / apps-json) - ProviderFormModal 增加 GitHub Copilot 入口;无 token 时进 device flow modal - CopilotLoginModal 重写为 in-app device flow 状态机(不再要求用户在终端跑 gh) - 删除 Copilot 时仅 source='env' 才清 ~/.hermes/.env,并自动 fallback 默认模型 - 老用户升级兼容:若 default 仍指向已禁用的 copilot,后端清空 default 让前端兜底 API - POST /api/hermes/copilot-auth/check-token - POST /api/hermes/copilot-auth/enable - POST /api/hermes/copilot-auth/disable - POST /api/hermes/copilot-auth/start (device flow) - POST /api/hermes/copilot-auth/poll (device flow) Tests - tests/server/copilot-auth-controller.test.ts (11 cases) - tests/server/copilot-device-flow.test.ts (12 cases) - tests/client/copilot-login-modal.test.ts 重写覆盖状态机 Follow-ups (留作后续 PR) - device flow session 未绑定 profile,登录中切 profile 会写到错的 .env - copilot device-code 接口的 expires_in 字段未使用,硬编码 15 分钟超时 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
97fbfac2d6 |
fix(chat): 检测并提示被静默吞掉的 run 错误 (#206)
当上游 hermes-agent 的 agent 层捕获了 LLM 错误(如无效 API key、 模型不被 provider 支持)后,gateway 仍会发送 run.completed 事件, 但 output 为空、usage 为零。前端因此误认为成功,UI 完全无任何 错误提示。 本次修复在 chat store 的 SSE 处理中加入两个 per-run 标志: - runProducedAssistantText:仅 reasoning/thinking/message.delta 置位 - runHadToolActivity:仅 tool.started/tool.completed 置位 run.completed 时: 1. 兜底渲染:若本次 run 没有 assistant 文本但 evt.output 非空, 将 output 作为 assistant 消息落盘(兼容某些只在 completed 事件给出最终文本的 provider)。 2. 静默错误检测:若三者均不成立(无 assistant 文本 + 无 tool 活动 + output 空),追加一条 system 消息提示用户检查 hermes-agent 日志。usage=0 不再作为强条件,避免某些 provider 或本地模型不返回 usage 时的误报。 api/hermes/chat.ts 给 RunEvent 增加 output 字段类型。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
4bdcaa6258 |
feat: add Alibaba Coding Plan provider with .env base_url support (#200)
* feat(providers): 新增 Alibaba Cloud (Coding Plan) 内置 provider 对齐 hermes-agent 上游 PR #15045(commit 727d1088),新增 alibaba-coding-plan provider,鉴权使用 ALIBABA_CODING_PLAN_API_KEY 环境变量,base_url 可通过 ALIBABA_CODING_PLAN_BASE_URL 覆盖。 默认 base_url 使用国际版端点 coding-intl.dashscope.aliyuncs.com/v1, 与上游 auth.py:255 保持一致。中国大陆 DashScope 账号 (dashscope.aliyun.com 颁发的 sk-sp-* 密钥)需要通过 ALIBABA_CODING_PLAN_BASE_URL=https://coding.dashscope.aliyuncs.com/v1 (不带 -intl)覆盖,因为 -intl 端点对该类密钥返回 HTTP 401。 该差异在源码注释中已说明。 模型列表覆盖 8 个 Coding Plan 支持的模型:qwen3.5-plus、 qwen3-max-2026-01-23、qwen3-coder-next/plus、glm-5、glm-4.7、 kimi-k2.5、MiniMax-M2.5(基于实测可用列表)。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(providers): Alibaba Coding Plan 添加国内/国际区域切换 在 ProviderFormModal 中针对 alibaba-coding-plan preset 增加一个 "区域"字段,可在国际版(coding-intl)与中国大陆(coding,无 -intl) 两个端点之间切换,切换时自动更新 base_url。 默认选中国际版以对齐上游 hermes-agent 默认值。中国大陆 DashScope 账号(dashscope.aliyun.com 颁发的 sk-sp-* 密钥)只需在表单里点一下 "中国大陆"即可,无需手动改 base_url 或设环境变量。 8 个 locale(zh/en/de/es/fr/ja/ko/pt)都补全了 region/regionIntl/ regionCn 三个 i18n key。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(providers): builtin provider 列表优先读取 base_url env override 之前服务端 getAvailable 在渲染 builtin provider 列表时直接 用 PROVIDER_PRESETS 里的默认 base_url,忽略了用户保存到 .env 的 base_url override。这导致用户在 Alibaba Coding Plan 选了"中国 大陆"保存后,列表里仍然显示国际版 URL。 修复:envMapping.base_url_env 如果存在且 .env 中有值,优先 使用该值;否则 fallback 到 preset 默认。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
369001824e |
feat(chat): 支持思考块实时流式与历史展示 (#191)
* feat: 添加文件下载功能,支持多 Terminal Backend 实现基于 FileProvider 抽象的文件下载能力,支持 local、Docker、SSH、 Singularity 四种 backend。 主要变更: - 新增 FileProvider 接口及四种后端实现(含 SSH 命令注入防护) - 新增 GET /api/hermes/download 下载路由(含 MIME 类型检测) - 前端 Markdown 文件链接拦截下载 + 附件下载按钮 - 中英文 i18n 翻译 - 更新 README、CLAUDE.md 和设计文档 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: 添加文件浏览器与下载功能,支持目录浏览、文件编辑、预览和上传 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * build: add prepare script so 'npm install git+url' auto-builds dist/ Allows installing this package directly from git without a pre-built dist/. When cloned via npm, prepare runs 'npm run build' if dist/ is missing, producing the artifacts declared in the files[] field before packing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use clipboard fallback for non-secure HTTP contexts navigator.clipboard is undefined on HTTP intranet deployments (only available in secure contexts). The previous synchronous calls threw silently and the success toast still fired, making 'copy' actions appear broken. - Add packages/client/src/utils/clipboard.ts with execCommand fallback via a hidden textarea - Use the helper in FileContextMenu (copy file path), CodexLoginModal (copy user code), NousLoginModal (copy user code), ChatPanel (copy session id) - Each call now awaits the result and shows success/failure based on the actual outcome Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * i18n: backfill files/download translations for de, es, fr, ja, ko, pt Add nav.files, files.* (39 keys), and download.* (9 keys) so the file browser UI is fully localized in these six locales instead of falling back to English. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(files): close preview when navigating or affected file changes Opening a preview and then navigating directories, deleting the previewed file, or renaming it left the preview pane stuck on stale content because previewFile was never cleared. - stores/hermes/files.ts: - fetchEntries clears previewFile on path change (in-place refresh keeps the preview). - deleteEntry / renameEntry clear preview/editor state when the affected entry matches the previewed/edited file or its parent. - Add isAffected(target, changed, isDir) helper. - components/hermes/files/FilePreview.vue: replace the misleading common.cancel close button with a dedicated files.closePreview key plus an X icon and quaternary style. - i18n: add files.closePreview to all 8 locales. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: 清理已完成功能的计划与设计文档 文件浏览器与文件下载功能均已被上游合并,对应的开发计划 与设计稿不再需要在 fork 中保留: - plans/2025-07-20-file-browser.md - plans/2026-04-20-file-download.md - specs/2025-07-20-file-browser-design.md - specs/2026-04-20-file-download-design.md 清理后本 fork 与 upstream/main 代码层面完全对齐。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: 添加 thinking 块分离与折叠展示设计稿(#164) 针对上游 issue #164,设计 assistant 消息中 <think>/<thinking>/<reasoning> 标签的识别、分离与可折叠展示方案。 关键决策(经 rubber-duck 审查修订): - 不修改 Message.content 与持久化字段,确保 localStorage 向前兼容 - 耗时摘要改为纯运行时派生(store 内 Map),避免刷新/重连丢失 - 首版即实现代码块保护,避免误识别 - 流结束时未闭合标签降级为正文,防止吞答案 - 解析 computed 与 duration interval 分离,规避性能风险 - 解析器放置 packages/client/src/utils/ 避免反向依赖 - 显式不支持同名嵌套(罕见场景文档化) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: 添加 thinking 块分离与折叠实施计划(#164) 12 Task TDD 计划: - Task 1-7:utils/thinking-parser.ts 纯函数模块 + 单元测试 - Task 8-9:chat store thinkingObservation Map 接入 SSE - Task 10:8 语言 i18n 新增 6 条 key - Task 11:MessageItem.vue 渲染折叠 UI + SCSS - Task 12:构建/测试/手动验证/推送 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(thinking-parser): 首个闭合 <think> 标签拆分 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(thinking-parser): 覆盖多段/变体标签/大小写/空输入 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(thinking-parser): 流式 pending 与终止态降级 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(thinking-parser): 代码块保护避免误识别伪标签 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(thinking-parser): 同名嵌套与 chunk 边界行为 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(thinking-parser): countThinkingChars 辅助函数 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(thinking-parser): detectThinkingBoundary 边界检测 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(chat-store): 新增 thinkingObservation 运行时 Map Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(chat-store): message.delta 写入 thinking 边界 + switchSession 清理 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * i18n: 新增 thinking 块 6 条 key(8 语言) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(chat): MessageItem 渲染 thinking 折叠区 - 复用 tool-line 风格 chevron - 两条响应链:parse computed + duration interval - 流式+pending 强制展开 - show_reasoning 控制默认态 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(chat): 支持思考块实时流式与历史展示 - 扩展 Message 接口增加 reasoning 字段,mapHermesMessages 从 HermesMessage.reasoning 透传历史会话的思考内容。 - RunEvent 类型新增 text 字段,chat store 处理三个新 SSE 事件: reasoning.delta / thinking.delta / reasoning.available。 - 思考时长观察:仅在 reasoning.delta 累积时记录起始时间戳, reasoning.available 时记录结束时间戳;无实时 delta 时不显示时长。 - MessageItem 采用双源渲染(reasoning 字段优先,<think> 标签作 fallback),duration > 0 才展示耗时。 - 新增 3 条单测覆盖三个 SSE 事件;测试 32/32 通过。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(chat): reasoning 块不再短暂展示正文 根因:上游 hermes-agent run_agent.py:11275 在每次模型响应结束时用 assistant content[:500] 作为 reasoning.available 的 preview 负载, 致使 Web UI 把正文写入 last.reasoning,思考块短暂显示正文直到会话 轮询/刷新从 session DB 读回正确的 reasoning 字段。 修复: - reasoning.available 事件不再写入 last.reasoning,仅用于标记计时 结束(noteReasoningEnd);真实推理由 reasoning.delta 或会话 DB 提供 - 新增 scrubBuggyReasoningInCache:hydration 时治愈 localStorage 里 已被污染的 assistant 消息(reasoning == content 或前缀时丢弃) - 两个 cache 加载入口(loadSessions / switchSession)均接入 scrubber 测试:新增 4 条单测,全套 280/280 通过。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
0cc31ee999 |
feat: add file browser and file download with multi-backend support (#142)
* feat: add file browser and file download with multi-backend support Adds a built-in File Browser page and a File Download system to Hermes Web UI, enabling users to browse, edit, preview, upload, and download files from the workspace directly from the web dashboard. File Browser (/hermes/files): - New view FilesView.vue plus components under components/hermes/files/ (FileTree, FileList, FileBreadcrumb, FileToolbar, FileContextMenu, FileEditor, FilePreview, FileRenameModal, FileUploadModal) - New Pinia store stores/hermes/files.ts for directory tree, selection, and editing state - New API module api/hermes/files.ts - New server routes routes/hermes/files.ts with CRUD, rename, upload, and directory listing - New service services/hermes/file-provider.ts with a pluggable provider architecture (local filesystem + multi-terminal backends) File Download: - New server route routes/hermes/download.ts and client API api/hermes/download.ts - Integration in chat messages (MessageItem.vue, MarkdownRenderer.vue) to surface downloadable file references Packaging: - package.json: add a prepare script so the package can be installed directly from a git URL with dist/ built automatically i18n: add files/download translations to en.ts and zh.ts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use clipboard fallback for non-secure HTTP contexts navigator.clipboard is undefined on HTTP intranet deployments (only available in secure contexts). The previous synchronous calls threw silently and the success toast still fired, making 'copy' actions appear broken. - Add packages/client/src/utils/clipboard.ts with execCommand fallback via a hidden textarea - Use the helper in FileContextMenu (copy file path), CodexLoginModal (copy user code), NousLoginModal (copy user code), ChatPanel (copy session id) - Each call now awaits the result and shows success/failure based on the actual outcome Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |