Skip to content

merge: main 合入 dev(补 v0.5.0 发版祖先,修 PR#44 diverged) - #45

Merged
BlackStar-Agent merged 1 commit into
devfrom
main
Oct 17, 2026
Merged

BlackStar-Agent merged 1 commit into
devfrom
main

Conversation

@BlackStar-Agent

Copy link
Copy Markdown
Collaborator

PR #43 以 squash 方式合并,其发版提交不在 dev 祖先中,导致 #44(dev→main)diverged 无法合并。本 PR 把 main 合回 dev,恢复单调发版线。

* feat: P2 batch 5 — distributed execution nodes (old-device worker cluster)

protocol: /worker WebSocket endpoint with JSON frames (hello/dispatch/tokens/report/error), authKey auth; WorkerHub pool with per-worker outbound channels, pending dispatch table, token streaming into event bus, timeout-bounded execution

orchestrator: remote-first routing (sync accepts check + remote execute with local fallback, remote.fallback event); Core::set_remote hot-rebuilds orchestrator; execute_unit entry for worker side

worker: WorkerSession client (tokio-tungstenite plain WS) runs full local Core — its own model profiles/tool gateway; exm worker --url --token --id CLI subcommand (hostname default)

tests: 21/21 green incl. two-Core full-wire smoke (worker session via real WS executes dispatched nodes, DAG terminal)

* feat: P2 batch 6 — interrupted-session resume on gateway boot

resume: scan sessions with Executing graphs containing non-terminal nodes; replay done nodes (reports backfilled from sync_reports_by_node, report ids restored), reset interrupted to Ready, re-run scheduler, converge with resumed flag

plumbing: store.sync_report_of_node typed lookup; TaskGraphModel.set_report_id; ExecCtx/run_node/converge made public for resume path; gateway serve() triggers resume at boot

tests: 22/22 green incl. interrupted-graph reconstruction smoke (all nodes terminal, >=3 done after resume)

* feat: P2 batch 7 — terminal hardening (timeout kill) and session token budget

terminal: async execution via tokio (no runtime-thread blocking), kill_on_drop timeouts — 120s dispatch / 300s approval execution; hung commands can no longer stall nodes

budget: maxSessionTokens config (estimated chars/4, 0 = unlimited); Core::chat gate rejects over-budget sessions with clear guidance; schema entry for settings page

tests: isolated per-test agents tree copy (fixes cross-test repo workspace pollution — leftover active_group from interrupted runs broke roster loading); 23/23 green incl. hung-command kill and budget-gate smokes

* feat: P2 batch 8 — voice input pipeline and windows process-tree kill

voice: transcribe on LlmProvider trait (openai/azure /audio/transcriptions, multipart), Core::transcribe via active profile (whisper-1), POST /api/voice/transcribe endpoint; WebUI mic button (MediaRecorder webm -> gateway -> text into input, recording state)

hardening: timeout kill now taskkills the full process tree on Windows (cmd grandchildren no longer leak); pid captured before wait_with_output move

tests: 24/24 green incl. transcribe channel contract (mock explicitly unsupported)

* feat: P2 batch 9 — text-to-speech read-aloud and session usage observability

tts: speak() on LlmProvider trait (openai/azure /audio/speech, mp3 bytes), Core::speak via active profile (tts-1); POST /api/voice/speak returns audio/mpeg; WebUI per-message read-aloud button with playback state

usage: GET /api/sessions/:id/tokens (estimate + budget); chat rail shows live token usage, refreshed per round

tests: 24/24 green (speak channel contract alongside transcribe)

* feat: P1 batch 10 — telegram voice input and channel chat allowlist

voice: telegram voice messages -> getFile download (ogg) -> active-profile transcription -> normal text flow; failed transcription degrades gracefully

security: Channel.allowedChats allowlist (empty = unrestricted); non-listed chats ignored with log; exposed in create/update endpoints and WebUI channel form (comma-separated)

tests: 24/24 green regression

* feat: settings page categorized redesign + empty model defaults without keys

settings: sectioned cards (runtime/memory/security/automation) with icon+description headers, label-left control-right rows, proper widgets (switch for booleans, textarea for prompts/allowlists), per-page save button; LLM section stays on provider page

defaults: model names default to empty instead of gpt-4o placeholders — without API keys placeholder models are meaningless; users set real models when configuring a provider; mock channel ignores model names

gateway: maxSessionTokens exposed in GET/PUT /api/config; settings page shows live budget

* feat(ui): settings page v3 — left category nav, single-panel view

one category visible at a time (runtime/memory/security/automation) instead of stacked cards; enum select for approval mode; per-section save; fixed-width right-aligned controls

* feat: P1 batch 11 — dual memory modes (deep db vs memory.md file-only) + full config exposure

deep-off mode: planning injects memory.md (<=8000 chars) instead of db recall; memory panel becomes markdown editor via GET/PUT /api/memory/md; settings labels clarified

config exposure: GET /api/config now returns memory/security/automation groups — settings page shows actual values instead of schema defaults (was the incomplete part)

* feat: memory.md size limit with autonomous AI compaction and archiving

config: memoryMdMaxChars (default 5000) in memory group + settings schema; PUT /api/memory/md auto-triggers background compaction when over limit

compaction: LLM simplification via orchestrator provider (compression contract), original text archived — deep-on writes digest entry into db (searchable), deep-off appends workspace memory_archive.md; nothing lost either way

ui: md editor shows char count vs limit, save reports background compaction; mock channel deterministic compression output; 25/25 tests green

* feat(ui): units page group selector, flat member list (primary first), no domain division

units page: group dropdown to view/manage any group members (no longer bound to background active group); nav renamed units; primary agent listed first; domain grouping/inputs removed from units/groups/singles create forms — single-domain labels added complexity without value

gateway: DELETE /api/groups/:gid/agents/:identifier for cross-group member management; api.ts removeGroupAgent + allowedChats passthrough on channel create/update

* fix(ui): remove leftover activation wording from management pages

group/channel management pages no longer surface session-scoped activation state; wording aligned to per-session target selection

* feat(ui): language switcher (zh/en) next to theme switcher + shell translations

sidebar language panel in same position/style as theme; localStorage persisted; nav/branding/status/settings fully bilingual via shared i18n infra

cleanup: remove redundant tip line in GroupsView (group switching is already noted in chat rail)

* fix(ui): settings i18n — replace remaining title/desc refs with t() keys

* docs+core: 文档与事实对齐;移除「无密钥自动降级模拟通道」;修复终端超时用例挂起

文档(与代码事实逐条核对)
- docs/协议与契约.md:SyncReport 契约按代码修正(statements / risks /
  blockers{reason,unblockCondition} / conflicts);扩展点路径改 <identifier>.json
- docs/使用指南.md:group/agent create 的名称是位置参数(原文误写 --name);
  补 worker、group export/import、经验优化三节
- docs/架构与设计.md:重复小节去重;测试策略改为「测试替身仅测试使用」
- docs/安装指南.md:FAQ 由「无密钥自动降级模拟通道」改为「不会用模拟输出充数,需先配置模型」

代码(产品行为)
- 新增 UnconfiguredProvider:未配置端点/密钥的通道调用即报错并给出配置指引
- Provider 规则改为显式配置优先:有 base_url+key → 真实推理;未配置 → 替身模式给 Mock、
  产品模式给 Unconfigured;use_mock 仅由 EXM_LLM_MOCK=1(或测试)开启
- 移除全部「自动置 mock」点(config/gateway/cli/install);配置热更新不改变替身状态
- install / doctor / model list / chat 头 / 网关 banner 文案统一为「未配置——请在模型提供商页配置」

测试
- 修复 tools.rs 终端超时路径:stdio 读取独立任务 + 超时 abort + taskkill /T /F +
  child.wait() 有界回收(原实现挂死,曾导致全量测试 20+ 分钟不结束)
- 清理编译告警:删死结构体、noop clone、未用 mut/导入、测试函数名 ASCII 化

验证:cargo test --workspace 8 单测 + 17 冒烟全绿;gateway e2e 92/92 全绿

* ui: 排版层级重构 —— 新增表单只留主流程,可选与运维细节收进「高级设置」

用户反馈:新增提供商把厂商预设全铺成按钮墙、还要求填指挥体/子个体模型、嵌入模型、失败回退——
这些不该出现在「接入一个厂商」的主流程里。

设计原则(本轮确立):一页只回答一件事;可选与运维细节一律折叠,默认收起。

- 「提供商」页重写(ModelsView.tsx)
  - 厂商预设 9 按钮墙 → 下拉(带端点形态提示 + 自定义/自建端点)
  - 主表单只剩:提供商类型 → Base URL → API Key(Key 池为可选多行)
  - 高级设置(折叠):显示名称 / 档案 ID / API 协议 / 默认模型(预设自动填)/
    指挥体与子个体模型覆盖 / 嵌入模型 / 失败回退
  - 卡片信息层级重排:端点(+协议短标签) / 模型 / 密钥状态 / 回退链 / 嵌入模型
  - 措辞修正:不再出现「Mock / 模拟通道」,未配密钥显示「未配置(对话前请补填)」
- 新增统一页头组件 components/PageHeader.tsx(标题 + 一句话说明 + 右侧操作区),
  落地于:提供商 / 子个体 / 智能体组 / 独立智能体 / 技能 / 自动化 / 审批 / 通道 / 记忆 / 活动;
  原先挤在按钮行里的长提示统一挪入说明段(层级:标题 → 说明 → 操作)
- 通道表单 8 项平铺 → 核心 = 平台/通道 ID/Token/绑定组,高级 = 备注/白名单/出站回调
- 自动化表单 6 项平铺 → 触发方式改 Segmented(周期 Cron | 一次性时间)互斥切换,会话标题进高级
- styles.css 新增 .page-head/.page-title/.page-desc/.page-actions/.form-advanced/.model-kv/.form-grid-2
- 命名对齐:与工作区正在进行的「模型提供商 → 提供商」全局改名保持一致

验证:npm run build:webui(tsc + vite)通过;产物含新样式与新文案,
「厂商预设 / 模拟通道 / Mock 模拟」字样已从产物消失;网关实测启动正常(health 200 / 托管 dist / 40 个体)

* ui: 控制台视觉重构 —— 工程图刻度语汇、页面编号 01–14、科研感登录门与任务图

三类线条语汇(全部由 CSS 变量驱动,随 5 套强调色联动):
- hud 角标:面板四角短刻线;scale 刻度尺:等差刻度 + mask 淡出;grid 剖面:低透明度栅格

全局
- 新增令牌 --tick-step / --tick-color / --tick-color-hi / --grid-size / --accent-04·08·30
- body 双向 40px 栅格底纹;全局 tabular-nums 保证读数对齐

侧栏与页头
- 侧栏右缘刻度尺(每 5 格长刻线);菜单项加序号列,序号与图标间加短刻线,选中项左侧荧光轨
- 页面编号 01–14:单一事实源 NAV_ITEMS,侧栏与页头同源
- PageHeader 重构:desc 移出 .page-head-row 独占整行,修复说明文字被操作按钮压住

组件
- 表格表头列间竖刻线分隔;补齐此前完全缺失的 .plain-table / .model-card / .skill-card / .pane-loading
- LedgerView 补页头(原无页头且空态早退);SettingsView 统一 pane-wrap;ChatView 加控制台读数条

仪器感页面
- 登录门:72 条刻度环 + 十字准星 + 双层同心圆,去圆角,标题下加测量基线
- 任务图:坐标刻度、节点状态轨 + 量度条、正交折线连线、NODES/EDGES/DEPTH 读数

文档
- docs/使用指南.md WebUI 章节表格按 01–14 重排

* 提供商页回到「只回答一件事」+ 侧栏/间距回正 + 编排词清理

提供商设置(用户反馈:不该加的东西不要往这加):
- API Key 与 Key 池合并为一个可增删列表,不再分两块填
- 指挥体模型 / 子个体模型从全栈删除(此前只是折进「高级设置」,等于没删):
  LlmProfile/LlmConfig 的 orch_model/unit_model/embed_model 合并为单一 model;
  ModelPool 的 insert/resolve/entry 去掉 unit 参数;expand_chain 同上;
  gateway/CLI/install 向导同步;旧配置由 LlmProfileFile/LlmConfigFile 兼容读取,保存后不再回写旧键
- 嵌入模型移到「记忆」页「语义检索」卡(memory.semanticModel),core 新增 semantic_recall()
- 提供商类型名后不再挂多余描述

WebUI:
- 侧栏去掉序号列、恢复原有顺序与文案(撤销上一轮擅自的改名「独立智能体」与换位)
- .pane-wrap 去掉在已有内边距容器里的二次居中(智能体组/子个体左空隙过大的根因)
- list-rail 300→260px、skill-grid 最小 380→320px

文案:
- 清除「公司架构/团队架构」类比(9 处),示例组名改「研发组」
- 清除自造的「独立智能体」,统一为「智能体」

修复:
- e2e.rs 未带密钥 401 用例中重复的请求行(第二次请求覆盖第一次,属脚本改写的残留)

验证:cargo check --all-targets 0 警告;cargo test 8+17 全绿;e2e 92/92;
tsc --noEmit 干净;vite build 通过;产物禁用语扫描全 0。

* webui: 修复「记忆」页白屏崩溃 + 提供商卡片信息层级 + 设计令牌归一

修复(实测发现,非推断):
- 记忆页整页白屏:MemoryView 用 stats?.memory.total,外层可选链挡不住内层缺失
  (stats 有值而 memory 为 undefined 时照样抛错,整棵 React 树塌掉)。
  改为逐层 stats?.memory?.total ?? 0;同类 config?.memory?.enabled / semanticModel 一并加固。
- 侧栏底栏的 MOCK/LINK 徽标删除:测试替身不是产品状态,违反项目铁律。
  改为「通道就绪 / 未接入」,由 config.llm.apiKey 是否非空驱动。

提供商卡片:
- 改为四行事实:端点 / 模型 / 密钥 / 状态;「全局默认」从标题行移入事实区,
  标题只留身份,不再与操作按钮争位置
- 「已配置(N 把)」原用 warning 琥珀色(读起来像出故障),改为绿色中性态;
  「未配置」才用 warning
- 卡片头统一高度,避免「有无次要按钮」导致事实行跨卡错位
- 页头说明压成一句

版式与令牌:
- 颜色归一:手抄近似值 #8fa6b8 / #9fb6c6 → var(--text),
  rgba(29,42,54,0.6~0.9) → var(--line),共 8 处
- antd token 同步:colorTextSecondary #8fa6b8 → #6d8296(= --muted),
  colorTextTertiary → #4a5c6c(= --muted-dim)
- 智能体组元信息行的全角空格分隔改为真实元素 + flex gap

验证:cargo check --all-targets 0 警告 0 错误;cargo test 8+17 全过;e2e 92/92;
tsc --noEmit 干净;vite build 通过;提供商/记忆/智能体组/侧栏多页截图实拍复核。

* docs: 统一 orchestrator 注释措辞为「单体智能体」

「独立智能体」是此前自造的叫法,全库仅剩这两处(均为注释)。代码库既有术语
是「单体智能体 / 单体模式」(registry.rs、singles.rs、SINGLE_CONTRACT 正文、
smoke.rs 一致使用),本次对齐,全库该词归零。

验证:cargo check --all-targets 无代码级告警;cargo test 8+17 全过;e2e 92/92。

* feat(ui): markdown rendering for chat messages (GFM, dark-theme code blocks)

* feat(ui): session search, rename, and chat rail cleanup

* refactor(ui): groups page — clean flat layout, settings modal, remove inline editing clutter

* feat(ui): groups page settings modal (workspace + default model) with gear button

* fix(ui): chat page declutter — remove duplicate speak btn, simplify console bar, hover session ops, shorter hints

* feat(ui): collapsible chat sidebar with edge toggle button

* fix(ui): restore console bar readouts (MODE/STATE/TOKENS) removed in earlier cleanup

* fix(ui): chat-shell height and CSS cleanup

* fix(ui): chat-shell row-reverse in main rule not trailing override

* fix(ui): remove redundant read-aloud button from message bubbles

* feat(ui): task graph page — session label + selector, clear which session the DAG belongs to

* fix(ui): graph page — stats readout left, session selector right

* feat: one-click quickstart scripts (sh + bat)

* docs: README quickstart — one-click scripts first, manual build second

* feat: full auto-install scripts (install.sh + install.bat) — clone, install deps, build, run

* feat: quickstart downloads prebuilt releases (no compile needed); CI workflow builds and publishes on tag

* chore: move install/quickstart scripts to scripts/ folder; update README URLs

* ci: add test-only workflow on push; release.yml waits for manual tag (no auto-publish until fully tested)

* fix(docs): README ASCII art — pure ASCII # style, equal-width lines render correctly on GitHub

* feat(docs): SVG logo with DAG node design, terminal aesthetic, animated status LED

* docs: SVG logo — 58px font, compact DAG, text glow, fills canvas

* docs: SVG logo — hard edges, diamond DAG nodes, right-angle wire routing, no ONLINE

* docs: SVG logo — diamond nodes drawn after lines (no overlap), diagonal wire routing restored

* docs: redesigned product logo — hex lattice + center diamond, large 68px wordmark; separate 256px app icon

* docs: premium logo — layered hex, glowing core with inner diamond, HUD tick marks, corner brackets, gradient wordmark

* docs: logo — restore EX·MACHINA dot separator, align connector lines to diamond vertices

* docs: full-width banner logo (icon left, wordmark + tagline right); README adds H1 heading; intro text embedded in SVG

* docs: logo — precise flat-top hexagon geometry, centered text block, proper icon-text spacing; README H1 updated

* docs: restore original subtitle and README H1

* docs: README H1 = ExMachina — 一个群体协作的智能集群

* docs: logo subtitle = ExMachina — 一个群体协作的智能集群

* docs: logo — remove icon, pure centered text banner

* docs: logo — 110px title nearly fills width, wider underline

* docs: logo — 100px title with top spacing, 18px subtitle, 14px body text

* docs: add LICENSE (MIT), SECURITY.md, CONTRIBUTING.md

* docs: SECURITY.md and CONTRIBUTING.md now bilingual (zh/en)

* docs: split README into zh (README.md) + en (README_EN.md) with language switcher

* docs: logo subtitle restored to 智械体集群 · MULTI-AGENT CLUSTER

* docs: logo subtitle — 智械体集群 // AGENT CLUSTER (original)

* docs: language switcher moved below badges, centered

* docs: logo — subtitle 18→22px semibold, body 14→18px, brighter colors, more height

* docs: logo — 画布 1200x300,字号与线宽按 Retina 重做;背景改纯色、去副标题

README 头部 SVG 的「字小、线细、锯齿」三个根因与修法:

1. 字小 —— 画布 960x280 经 width=100% 引用后在 GitHub 阅读栏(1012px)
   只剩 ~295px 高。改为 1200x300,主标题 100→88px(配 letter-spacing 撑满)、
   底部文案 18→23px。删掉副标题后标题整体下移到视觉居中。
2. 线细 —— 原字体栈以 'SF Mono','Cascadia Code' 打头,Windows 会落到
   Courier New(细衬线等宽)。字体栈改为 ui-monospace 打头;
   主标题改 fill + 同色 stroke + paint-order 加粗字面。
3. 锯齿 —— 0.4px 级描边在 Retina 上被采样成灰虚线。全部细线提到 >=1.6px
   且落在整数设备像素;移除 0.4px 网格线。

排版取舍:
- 背景改为纯色 #0b1118,不使用渐变。
- 删除副标题「智械体集群 // AGENT CLUSTER」。
- 不加角标等装饰性元素,只保留刻度尺 / HUD 角标 / 边框 / 分隔线。
- 底部文案含「零情绪」,属此前已否掉的自造氛围词,删除;
  压成四个短标签(契约回流 / 冲突裁决 / 证据分级 / 结论收束)。

exmachina-icon.svg 未改动。

* feat: 通道平台全面扩展 —— QQ 官方机器人 / NapCat 适配器 + 运行状态 + 密钥掩码

通道网关(后端):
- 新增 qqbot 适配器:开放平台 WS 长连接,token 缓存提前刷新,断线先 Resume 再
  Identify,被动回复携带 msg_id + 递增 msg_seq,sandbox 可选
- 新增 napcat 适配器:OneBot 11 正向 WS(NapCat / Lagrange 通用),读循环常开 +
  mpsc 专职写任务,数组段与 CQ 码双格式解析
- 通道配置平台目录化:Channel.config{} 扩展配置,新平台零结构体改动;
  create 校验 qqbot 需 appId/appSecret、napcat 需 url
- 通道运行状态:适配器连上/断开/出错覆盖上报,GET /api/channels/status 查询,
  删除/停用即清除
- 密钥全链路掩码回显(***已配置***):顶层 token/secret + 敏感 config 键;
  更新三态语义(掩码沿用 / 空清除 / 新值)
- 修复:PUT /channels/:id 的 body.id 无默认值,前端更新通道(不发 id)一直 422,
  通道编辑与启停开关自上线即不可用;补 #[serde(default)] + e2e 锁定

WebUI:
- 通道页重写为平台目录驱动(PLATFORMS):表单/凭证判定/回复形态由目录出,
  状态列轮询运行状态(已连接 / 连接异常 + 明细)
- 修复:ModelsView 本地掩码哨兵 ***MASK*** 与后端 ***已配置*** 漂移,编辑档案
  不改密钥会把掩码字面量存成 API Key;统一为 api.ts 共享 KEY_MASK
- i18n 架构化:i18n/ 注册表(TKey 编译期键检查,en 缺键回退 zh,新语言零成本),
  全部视图清扫,中英双份词条
- 布局修复:对话页与右侧会话栏间距(row-reverse 无 gap)

验证:
- cargo check --workspace 零警告;e2e 103/103(新增通道校验/掩码落盘/状态接口
  断言;e2e 环境自持,不再随本机 config 漂移)
- npm build 通过;通道页中英表格与编辑弹窗截图复核

* feat: 「提供商」→「模型设置」—— 模型清单 + 能力模型(组级覆盖)+ 视觉转述

模型设置页(原「提供商」页改名,nav.models):
- LlmProfile.models[]:每个提供商一份模型清单(模型名 + 视觉/语音能力开关);
  默认模型保存时自动并入清单;清单未标记 = 能力未知,输入直通(向后兼容)
- 能力模型槽位(capabilities 配置节 + GET/PUT /api/llm/capabilities):
  语音合成(TTS)/ 语音识别(语音转述)/ 视觉转述 / 嵌入;
  嵌入与记忆页 semanticModel 同一字段(两处入口等价);TTS/STT 由硬编码 tts-1/whisper-1
  改为按槽位解析,未配置回落原默认
- 视觉转述降级:生效模型明确 vision=false 且配置了转述模型时,逐图转文字描述注入规划;
  未配置则忽略图片并在输入中说明;能力未知保持直通
- UI:提供商卡新增模型清单行(默认 / 视觉 / 语音);页底「能力模型 · 全局默认」卡;
  编辑弹窗 Form.List 模型清单(开关 + 增删)

组级能力覆盖(能力槽位不再全局单值):
- GroupMeta.capabilities 持久化 + PUT /api/groups/:id/capabilities
  (空串 = 清除该项跟随全局;全空 = 整块收回)
- 槽位解析两级:组覆盖 → 全局槽位 → 出厂默认;TTS / STT / 视觉转述 / 嵌入四处统一
- 组设置弹窗新增「能力模型(组级覆盖)」四槽位,留空 = 跟随全局默认

修复:
- tr() 改用 useLang.getState() 同步读语言:原 hook 形式在组件渲染期被调用
  (构造 Select options)会把 hook 计入当前组件,两次渲染间钩子数漂移导致 React #310
  全树崩溃;同时消除 api.ts / models.ts 三处同类隐患

验证:cargo check 零警告;e2e 全过(模型清单与开关回显、能力槽位写入/回读、
组级覆盖写入/空串清除/落盘回读);npm build 通过;中英双页截图复核

* docs: README 头部改用同款 EXMACHINA 字符画(字母间 2 空格),快速开始前移至告警之后

* docs: 警告块前移至字符画之前(H1 下首元素)

* docs: 字符画首行补 1 空格对齐 88 列——修复逐行居中渲染下的右偏

* build(rust): toolchain by host + silence Linux-only unused pid

- rust-toolchain.toml / .cargo/config.toml: switch to stable channel so
  rustup auto-selects the host triple (Linux/macOS/Windows all build
  without edits); comment updated accordingly.

- crates/exm-core/src/tools.rs: mark the local \`pid\` binding with
  \`cfg_attr(not(target_os = \"windows\"), allow(unused_variables))\`.
  The PID is only consumed inside the Windows taskkill branch; on POSIX,
  tokio::Child::kill_on_drop already handles process teardown.

Verified on Debian 13 / x86_64-unknown-linux-gnu: `cargo check --workspace`
and `cargo build --workspace --release` both report zero warnings; the
`exm` / `exmachina` / `exm-gateway` binaries are produced and a
`cargo run -p exm-gateway --release` smoke test answers
`/api/health` with agents=40, ok=true.

* feat(gateway): bind on 0.0.0.0 by default; add --host flag

VPS / 容器 / 局域网部署场景下,loopback 默认值导致 '能跑起来但远程
访问不到'。改为:

- exm-gateway 默认监听 0.0.0.0,公网/局域网可访问(向后兼容:
  EXM_HOST=127.0.0.1 或 --host 127.0.0.1 仍可收紧)。
- `exm serve` 新增 --host 选项(短 -H),显式传入覆盖默认 / 环境变量。
- 启动日志链接打印改为绑定到的真实地址(不写死 127.0.0.1)。

API 变化:`exm_gateway::serve(core, port)` → `serve(core, port, host: Option<&str>)`,
库调用方需更新;唯一调用方(exm-cli 与 exm-gateway 独立入口)已同步。

* fix: 批量修复 WebUI/网关缺陷 17 项(API Key 保存与池掩码令牌化、鉴权设置入口、个体/智能体编辑、设置页契约、WS 重连竞态、间距统一等)+ 主智能体更名指挥体 + 单体去职责化;并入在途 WIP(browser 闸门/自定义工具/discord/matrix/slack 通道)

* fix: API Key 表单绑定真根因(Form.List 行绑定致输入被过滤)+ 智能体卡片 ⋮ 菜单(切换模型/编辑描述/编辑 SOUL.MD)+ 单体人设读写与 plan/converge 双注入 + 默认组/指挥体英文标注映射

* feat: 安装脚本重写(4 文件)——预检/重试/校验和/升级保数据/--port/--help/品牌化输出;修 macOS arm64 硬编码与构建日志吞错;bat 改 PS5.1 引导壳全 ASCII 免疫代码页 bug

* chore: 移除误入提交的测试残留文件 upgrading

* docs: 移除 README 低性能设备预编译包引导段落

* Update README with project inspiration details

Added a note about the project's inspiration from Ex-Machina in No Game No Life.

* Fix formatting in README.md for project inspiration

* feat: 编码体验全量落地 + 编成组目录制定稿 + Computer Use + WebUI 编码工作台/PWA + 桌面端 Tauri 壳

思维链与过程透明(对标编码型 Agent):
- provider 双轨流式:解析 reasoning_content/thinking_delta/Gemini thought,新增
  StreamDelta::{Text,Thinking};新 WS 事件 orchestrator.thinking / unit.thinking
- tool.call / tool.result 事件(callId/args/ok/耗时/摘要/images),工具执行全程可见
- 审批等待回灌:拦截后原地等待 approvalWaitSecs,批准后代执行、输出直灌模型继续干活
- WebUI 聊天页:思维流折叠、工具执行卡(edit diff/终端输出/截图预览)、内联审批卡

Computer Use:
- computer 工具(enigo 键鼠 + xcap 截屏):screenshot/click/move/scroll/type/key
- 默认关闭显式开启;输入动作过审批闸门 + 动作节流;截图经 ToolResult.images
  回灌视觉模型(vision 能力检测)并可在工具卡内预览

WebUI:
- 新增编码工作台 [CODE]:会话 | 工具优先对话流 | 工作区文件树 + 变更清单 + 代码预览
- 网关配套 /api/asset(截图预览)与 /api/fs/list|file(文件树/预览,沙箱只读)
- PWA(manifest + Service Worker + 图标)与移动端抽屉导航;与客户端同端口交付

编成组目录制定稿(多轮评审定稿):
- 组 = groups/<gid>/:group.json + SOUL.md(主智能体人格,仅用户面持有)+
  MEMORY.md(组浅层记忆快照,6000 字截断)+ agents/*.json + prompts/*.md + adaptations/
- 单体 = singles/<id>/:agent.json + PROMPT.md + SOUL.md + MEMORY.md
- 子个体无人格层、无独立文件夹(定义+提示词合并存储于组内);深/浅记忆分层语义定稿
- 提示词分层:主智能体偏助手(对话优先/L0 直答)、子个体各司其职(编码位增补作业纪律)、
  单体全能;registry 全链适配 + gen-agents.mjs/doctor/install/e2e 同步

桌面端:
- desktop/(Tauri v2):捆绑 exm-gateway sidecar 本机模式 + --remote/--key 远程直连,
  退出杀进程树;MSVC 为官方构建目标(README 内说明)

测试:test_config 密封化(强制 Mock + 审批等待 0);新增审批等待回灌三场景用例;
cargo test --workspace 8 单测 + 21 冒烟全绿;npm run build:webui 通过;网关冒烟全过

* chore: 接入 OpenSpec 规范驱动开发——新增 openspec/ 目录骨架与配置,.gitignore 放行 .gitkeep

* feat: OpenSpec 变更 capability-completion 落地(1/3)——配置 v2 六段新配置与迁移、存储三集合骨架、patch 补丁工具(统一 diff 解析/整体拒绝/行尾容差)+ coding/ops 白名单

* feat: capability-completion(2/3)——工作区变更接口(git 口径/检查点回退)、文件保存接口(沙箱+检查点+审计)、simple_unified_diff 生成器;测试 5+23 全绿

* feat: capability-completion(3/3 P0)——git 面板(概览/暂存/提交/切换 + 破坏性审批单)、CodingView 三标签改造、webui i18n;测试 3/5 全绿

* test: P0 闸门验证——修复上游脆弱测试(审批等待用例未显式声明 risky 闸门模式);workspace 52 测试全绿

* feat: capability-completion 组3 通道身份与门控——/pair 配对码(短码/TTL/单次)、入站统一闸门(群聊唤醒门控+身份管控前置裁决)、六适配器提及归一化(tg getMe 缓存/discord mentions/slack app_mention/napcat CQ:at/qqbot @驱动/matrix m.mentions)、审批单来源升级标(origin_user/origin_role)、IdentityPanel 控制台 UI;闸门单测 5/5

* feat: capability-completion 组4 用量治理——滑动窗口限流(通道主体/API 维度)、周期配额(请求数 @admit + token @run,按会话台账)、组内派发豁免、/api/limits/stats + SettingsView 用量卡片;P0 闸门关闭(workspace 全绿 68 测、validate 通过)

* feat: capability-completion 组6(1/3)——出站能力矩阵与降级决策、typing 指示(telegram/discord)、长回复分段推送(段落优先/代码块完整/超长硬切续接);回复分段/降级单测 5 个

* docs: design.md 增补 D12——媒体产物透出(outbox/artifacts)与出站投递实施口径(组 6.2-6.4)

* feat: capability-completion 组6(2/3)——媒体产物透出(outbox/截图与投递目录登记/run.finished artifacts)、spawn_reply 双闭包投递(直发+降级并注)、telegram/discord/slack 媒体直发(multipart/三步上传)

* feat: capability-completion 组6(3/3)——napcat 媒体直发(base64:// 段,远程安全)、matrix 媒体上传(media v3→content_uri)、入站媒体解析(telegram photo/document、discord attachments、napcat 段:下载落 inbox→图片暂存/文件注记,失败回退)+ 注入单测 2

* feat: capability-completion 组6 收尾——slack url_private 下载 / qqbot attachments / matrix mxc 媒体下载与失败占位回退;六通道入站媒体全通 + 注入/回退单测

* feat: capability-completion 组7-9——事件触发器(文件监听去抖合并/webhook HMAC+审计/cron 推送订阅/心跳 per-agent)、记忆三工具(组隔离/source=agent/主智能体默认授权)、会话历史管控(轮次快照/undo 检查点联动/编辑重发/fork 分支+REST+WebUI 入口)

* feat: capability-completion 组10 MCP 服务端——ACL 可见性矩阵(组/会话/工具清单)、stdio exm mcp serve(JSON-RPC 会话亲和)、网关 /mcp HTTP 挂载(鉴权+限流)、外部调用安全口径一致(审批/审计 mcp 来源标注);协议端到端/亲和/ACL/审批口径测试

* feat: capability-completion 组11-12——桌面集成(系统托盘/关窗驻留可配/原生通知三类含类别开关与事件映射单测/全局快捷键可改绑冲突提示)、doctor 新配置段诊断、文档同步(README 能力表/使用指南新章节/协议契约 REST+WS 事件)、原创性验收禁用词零命中

* chore: capability-completion 12.4 最终闸门——Dockerfile 补齐容器构建/运行时依赖(xcap dbus vendored 静态编译、enigo libxdo 构建包与 X11 运行时栈),compose 冒烟通过(health ok + 40 个体装载)

* chore: compose 支持 EXM_AUTH_KEY 注入(后台访问密钥,.env 注入不入库)

* fix: 用户测试反馈 12 项——WS 鉴权豁免(浏览器无法带头)+服务端 Ping 保活+客户端指数退避看门狗、组页卡片化+子个体并入组详情、编码页撤并为对话页编码模式开关、指挥体显示名目标感知、弹窗防溢出+全局紧凑化、MiniMax 预设+端点模型清单拉取+默认模型改清单选择、登录页十六进制稳定 8 列、导航改模型/网关措辞

* i18n: 组详情视图新增键(返回/交互中/组成员等)

* fix: 左下角「通道就绪」改「模型就绪/模型未配置」(区分 IM 通道页与模型接入状态),WS 断连提示统一网关措辞

* feat: 体验优化批次——组内个体/单体系统提示词在线编辑(PROMPT 读写端点+弹窗重构,去领域/能力字段)、orchestrator 改名去前缀+主智能体标签后置、设置页移除用量卡、加载/输出卡互斥+内联<think>归入思维链(MiniMax-M1)、组卡片头换行修复、单体菜单重构(修改PROMPT.md/删除沉底确认)、Machina 提示词沉浸化重写(去系统机制自述)

* fix: 组卡片头单行(名称不折+id省略号)与设置页撑满正式部署;此前容器误载旧CSS(column版)

* fix: 块级标题卡片(组卡/模型卡/单体卡/技能卡)隐藏标题内联装饰——装饰遇块级标题折行为「装饰行+文字行+装饰行」

* fix: 卡片标题装饰保留并与文字同行——组卡/模型卡标题容器改 inline-flex(内联装饰不再被块级标题挤到独立行)

* fix: 设置页界面分类选中时运行时不再误亮(current回退groups[0]的bug);webui细节打磨——移除压角测量标记、选中色/光标跟随强调色、控件圆角统一、卡片与表格悬停反馈、弹窗分隔线质感、内联代码样式、菜单选中强调线、滚动条细化

* fix: 侧栏分隔线移除无意义的「CHANNEL」标签(避免与真正的通道页混淆)

* feat: 对话界面过程呈现重构(OpenCode 模式)——撤编码模式开关;思维链随收束留存(不再消失);思维/工具/调度过程全部收入「使用了 N 个…」收起栏(默认收起、点击展开、流式带呼吸点)

* fix: 内联<think>分流截断点按字符边界回退——中文等多字节思考内容触发 is_char_boundary 断言恐慌(线上实测);回归测试覆盖多字节小步增量/完整分离/前缀判定

* fix: 删除当前会话未从 sessions 列表状态移除——后续删除用旧快照重建列表导致已删会话「复活」;统一从 getState 最新状态过滤并先落列表

* fix: 规划阶段流式输出改道思维轨——L0/L1+ 的内部协议 JSON 不再裸奔到可见输出区;非流式回退的内联<think>按阶段分轨(思考轨/可见轨)

* fix: 断点续跑改后台执行——不再阻塞端口绑定(中断会话的多节点调度+LLM往返曾导致启动期间整站502)

* feat: ux-refinements 组1-4 实施——停止轮次(令牌+检查点+端点+按钮+通道/stop)、思维链落盘(messages 扩展+round_trace)、会话搜索/通道标识过滤/导出、工具审计页、用量面板回归、审批跳转、通道连通测试探针、cron 下次执行+模板

* chore: ux-refinements 任务勾选

* feat: 智能连结网络(实验性)——nexus.links 配置段+LinkTarget、连结体执行器(exmachina REST/CLI opencode/codex/claude/custom)、编成 link 代理声明+run_node 路由、连结体 CRUD 端点与智能体组页管理区、指挥体/子个体集群措辞与默认智能体改名「智能连结」

* fix: 「智能连结」是默认智能体组名(连结体)而非单体智能体——组名改智能连结、单体恢复 Machina;registry 缺省组名同步

* fix: 智能连结网络独立为侧栏页(智能体组下方);组成员单元格 id 移到中文名下方;恢复成员 SOUL.md 编辑(重构时误删);NexusView 补 message 导入

* ui: 侧栏顺序调整——任务图/自动化上移至技能/模型之前

* ui: 智能连结网络显性实验性声明(侧栏实验角标+页内警示条)+ 图标改 ClusterOutlined 消除与任务图撞图标

* fix: 智能连结网络实验声明改到点子上——如实说明设想尚未被验证、效果可能达不到预期,而非泛泛的接口变动免责

* ui: 智能连结网络实验声明精简为一句话

* ui: 侧栏智能连结项精简命名并保证左对齐单行(实验角标浮右)

* ui: 侧栏实验角标改为紧跟文字内联(浮右被甩出可视区)

* ui: 侧栏不再显示实验角标——实验声明保留在智能连结网络页内

* feat: experience-polish 实施——草稿/召回/复制/会话预览与相对时间、浏览器通知(授权+分类开关+点击跳转)、hash 视图路由+会话深链、骨架屏+横幅统一

* chore: experience-polish 任务勾选

* feat: WebUI 移动端适配——触屏操作常显(无hover)、设置页纵向堆叠、表格横向滚动兜底、网格窄屏单列、刘海屏安全区、页头操作换行

* ui: 回到底部悬浮按钮+视图切换淡入

* fix: 登录页窄屏适配——品牌字 clamp 缩放不再截断;底部签名去「全连结」残留(指挥体就绪)

* ui: 登录页签名去掉 DEUS 前缀(恢复用户已删的措辞)

* fix: 设置页 SECTIONS 补齐 6 个新分类(Computer Use/通道身份/用量限制/事件触发器/MCP 服务端/结果推送)——此前选择这些分类因缺 SECTIONS 条目导致面板永远加载

* refactor: agents 结构重组——skills 移至项目根、protocol 移入默认组、组 id default→exmachina

* feat: 默认智能体/指挥体/默认 SOUL 提示词全面重构——参考成熟编码智能体注入完整编码工作流(编辑纪律/终端纪律/搜索策略/调试流程)、机械语言协议(状态播报/情绪抑制/判定短语)、安全与权限协议、错误分级处理

* fix: SOUL.md 去掉身份标签只留人设描述;registry 残留 default 引用清理

* fix: SOUL 文件去除元描述引言——组指挥体与默认人格只留角色本身

* ui: 组成员表紧凑列宽——子个体列固定 220 消除空白,职责 260,工具/状态列收窄

* fix: 组成员提示词校验文案修正——不再误用模型名提示

* fix: SOUL 只留性格层(工作流归 PROMPT);成员表 tableLayout=fixed + 子个体列 220 真正生效

* refactor: 编成目录 agents/ → entities/——entities/agents(单体,常见 AI 软件同款) + entities/groups(智能体组);修复 skills 未入镜像

* copy: 默认智能体描述精简——默认智能体,以「本机」自称

* ui: 组成员表工具列加宽到 300,职责列让位——标签不再逐行堆叠

* rename: 子个体「媒体体」→「影音体」——避免「媒体+体」双体拗口

* feat: 编成模板机制——entities/templates/(unit×4 + group×1),用户与 agent 均可基于模板创建组和子个体(GET /api/templates + agent_manage templates/create + 前端模板选择)

* fix: 模板创建按 template.json 的 id 解析目录(此前误用 id 拼路径导致创建失败)

* feat: 版本更新功能——版本号定为 0.1.0,/api/version(+check) 对比上游 dev,设置页「版本更新」面板,Docker 构建注入 GIT_HASH

* fix: compose build.args 重复键合并——GIT_HASH 与 EXM_LANG 同段

* feat: 一键更新——POST /api/version/apply 经 docker.sock 执行 git pull→build→up -d,状态轮询端点 + 设置页一键更新按钮与恢复检测

* change: 更新检查源 dev→main——发版口径(dev 开发线,merge 到 main 时推送新版本);main 尚不存在时优雅降级提示

* fix: 一键更新重启步骤借道一次性辅助容器——compose 客户端不再随被重启的旧容器一起被杀(实测踩坑:recreate 半途而废)

* fix: 工具链下载 ADD url → RUN curl --retry——消除构建期持续联网校验,网络抖动不再炸构建

* fix: 一键更新工具链改挂载宿主 docker cli/compose 插件——移除构建期下载,内层构建零网络依赖(根治缓存不命中+网络抖动)

* docs: 替换“智械体集群”为“智能集群”并更新示例文案

* fix: 更新脚本自造 DOCKER_CONFIG/config.json——docker pull 无配置文件时报 no configuration file provided

* perf: GIT_HASH 移至 runtime 阶段注入——commit 变化不再作废 Rust 编译缓存(外层构建 10min→<1min,一键更新内层构建不再触发 rustup 全量同步)

* copy: 更新检查描述去掉工作流括号说明

* fix: 辅助容器挂载仓库宿主真实路径(从容器 mount 反解)——/host 只存在于网关容器内,宿主侧不存在导致 compose 找不到编排文件

* ci: 工作流触发策略收敛——CI 仅 PR 触发,发版仅 dev→main 合入触发,dev 日常提交零消耗

* docs: 新增开发规范——分支模型/提交纪律/发版仪式/工作流触发矩阵固化成文;CONTRIBUTING 对齐实际提交类型并挂规范入口

* fix: 更新检查分支感知——本地在什么分支就对比该分支的上游(main 用户看 main,dev 开发者看 dev);「上游最新」标签随实际上游渲染

* ui: 「上游最新」行渲染实际上游 ref——不再写死分支名(dev/main 通吃)

* fix: add_message_full 过程数据按 id 原位替换回 jsonl——此前 put 写独立文档,思维链/工具轨迹刷新即失

* feat: 单体直接工具循环——chat_execute(系统提示+历史+工具面自主决策)+ run_round 单体分支 + execute_named 过程轨迹补录

* test: 单体直接循环冒烟(工具回灌/轨迹留痕/无任务图)+ 上下文压缩用例改组模式承载;修复 dev 存量测试编译债(link 字段/ExmConfig::default)

* chore: 版本推进 0.1.1——单体直接工具循环 + 编成模板 + 版本更新/一键更新

* ci: CI/发版流水线补装 libxdo——computer-use 栈(enigo/xcap)链接期缺库,cargo test 未跑先挂

* docs: 单体直接工具循环 4.5 部署实测勾选——真实模型两轮验证通过

* test: git_panel 干净断言过滤注册表播种目录——entities/skills 是测试环境噪声,不属于提交流程

* fix: 更新检查 rev-parse 加 --verify——上游 ref 不存在时保持空值走降级,而非把字面量当 sha 返回

* release: v0.1.1 (#12)

* ci: 工作流触发策略收敛——CI 仅 PR 触发,发版仅 dev→main 合入触发,dev 日常提交零消耗

* docs: 新增开发规范——分支模型/提交纪律/发版仪式/工作流触发矩阵固化成文;CONTRIBUTING 对齐实际提交类型并挂规范入口

* fix: 更新检查分支感知——本地在什么分支就对比该分支的上游(main 用户看 main,dev 开发者看 dev);「上游最新」标签随实际上游渲染

* ui: 「上游最新」行渲染实际上游 ref——不再写死分支名(dev/main 通吃)

* fix: add_message_full 过程数据按 id 原位替换回 jsonl——此前 put 写独立文档,思维链/工具轨迹刷新即失

* feat: 单体直接工具循环——chat_execute(系统提示+历史+工具面自主决策)+ run_round 单体分支 + execute_named 过程轨迹补录

* test: 单体直接循环冒烟(工具回灌/轨迹留痕/无任务图)+ 上下文压缩用例改组模式承载;修复 dev 存量测试编译债(link 字段/ExmConfig::default)

* chore: 版本推进 0.1.1——单体直接工具循环 + 编成模板 + 版本更新/一键更新

* ci: CI/发版流水线补装 libxdo——computer-use 栈(enigo/xcap)链接期缺库,cargo test 未跑先挂

* docs: 单体直接工具循环 4.5 部署实测勾选——真实模型两轮验证通过

* test: git_panel 干净断言过滤注册表播种目录——entities/skills 是测试环境噪声,不属于提交流程

* fix: 更新检查 rev-parse 加 --verify——上游 ref 不存在时保持空值走降级,而非把字面量当 sha 返回

---------

Co-authored-by: KurohaneKaoruko <kurohanekaoruko@gmail.com>

* Fix/cross platform release (#16)

* build: 跨平台编译修复——computer.rs 平台差异(enigo Send/Key::Insert 平台门控)+ 一键更新 Unix 门控;release 流水线支持分支手动触发(编译预验,发布仍钉死 main)

* build: 重生成 tauri icon.ico——原文件是改扩展名的 PNG,Windows 资源编译器与 macOS 图标解码均拒绝

---------

Co-authored-by: BlackStar-Agent <kurohoshi@126.com>

* release: v0.1.1 (#17)

* ci: 工作流触发策略收敛——CI 仅 PR 触发,发版仅 dev→main 合入触发,dev 日常提交零消耗

* docs: 新增开发规范——分支模型/提交纪律/发版仪式/工作流触发矩阵固化成文;CONTRIBUTING 对齐实际提交类型并挂规范入口

* fix: 更新检查分支感知——本地在什么分支就对比该分支的上游(main 用户看 main,dev 开发者看 dev);「上游最新」标签随实际上游渲染

* ui: 「上游最新」行渲染实际上游 ref——不再写死分支名(dev/main 通吃)

* fix: add_message_full 过程数据按 id 原位替换回 jsonl——此前 put 写独立文档,思维链/工具轨迹刷新即失

* feat: 单体直接工具循环——chat_execute(系统提示+历史+工具面自主决策)+ run_round 单体分支 + execute_named 过程轨迹补录

* test: 单体直接循环冒烟(工具回灌/轨迹留痕/无任务图)+ 上下文压缩用例改组模式承载;修复 dev 存量测试编译债(link 字段/ExmConfig::default)

* chore: 版本推进 0.1.1——单体直接工具循环 + 编成模板 + 版本更新/一键更新

* ci: CI/发版流水线补装 libxdo——computer-use 栈(enigo/xcap)链接期缺库,cargo test 未跑先挂

* docs: 单体直接工具循环 4.5 部署实测勾选——真实模型两轮验证通过

* test: git_panel 干净断言过滤注册表播种目录——entities/skills 是测试环境噪声,不属于提交流程

* fix: 更新检查 rev-parse 加 --verify——上游 ref 不存在时保持空值走降级,而非把字面量当 sha 返回

* Fix/cross platform release (#16)

* build: 跨平台编译修复——computer.rs 平台差异(enigo Send/Key::Insert 平台门控)+ 一键更新 Unix 门控;release 流水线支持分支手动触发(编译预验,发布仍钉死 main)

* build: 重生成 tauri icon.ico——原文件是改扩展名的 PNG,Windows 资源编译器与 macOS 图标解码均拒绝

---------

Co-authored-by: BlackStar-Agent <kurohoshi@126.com>

---------

Co-authored-by: KurohaneKaoruko <kurohanekaoruko@gmail.com>
Co-authored-by: Kaoruko <101451942+KurohaneKaoruko@users.noreply.github.com>

* build: 桌面端重写为 egui 纯原生应用(无 webview)——chat-first 主窗口 + 原生设置页 + 隐藏终端侧车 + Inno Setup/tar.gz/dmg 安装链

* build: 桌面端重写为 egui 纯原生应用(无 webview)——chat-first 主窗口 + 原生设置页 + 隐藏终端侧车 + Inno Setup/tar.gz/dmg 安装链 (#18)

* feat: B1 SQLite 存储底座——store.sqlite 主库 + 自动迁移 (#19)

* feat: B1 SQLite 存储底座——store.sqlite 主库(会话/消息/任务图/回流/账本/快照/审计)+ 自动迁移旧 FSDB 数据

- store_sqlite.rs: SQLite 实现(62 方法全量移植,WAL 单写者)
- 自动迁移: Store::open 检测旧 FSDB 数据一次性转换
- rusqlite bundled(零外部依赖,构建环境自带 C 编译器即可)
- 已知边界: 证据/事件/检查点/outbox 等低频集合本批次仍走 FsDb

* feat: B1 SQLite 存储底座——store.sqlite 主库 + 自动迁移 + rusqlite 依赖(bundled)

* fix: 补齐 feat/sqlite-storage 分支丢失的 Cargo.toml/lib.rs 改动(分支切换时丢失)

* release: v0.1.1 (#25)

* feat: EXMACHINA 智械体集群 —— Rust 多智能体协作系统(集群调度 / 契约回流 / 三账 / 记忆 / 多模型 / WebUI)

core: orchestrator DAG planning + concurrent dispatch, SyncReport contract enforcement with auto-rewrite, conflict arbitration, three-ledger (task/evidence/risk), recallable memory with decay, group/agent scoping and reliability stats

models: four protocols (openai/anthropic/gemini/azure) with sticky multi-key pools and per-protocol connectivity probe; per-agent/group default model resolution (agent -> group -> global) via ModelPool

platform: skills, cron/heartbeat automation, exec approval gate + auth key; Telegram/webhook/qq/wechat bridge channels; single-process gateway serving REST+WS+WebUI

delivery: exm/exmachina CLI, native-tls via system store, release profile LTO+strip (single binary ~5MB), GitHub Actions release pipeline for compile-free low-spec deployment; WebUI on React 19.3 + antd 6 (14 panels, 5 themes)

docs: four-doc set (install/usage/design/protocol); no provenance metadata in repo

* feat: P0 batch 1 — native function calling, model failover chain, context compaction, followup/collect

function calling: protocol-level tools for openai/anthropic/gemini/azure (definitions, streaming fragment assembly, per-protocol result threading); text protocol kept as mock/compatible fallback; whitelist/approval/audit preserved

failover: profile-level fallback chains (cycle-guarded), 45s cooldown skipping, switch only before any token emitted, global profile tail, model.failover event; provider form gains fallback selector

compaction: multi-turn context for planning — rolling summary (LLM-compressed) + recent-12 window injected into plan prompt; session.rollingSummary/summaryUpto persisted

followup/collect: Core::chat serializes runs per session (all channels migrated); queued inputs within a window merge into one round goal

fix latent ordering assumption: list_messages is chronological (fsdb read_lines), oldest->newest

tests: 17/17 green incl. failover chain/cooldown, compaction+collect semantics

* feat: P1 batch 2 — MCP client (stdio + streamable http) with tool gateway integration

mcp.rs: JSON-RPC 2.0 client, lazy initialize handshake, tools/list snapshot cache (sync) + connection pool (async, Send-safe), per-server allowedAgents visibility, tools/call with text content normalization

integration: config mcpServers[] persisted + hot rebuild on apply_config; ToolGateway.execute_mcp with unified audit; runtime tool specs extended per-agent with mcp:server:tool; native function-calling path routes mcp names; gateway serves GET /api/mcp + POST /api/mcp/refresh with background refresh on startup

tests: 18/18 green incl. in-test axum MCP server covering configure/refresh/snapshot/call/allowlist

* feat: P1 batch 3 — hybrid memory retrieval (semantic embeddings + lexical scoring)

provider: embed() on trait (openai /embeddings + azure deployments), deterministic pseudo-embeddings for mock channel; profile embedModel config + WebUI field

memory: entry vectors with write-path background backfill, query embedding boost in scoring, semantic fallback scan when lexical candidates empty; cosine similarity with layer/group scoping preserved

orchestrator: embed_query via active profile embed model injected into planning + dispatch recall paths

tests: 19/19 green (semantic fallback/boost smoke); serial guard for Core-based tests sharing repo workspace

* feat: P1 batch 4 — web_fetch tool and multimodal image input

web_fetch: ToolName variant with zero-dependency HTML body extraction (script/style/tag stripping, whitespace compaction), 20s timeout, 2MB cap, allowlist + audit semantics; dispatch made async

vision: ChatMessage.images (data URLs) mapped per protocol (openai image_url parts / anthropic base64 image blocks / gemini inline_data); image_stash module stages channel attachments for next planning turn; gateway chat body accepts images; WebUI attach button with canvas compression (<=1280px JPEG 82%, up to 4)

tests: 20/20 green incl. in-test axum page fetch (script/style stripped) and stash take-once semantics

* feat: P2 batch 5 — distributed execution nodes (old-device worker cluster)

protocol: /worker WebSocket endpoint with JSON frames (hello/dispatch/tokens/report/error), authKey auth; WorkerHub pool with per-worker outbound channels, pending dispatch table, token streaming into event bus, timeout-bounded execution

orchestrator: remote-first routing (sync accepts check + remote execute with local fallback, remote.fallback event); Core::set_remote hot-rebuilds orchestrator; execute_unit entry for worker side

worker: WorkerSession client (tokio-tungstenite plain WS) runs full local Core — its own model profiles/tool gateway; exm worker --url --token --id CLI subcommand (hostname default)

tests: 21/21 green incl. two-Core full-wire smoke (worker session via real WS executes dispatched nodes, DAG terminal)

* feat: P2 batch 6 — interrupted-session resume on gateway boot

resume: scan sessions with Executing graphs containing non-terminal nodes; replay done nodes (reports backfilled from sync_reports_by_node, report ids restored), reset interrupted to Ready, re-run scheduler, converge with resumed flag

plumbing: store.sync_report_of_node typed lookup; TaskGraphModel.set_report_id; ExecCtx/run_node/converge made public for resume path; gateway serve() triggers resume at boot

tests: 22/22 green incl. interrupted-graph reconstruction smoke (all nodes terminal, >=3 done after resume)

* feat: P2 batch 7 — terminal hardening (timeout kill) and session token budget

terminal: async execution via tokio (no runtime-thread blocking), kill_on_drop timeouts — 120s dispatch / 300s approval execution; hung commands can no longer stall nodes

budget: maxSessionTokens config (estimated chars/4, 0 = unlimited); Core::chat gate rejects over-budget sessions with clear guidance; schema entry for settings page

tests: isolated per-test agents tree copy (fixes cross-test repo workspace pollution — leftover active_group from interrupted runs broke roster loading); 23/23 green incl. hung-command kill and budget-gate smokes

* feat: P2 batch 8 — voice input pipeline and windows process-tree kill

voice: transcribe on LlmProvider trait (openai/azure /audio/transcriptions, multipart), Core::transcribe via active profile (whisper-1), POST /api/voice/transcribe endpoint; WebUI mic button (MediaRecorder webm -> gateway -> text into input, recording state)

hardening: timeout kill now taskkills the full process tree on Windows (cmd grandchildren no longer leak); pid captured before wait_with_output move

tests: 24/24 green incl. transcribe channel contract (mock explicitly unsupported)

* feat: P2 batch 9 — text-to-speech read-aloud and session usage observability

tts: speak() on LlmProvider trait (openai/azure /audio/speech, mp3 bytes), Core::speak via active profile (tts-1); POST /api/voice/speak returns audio/mpeg; WebUI per-message read-aloud button with playback state

usage: GET /api/sessions/:id/tokens (estimate + budget); chat rail shows live token usage, refreshed per round

tests: 24/24 green (speak channel contract alongside transcribe)

* feat: P1 batch 10 — telegram voice input and channel chat allowlist

voice: telegram voice messages -> getFile download (ogg) -> active-profile transcription -> normal text flow; failed transcription degrades gracefully

security: Channel.allowedChats allowlist (empty = unrestricted); non-listed chats ignored with log; exposed in create/update endpoints and WebUI channel form (comma-separated)

tests: 24/24 green regression

* feat: settings page categorized redesign + empty model defaults without keys

settings: sectioned cards (runtime/memory/security/automation) with icon+description headers, label-left control-right rows, proper widgets (switch for booleans, textarea for prompts/allowlists), per-page save button; LLM section stays on provider page

defaults: model names default to empty instead of gpt-4o placeholders — without API keys placeholder models are meaningless; users set real models when configuring a provider; mock channel ignores model names

gateway: maxSessionTokens exposed in GET/PUT /api/config; settings page shows live budget

* feat(ui): settings page v3 — left category nav, single-panel view

one category visible at a time (runtime/memory/security/automation) instead of stacked cards; enum select for approval mode; per-section save; fixed-width right-aligned controls

* feat: P1 batch 11 — dual memory modes (deep db vs memory.md file-only) + full config exposure

deep-off mode: planning injects memory.md (<=8000 chars) instead of db recall; memory panel becomes markdown editor via GET/PUT /api/memory/md; settings labels clarified

config exposure: GET /api/config now returns memory/security/automation groups — settings page shows actual values instead of schema defaults (was the incomplete part)

* feat: memory.md size limit with autonomous AI compaction and archiving

config: memoryMdMaxChars (default 5000) in memory group + settings schema; PUT /api/memory/md auto-triggers background compaction when over limit

compaction: LLM simplification via orchestrator provider (compression contract), original text archived — deep-on writes digest entry into db (searchable), deep-off appends workspace memory_archive.md; nothing lost either way

ui: md editor shows char count vs limit, save reports background compaction; mock channel deterministic compression output; 25/25 tests green

* feat(ui): units page group selector, flat member list (primary first), no domain division

units page: group dropdown to view/manage any group members (no longer bound to background active group); nav renamed units; primary agent listed first; domain grouping/inputs removed from units/groups/singles create forms — single-domain labels added complexity without value

gateway: DELETE /api/groups/:gid/agents/:identifier for cross-group member management; api.ts removeGroupAgent + allowedChats passthrough on channel create/update

* fix(ui): remove leftover activation wording from management pages

group/channel management pages no longer surface session-scoped activation state; wording aligned to per-session target selection

* feat(ui): language switcher (zh/en) next to theme switcher + shell translations

sidebar language panel in same position/style as theme; localStorage persisted; nav/branding/status/settings fully bilingual via shared i18n infra

cleanup: remove redundant tip line in GroupsView (group switching is already noted in chat rail)

* fix(ui): settings i18n — replace remaining title/desc refs with t() keys

* docs+core: 文档与事实对齐;移除「无密钥自动降级模拟通道」;修复终端超时用例挂起

文档(与代码事实逐条核对)
- docs/协议与契约.md:SyncReport 契约按代码修正(statements / risks /
  blockers{reason,unblockCondition} / conflicts);扩展点路径改 <identifier>.json
- docs/使用指南.md:group/agent create 的名称是位置参数(原文误写 --name);
  补 worker、group export/import、经验优化三节
- docs/架构与设计.md:重复小节去重;测试策略改为「测试替身仅测试使用」
- docs/安装指南.md:FAQ 由「无密钥自动降级模拟通道」改为「不会用模拟输出充数,需先配置模型」

代码(产品行为)
- 新增 UnconfiguredProvider:未配置端点/密钥的通道调用即报错并给出配置指引
- Provider 规则改为显式配置优先:有 base_url+key → 真实推理;未配置 → 替身模式给 Mock、
  产品模式给 Unconfigured;use_mock 仅由 EXM_LLM_MOCK=1(或测试)开启
- 移除全部「自动置 mock」点(config/gateway/cli/install);配置热更新不改变替身状态
- install / doctor / model list / chat 头 / 网关 banner 文案统一为「未配置——请在模型提供商页配置」

测试
- 修复 tools.rs 终端超时路径:stdio 读取独立任务 + 超时 abort + taskkill /T /F +
  child.wait() 有界回收(原实现挂死,曾导致全量测试 20+ 分钟不结束)
- 清理编译告警:删死结构体、noop clone、未用 mut/导入、测试函数名 ASCII 化

验证:cargo test --workspace 8 单测 + 17 冒烟全绿;gateway e2e 92/92 全绿

* ui: 排版层级重构 —— 新增表单只留主流程,可选与运维细节收进「高级设置」

用户反馈:新增提供商把厂商预设全铺成按钮墙、还要求填指挥体/子个体模型、嵌入模型、失败回退——
这些不该出现在「接入一个厂商」的主流程里。

设计原则(本轮确立):一页只回答一件事;可选与运维细节一律折叠,默认收起。

- 「提供商」页重写(ModelsView.tsx)
  - 厂商预设 9 按钮墙 → 下拉(带端点形态提示 + 自定义/自建端点)
  - 主表单只剩:提供商类型 → Base URL → API Key(Key 池为可选多行)
  - 高级设置(折叠):显示名称 / 档案 ID / API 协议 / 默认模型(预设自动填)/
    指挥体与子个体模型覆盖 / 嵌入模型 / 失败回退
  - 卡片信息层级重排:端点(+协议短标签) / 模型 / 密钥状态 / 回退链 / 嵌入模型
  - 措辞修正:不再出现「Mock / 模拟通道」,未配密钥显示「未配置(对话前请补填)」
- 新增统一页头组件 components/PageHeader.tsx(标题 + 一句话说明 + 右侧操作区),
  落地于:提供商 / 子个体 / 智能体组 / 独立智能体 / 技能 / 自动化 / 审批 / 通道 / 记忆 / 活动;
  原先挤在按钮行里的长提示统一挪入说明段(层级:标题 → 说明 → 操作)
- 通道表单 8 项平铺 → 核心 = 平台/通道 ID/Token/绑定组,高级 = 备注/白名单/出站回调
- 自动化表单 6 项平铺 → 触发方式改 Segmented(周期 Cron | 一次性时间)互斥切换,会话标题进高级
- styles.css 新增 .page-head/.page-title/.page-desc/.page-actions/.form-advanced/.model-kv/.form-grid-2
- 命名对齐:与工作区正在进行的「模型提供商 → 提供商」全局改名保持一致

验证:npm run build:webui(tsc + vite)通过;产物含新样式与新文案,
「厂商预设 / 模拟通道 / Mock 模拟」字样已从产物消失;网关实测启动正常(health 200 / 托管 dist / 40 个体)

* ui: 控制台视觉重构 —— 工程图刻度语汇、页面编号 01–14、科研感登录门与任务图

三类线条语汇(全部由 CSS 变量驱动,随 5 套强调色联动):
- hud 角标:面板四角短刻线;scale 刻度尺:等差刻度 + mask 淡出;grid 剖面:低透明度栅格

全局
- 新增令牌 --tick-step / --tick-color / --tick-color-hi / --grid-size / --accent-04·08·30
- body 双向 40px 栅格底纹;全局 tabular-nums 保证读数对齐

侧栏与页头
- 侧栏右缘刻度尺(每 5 格长刻线);菜单项加序号列,序号与图标间加短刻线,选中项左侧荧光轨
- 页面编号 01–14:单一事实源 NAV_ITEMS,侧栏与页头同源
- PageHeader 重构:desc 移出 .page-head-row 独占整行,修复说明文字被操作按钮压住

组件
- 表格表头列间竖刻线分隔;补齐此前完全缺失的 .plain-table / .model-card / .skill-card / .pane-loading
- LedgerView 补页头(原无页头且空态早退);SettingsView 统一 pane-wrap;ChatView 加控制台读数条

仪器感页面
- 登录门:72 条刻度环 + 十字准星 + 双层同心圆,去圆角,标题下加测量基线
- 任务图:坐标刻度、节点状态轨 + 量度条、正交折线连线、NODES/EDGES/DEPTH 读数

文档
- docs/使用指南.md WebUI 章节表格按 01–14 重排

* 提供商页回到「只回答一件事」+ 侧栏/间距回正 + 编排词清理

提供商设置(用户反馈:不该加的东西不要往这加):
- API Key 与 Key 池合并为一个可增删列表,不再分两块填
- 指挥体模型 / 子个体模型从全栈删除(此前只是折进「高级设置」,等于没删):
  LlmProfile/LlmConfig 的 orch_model/unit_model/embed_model 合并为单一 model;
  ModelPool 的 insert/resolve/entry 去掉 unit 参数;expand_chain 同上;
  gateway/CLI/install 向导同步;旧配置由 LlmProfileFile/LlmConfigFile 兼容读取,保存后不再回写旧键
- 嵌入模型移到「记忆」页「语义检索」卡(memory.semanticModel),core 新增 semantic_recall()
- 提供商类型名后不再挂多余描述

WebUI:
- 侧栏去掉序号列、恢复原有顺序与文案(撤销上一轮擅自的改名「独立智能体」与换位)
- .pane-wrap 去掉在已有内边距容器里的二次居中(智能体…
@BlackStar-Agent
BlackStar-Agent merged commit b155e85 into dev Oct 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant