Commit Graph

596 Commits

Author SHA1 Message Date
matevip
22c49f3a07 fix(chat): keep every iteration reasoning and render the timeline in emission order 2026-08-06 05:13:09 -04:00
matevip
30560eb7cf fix(chat): classify pre-tool narration by observation count, not iteration budget 2026-08-06 02:39:03 -04:00
matevip
e22173a476 feat(skill): close the self-evolution loop — auto-bind, routine mining, curation provenance and restore points 2026-08-06 01:51:22 -04:00
matevip
9dd58053c0 feat(channel): proactive channel-session message push + cron delivery target picker 2026-08-05 05:51:59 -04:00
matevip
c31a216cbd feat(chat): first-token pending placeholder in the assistant bubble 2026-08-04 23:28:17 -04:00
matevip
fefb3b25b8 feat(chat): live pre-tool narration collapse via segment_kind SSE event 2026-08-04 22:51:12 -04:00
matevip
046080d6aa feat: thinking display overhaul — live think-tag extraction, real durations, default visibility, reconnect and team-note fixes 2026-08-03 05:56:16 -04:00
matevip
679f749959 chore: bump version to 2.1.0-SNAPSHOT 2026-08-03 03:22:32 -04:00
matevip
5ba92f3b87 feat(llm): resolve per-model context windows instead of the global 128k default 2026-08-02 23:39:31 -04:00
mateaix
bfd84fd5c3 fix(models): 成员角色可读取自己能绑定的 provider 选项 (#570)
绑定 Agent 首选 provider 是 member 权限的操作,但唯一能列出 provider 的
GET /api/v1/models 要求全局 admin(它带 base URL、请求参数、liveness 诊断等
连接配置)—— 成员写得了绑定,却读不到可选项。

员工编辑弹窗把这个 admin-only 请求放在没有单独兜底的 Promise.all 里,成员
打开时 403 会让整批请求失败:技能、工具、已有绑定、首选模型链全部加载不出来,
弹出通用加载错误。

新增 GET /api/v1/models/options —— 只返回 provider 的 id 和显示名,viewer
权限,过滤掉未配置项 —— 并让员工编辑弹窗改用它。/api/v1/models 保持全局
admin 限制不变。
2026-08-01 22:12:47 +08:00
matevip
bdfa8a6f9d release: v2.0.0 2026-07-31 03:51:45 -04:00
matevip
823efc0c36 feat(memory): surface per-user private memory copies in admin UI and tool results 2026-07-31 01:50:52 -04:00
matevip
ad6b0728e9 fix(channel): stop streaming replies from showing the same text twice 2026-07-29 21:29:48 -04:00
matevip
9bc4741aa7 fix(channel): apply message filters on card streaming paths 2026-07-28 06:31:01 -04:00
mateaix
3643aed756 fix(team): gate pending-task auto-claim to the assignee; expose attach in tool schema 2026-07-26 12:35:51 +08:00
mateaix
b6326daaf8 feat(team): windowed task board — paged terminal columns with true totals and database-side status counts 2026-07-26 10:17:47 +08:00
mateaix
2cbe00a1e7 feat(team): plan-execute leads orchestrate through the task board — hand-off bridge, resume gate and step dependencies 2026-07-25 22:22:38 +08:00
mateaix
c15e51b34b feat(team): collaboration observability — live event channel, task timeline, prerequisite hand-off and readable validation errors 2026-07-25 19:57:57 +08:00
mateaix
251a3288dd feat(team): execution hardening, task deliverables and run transcript visibility 2026-07-25 14:32:49 +08:00
matevip
bc867f0cbb feat(ui): agent teams page with team management, kanban board and role-aware member views 2026-07-24 17:38:44 +08:00
matevip
86e65beafe feat(team): auto-dispatch assigned tasks to member agents and announce settled results to the lead 2026-07-24 17:37:33 +08:00
matevip
626c3a2fae feat(team): team registry, membership and shared task board with guarded state transitions 2026-07-24 17:37:04 +08:00
matevip
130112c5bf fix(ui): read the correct localStorage key for USER-scope always-approve 2026-07-23 14:59:08 +08:00
matevip
8174006b01 feat(approval): reject dead grant configurations at creation 2026-07-23 11:46:15 +08:00
matevip
be7b236cb5 feat(ui): surface the auto-approve outcome on audit rows with a create-grant shortcut 2026-07-23 11:46:09 +08:00
matevip
aa54058e31 feat(ui): scope-typed pickers and severity-ceiling hints on the auto-approve grant form 2026-07-23 11:45:42 +08:00
matevip
717f15e91f feat(conversation): rewind-to-message endpoint and duplicate-free regenerate across web, webchat, and console UI 2026-07-22 18:10:28 +08:00
matevip
4ac72a90a0 feat(skill): bundle file management — view and edit scripts, references, and templates from the console
The skill detail drawer could only show and edit SKILL.md; the bundle
files under scripts/ and references/ had no console surface, and
templates/ was readable by agents but absent from the canonical
store's bucket set.

- admin endpoints on /api/v1/skills/{id}/files: list (self-heals an
  empty canonical store from on-disk files), read, upsert, delete.
  Writes update the canonical row, materialize the workspace cache,
  and re-resolve the skill so agents pick changes up immediately.
  Path envelope enforces the three buckets and blocks traversal;
  builtin skill files stay read-only; virtual skills own no files.
- templates/ becomes a first-class DB-persisted bucket shared across
  the syncer, the workspace write/delete envelope, and prune guards.
- the agent-facing write_file action now mirrors into the canonical
  store and re-resolves instead of writing only the local filesystem.
- SkillMarket detail drawer gains a Files tab: grouped list, viewer,
  inline editor, create and delete, refetched on every entry.
2026-07-22 15:39:59 +08:00
matevip
5e188cd77b feat(skill): single-source SKILL.md — DB canonical, workspace file as tracked cache
The runtime resolved SKILL.md from the workspace directory while the
admin console read the skill_content column, so out-of-band file edits
(agent shell tools in a chat session) changed runtime behavior but never
showed up in the console, and a failed workspace export left agents
executing stale content the console claimed was current.

- SkillContentReconciler: three-way sync between the canonical DB column
  and the convention-workspace file, anchored on a sidecar hash marker.
  File-side edits ingest into the DB, DB-side edits materialize to the
  file, two-sided conflicts resolve DB-wins with a backup.
- Skill detail GET performs a read-time reconcile and triggers a
  single-skill rescan when the file side changed, so a console query is
  always current without waiting for the runtime cache TTL.
- SkillMarket detail drawer refetches the row and runtime status on open
  instead of rendering the page-load list snapshot.
2026-07-22 14:20:27 +08:00
matevip
e756219bdc fix(ui): channel binding picker shows agents created after page mount 2026-07-21 18:41:44 +08:00
matevip
bf6bed5511 feat(wecom): event-driven progress bubble with live tool trace 2026-07-21 10:29:00 +08:00
matevip
ae62faee4e fix(chat): refresh agent list on chat page reactivation
The chat page is kept alive by the router so navigating away and back
only fires an activation hook, not a fresh mount. An agent created,
edited, or deleted elsewhere (e.g. the employee management page) never
reached the chat page's own agent list, and stayed invisible or
unselectable in the agent picker until a full page reload forced a
fresh mount. The agent list is now refetched on every reactivation.
2026-07-17 18:15:38 +08:00
matevip
22a61e6e78 feat(wiki): closed relation schema for entity extraction
Entity extraction previously constrained entity types but let the
model freely invent any relation between entities, producing noise
that diluted the entities a knowledge base actually cares about.
Adds an optional per-KB relation schema (subjectType/predicate/
objectType triples): when set, the extraction prompt is scoped to
only those relations, and a hard filter drops anything that slips
through before it is persisted. Empty/unset keeps the existing
open-vocabulary behaviour.
2026-07-16 17:39:41 +08:00
倪程伟
fbfb8982cc
fix(agents): keep each (provider, model) unique in the preference chain
In the "Edit Agent → Preferred Providers" tab the same (provider, model)
combination could be selected repeatedly — e.g. two rows of the same
provider both pointing at the same model, or two "provider default" rows.
This is unintended: a provider may repeat across the fallback chain, but
each (provider, model) should stay unique.

Root cause: addProviderEntry() pushed unconditionally (the code comment
even said "we never dedup here") and the model <option>s had no disabled
state, so already-chosen models remained selectable.

Fix (Agents.vue):
- isProviderChoiceTaken(): detect whether a (provider, model) slot — or the
  provider-default slot (modelId === null) — is already used in another row.
- Model <option> + the default-model option are :disabled when already taken;
  the current row's own value stays selectable (exceptIdx).
- addProviderEntry(): take the default slot if free, else the first unused
  model; do nothing if every option is taken.
- The "+ Provider" pool button is disabled once the provider has no free
  (provider, model) slot left, so the click is never a silent no-op.

The existing unique index uk_agent_provider_model(agent_id, provider_id,
model_id) already guards non-null duplicates at the DB level, but it cannot
catch model_id IS NULL rows (SQL treats NULLs as distinct); the UI is now
the single source of truth for that.

Fixes #530
2026-07-15 14:56:16 +08:00
倪程伟
97a040aa89
fix(chat): dedupe tool-call segments by toolCallId, not name+args
A tool/MCP call could render 2+ times in the timeline (issue #521). The
tool is invoked once — this is a display artifact. The segment de-dup in
MessageBubble keyed on `toolName::toolArgs`, which fails two ways:

- The same logical call rendered on both the live SSE stream and the
  reloaded/persisted path can carry differing toolArgs strings
  (whitespace / key-order from re-serialization), so the two are NOT
  de-duplicated and both survive → the reported duplicate.
- Genuine repeated calls of the same tool with identical args (e.g. shell
  / python retries) share the key and get wrongly collapsed to one.

Prefer the LLM-provided toolCallId (carried end-to-end on both live and
persisted segments, stable across serialization) and fall back to
toolName::toolArgs only for legacy segments without an id. This fixes
both the visible duplication and the over-collapse.

Adds pure-function tests for the de-dup logic.
2026-07-15 14:53:22 +08:00
倪程伟
04a9bb9e13
fix(chat): honour per-agent model override in web chat model selector
The web ChatConsole seeded a fresh conversation's model from the global
default, never the selected agent's model override, and handleSendMessage
then pinned that default onto the conversation row. Since a conversation
pin outranks the agent override in the backend runtime resolver
(AgentGraphBuilder.resolveRuntimeBaseModel), the model chosen on the
agent edit page was silently clobbered. IM channels and external webchat
were unaffected — they leave the conversation unpinned.

- applyConversationModel now follows the backend precedence:
  conversation pin > agent model override > global default.
- The agent tier resolves via /agents/{id}/capabilities (authoritative)
  with a synchronous fallback (currentAgent.modelName against the
  enabled-model list) so an agent switch, a capability-fetch failure, or
  a not-yet-hydrated deep-link still honour the override instead of
  dropping to the global default.
- userPickedModel guards the async re-seed from clobbering an explicit
  pick; reset on new/switch/delete conversation.
- Unit tests cover the precedence tiers, the empty-string capabilities
  wire shape, and the synchronous fallback.
2026-07-15 14:51:55 +08:00
matevip
cd0360ff3f fix(wiki): stabilize concurrent raw-material uploads and PostgreSQL-compatible IDs
Give raw-material uploads a dedicated five-minute timeout and process file-picker and drag/drop uploads through a shared two-worker queue, so constrained uplinks no longer abort multipart requests at the global 30-second deadline.

Switch wiki processing jobs and page citations to application-assigned IDs: the PostgreSQL/Kingbase migrations define plain BIGINT primary keys without identity defaults, so database-generated keys fail on insert.
2026-07-15 14:27:14 +08:00
matevip
6aad9fd945 fix(ui): resolve lint errors surfaced by the new ESLint config
Use const for a never-reassigned local, drop an unused v-for index,
add a default branch to an exhaustive switch the linter cannot prove,
and remove eslint-disable directives that no longer match enabled rules.
2026-07-15 14:26:27 +08:00
matevip
f97624874c chore(ui): add ESLint 9 flat config and fix lint script
The lint script referenced eslint with --ext flags but the repo never had
an ESLint config file, so pnpm lint always failed. Add a flat config
(typescript-eslint recommended + vue essential) with legacy-code rules
downgraded to warnings, drop the flat-config-incompatible --ext flags,
and move pnpm build approvals from the no-longer-read
pnpm.onlyBuiltDependencies field to pnpm-workspace.yaml allowBuilds.
2026-07-15 14:25:59 +08:00
RobinZhiBin
8a6dd1fa67
fix(wiki): stabilize concurrent raw-material uploads and PostgreSQL-compatible IDs
Give raw-material uploads a dedicated five-minute timeout and process file-picker and drag/drop uploads through a shared two-worker queue, so constrained uplinks no longer abort multipart requests at the global 30-second deadline.

Switch wiki processing jobs and page citations to application-assigned IDs: the PostgreSQL/Kingbase migrations define plain BIGINT primary keys without identity defaults, so database-generated keys fail on insert.
2026-07-15 09:51:20 +08:00
mateaix
e82adfed42 chore(ui): ESLint 9 flat config, lint script fix, and lint error cleanup 2026-07-14 21:11:58 +08:00
matevip
f0dcc44fef feat(workspace): default storage root setting + desktop local-tools whitelist management (#512)
- Settings → System gains a 'default workspace storage path' item: validated
  on save (absolute, creatable), applied immediately without restart, and
  re-applied from the database on startup. Blank clears the override;
  existing data is never migrated.
- Desktop local file/command tools get a renderer settings page (allowed
  directory list with per-row delete, add via native picker, enable toggle,
  tunnel status); the native dialog additionally gains a 'remove directory'
  flow, fixing the whitelist that could only grow.
- System settings save surfaces backend validation errors as a toast.
2026-07-14 18:24:58 +08:00
mateaix
cf43294a9e fix(ui): resilient lazy-route loading during heavy agent runs (#515)
- router.onError fallback: a failed route-chunk load hard-navigates to the
  clicked route once (guarded against reload loops) instead of hanging
  silently until a manual refresh
- warm all lazy route chunks during idle time after login, so sidebar
  navigation no longer depends on live chunk fetches under load
- SSE executor switches to a virtual-thread-per-task executor, matching
  the app-wide virtual-thread model
2026-07-13 21:50:53 +08:00
matevip
6f875215ab chore: bump version to 2.0.0-SNAPSHOT 2026-07-13 18:10:41 +08:00
matevip
c9cc5b4f6f feat(chat): glass-themed preview for uploaded & AI-generated docx/xlsx/pdf (#513) 2026-07-13 18:00:54 +08:00
mateaix
a466f609cf release: v1.8.0 2026-07-12 17:29:29 +08:00
mateaix
9d6509840c feat(content-studio): 内容日历去重 + 毛玻璃改版 + 外框线加实 2026-07-12 13:08:58 +08:00
mateaix
ac4b277492 feat(content-studio): 交付即扫即记 + 内容日历只读页(自动化与打磨) 2026-07-12 11:51:12 +08:00
mateaix
85bee7a041 feat(content-studio): 公众号凭据设置+截图工具+平台规范; fix: 封面按文件名自愈 2026-07-11 18:48:11 +08:00
mateaix
973c4c508c feat(content-studio): 公众号/小红书图文创作场景 + gzh_package 打包与在线预览 2026-07-11 12:01:41 +08:00
matevip
71ad735e95 feat(wiki): cross-KB wikilinks [[kbId/slug]] and raw-material batch filter/reprocess/delete (#506) 2026-07-10 12:01:48 +08:00
MIST
e35c07f742
feat(mcp): progress notifications for long-running MCP tools
Wire MCP standard notifications/progress into the existing SSE stream so long-running MCP tool calls surface live progress instead of a bare spinner. A per-call progressToken maps back to (conversationId, toolCallId); ProgressAwareMcpToolCallback injects it into tools/call _meta and calls McpSyncClient directly (falling back to the delegate on error, and applying identity forwarding first). Progress events skip the ring buffer and are replayed from a latest-value snapshot on SSE reconnect. Frontend renders a gradient progress bar in ToolCallSegment when a running tool reports progress.
2026-07-09 18:05:14 +08:00
matevip
cc444f4c06 feat(agent): tool-call loop guard, post-mutation verify reminder, warning chips 2026-07-08 18:18:34 +08:00
matevip
5b948f7852 perf(ui): on-demand Element Plus, tree-shake unused components 2026-07-08 15:54:18 +08:00
matevip
1318a32b71 perf(ui): cut initial-load bundle via lazy model-viewer and preload fix 2026-07-08 15:53:57 +08:00
matevip
5db8fb14a4 fix(chat): stop history view snapping to bottom during streaming (#498) 2026-07-08 15:53:10 +08:00
matevip
b1648cad88 feat(llm): add Volcano Engine Agent Plan provider (/api/plan/v3) with GLM-5.2 primary 2026-07-08 11:21:23 +08:00
matevip
6802fc1c6a feat(chat): context occupancy panel with per-source breakdown (#492) 2026-07-06 16:44:59 +08:00
matevip
e236800002 chore: bump version to 1.8.0-SNAPSHOT 2026-07-06 11:40:52 +08:00
matevip
d950d54b00 fix(ui): resolve state confusion and cross-user data leak when switching menus/workspaces 2026-07-06 10:17:21 +08:00
mateaix
6252dfb81a release: v1.7.0 2026-07-04 20:28:15 +08:00
mateaix
9dfdae0aec docs(ui): translate tier-btn specificity comment to English
Follow-up to #488: repo convention is English-only code comments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 12:13:29 +08:00
MIST
d9c999abc8
fix(ui): stop tool-tier toggle button text overflow by raising .tier-btn selector specificity
The tier toggle buttons carry both .row-btn and .tier-btn (equal 0,1,0 specificity), so the later-declared .row-btn width:30px/display:flex overrode .tier-btn's width:auto/line-height and clipped the label. Scope the rule to .row-btn.tier-btn (0,2,0) so the text-button properties win.
2026-07-04 12:12:25 +08:00
倪程伟
53a12ee18d
feat(plugin/settings): search-provider catalog endpoint + grouped settings UI + plugin config form
Adds a read-only GET /api/v1/settings/search-providers catalog (admin-gated, no secrets), grouped collapsible provider cards, and a schema-driven plugin config form. Breaks a SystemSettingService<->PluginManager circular dependency via parameter @Lazy (with a context smoke test), and fixes PluginManager.updateConfig to merge instead of overwrite so omitted/blank secret fields are preserved. Hardens plugin search-provider id validation (reject-not-trim, case-insensitive conflict) and insulates the provider bridge hot path from throwing plugin code.
2026-07-04 12:06:33 +08:00
MIST
9fb3550e91
fix(ui): 修复菜单/工作区切换时的状态错乱与跨用户数据泄漏 (#483)
### 背景
切换菜单(对话 ↔ 知识库)或工作区时,存在多个状态错乱问题:

1. 员工名称闪烁为数据库数字 ID(如 1000000001 )
2. 对话生成中切菜单再切回,出现白屏重渲染
3. Wiki 工作区切换后仍显示上一工作区内容
4. 登出后 keepAlive 缓存与模块级变量未清空,存在跨用户数据泄漏风险

### 改动内容

| 文件 | 改动 |
|------|------|
| `ChatConsole.vue` | 新增模块级 `cachedAgents` 缓存,组件重建首帧即有员工数据;启用 keepAlive,新增 `onActivated`/`onDeactivated` 生命周期管理,释放定时器/图表/监听器并自动重连流式对话 |
| `AgentPickerDialog.vue` | `isUnknown` 计算属性增加 `agents.length > 0` 守卫,列表未加载时走 placeholder 而非显示原始 ID |
| `router/index.ts` | `/chat` 路由添加 `keepAlive: true` |
| `MainLayout.vue` | 登出改为 `window.location.href` 整页刷新,确保清空 keepAlive 缓存与模块级变量 |
| `useWikiStore.ts` | `fetchKnowledgeBases` 检测 currentKB 不在新列表时调用 `backToLibrary` 清理旧工作区上下文 |
| `zh-CN.ts` / `en-US.ts` | 新增 `unknownAgent` 国际化键 |

### 测试

- 新增 `agentPickerLogic.test.ts`:覆盖 isUnknown 判定的 4 类边界场景(空值/正常匹配/列表为空/员工被删除)
- 新增 `wikiStoreWorkspaceSwitch.test.ts`:覆盖工作区切换清理逻辑(跨工作区清理/同工作区保留/首次进入/接口异常/组合路径)
- 前端全量测试:**58/58 通过**(原 40 + 新增 18)
- TypeScript 类型检查:通过
- 后端 Maven 测试:3473/3555 通过,9 失败均为预存 Windows 路径兼容问题,与本次改动无关

### 安全性

- 不同对话:`currentConversationId` 单一来源 + API 校验
- 不同账号:登出整页刷新,零残留
- 不同工作区:`router-view` key 重建 + wiki store 主动清理

---
2026-07-03 19:27:18 +08:00
matevip
bb946685b3 fix(chat): render generated-file download links with the file name, not the raw id URL (#466) 2026-07-03 14:34:35 +08:00
matevip
25737495e5 feat(chat): per-turn token usage breakdown with cache hit/miss/write and reasoning split (#474) 2026-07-03 11:28:00 +08:00
MIST
6741920446
fix(ui): 修复工具目录页面层级切换按钮文字溢出与比例失调 (#476)
### 问题
「设置 → 工具目录」页面中,核心工具 / 扩展工具表格操作列的「→ 扩展」「← 核心」文字按钮渲染异常:文字溢出按钮边界,与同行的编辑、删除图标按钮高度不一致,整体比例失调。

### 原因
该按钮同时挂载 .row-btn (30×30px 图标按钮)和 .tier-btn (文字按钮)两个 CSS 类。 .tier-btn 仅重置了 width: auto ,但未重置 height: 30px ,且缺少 line-height 和 hover 背景色,导致 12px 文字被压在 30px 矮盒内无法正常居中渲染。

### 修复
mateclaw-ui/src/views/Tools.vue — .tier-btn 样式:

属性 修复前 修复后 height 继承 30px (隐式,无声明) 30px (显式,与编辑/删除按钮统一) line-height 无 30px (文字垂直居中) hover background 无 var(--mc-bg-sunken) (hover 有视觉反馈)

### 影响范围
- 仅影响 Tools.vue 中 .tier-btn 的渲染样式
- 不涉及逻辑、API、后端代码
- 无需跑测试
2026-07-03 10:43:44 +08:00
matevip
b6d60cd946 fix(chat): drop stale workspace agentId from chat URL on remount (#465) 2026-07-02 17:35:17 +08:00
matevip
fa4e7018a0 feat(delegation): 本轮 token 总量页脚 + 子 Agent 用量向上滚加
- 新增 DelegatedUsageAccumulator:按根会话累加每个完成子 Agent 用量,根 Agent
  在 _usage_final 处一次性 drain 整棵子树、中间层得 0,每个子只计一次、无重复计数
- runSingleChild 增 accumulateToParent:同步/并行/计划步骤委派计入父轮,游离异步不计
- ReAct / Plan-Execute 在 _usage_final 处 drain 并加进 token + 附委派分解字段,
  doFinally 清理防泄漏;该事件同时驱动实时 SSE 与 mate_message 落库,实时/刷新一致
- 前端消息底部新增 Σ<total> tok 徽标(tooltip 含委派分解),总量仅取 message 用量
- 测试:补 DelegatedUsageAccumulator 接线,委派全套 59 绿
2026-06-30 17:21:10 +08:00
matevip
d390935763 feat(delegation): 子 Agent 成本透出 + 单任务/计划步骤委派结构化
- 子执行改走 chatWithUsage,捕获并透出每个子 Agent 的 prompt/completion token
  (单任务回复、并行机读头+逐行、delegation_end/child_complete/单路 broadcastEnd 事件)
- 新增 delegateByAgentIdStructured 返回结构化 ChildResult;计划步骤委派改按
  success()/isBlank() 判定成败,替掉脆弱的错误前缀匹配
- 前端委派段与嵌套节点显示紧凑成本后缀/徽标
- 测试:子执行 stub 迁移到 chatWithUsage + 新增 token 回归用例
2026-06-30 11:06:19 +08:00
matevip
db11433883 fix(settings/models): keep the model-discovery button visible before an API key is set 2026-06-30 10:09:04 +08:00
matevip
812daae0fc feat(wiki): search box to locate a node by name in the knowledge graph 2026-06-29 11:29:20 +08:00
matevip
4d0f9aa776 fix(agents): show a running plan's queued steps in the To Do column 2026-06-29 11:07:36 +08:00
mateaix
83660893a6 fix(chat): restrict generated-file link regex to http(s)/relative URLs
Follow-up to #447. The generated-file link extraction accepted any
non-')' text before the path, so a paren-free javascript:/data: URL
embedding /api/v1/files/generated/<id> could be captured and bound to an
<a href>, enabling XSS on click. Adopt the scheme-restricted pattern
already used by SegmentSupersedeDetector and the channel adapters, on
both backend (ChatController) and frontend (useChat). Also replace the
inline fully-qualified Pattern/Matcher with imports and drop an unused
run-overview i18n key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 16:25:11 +08:00
jack
3c6c765e51
feat(chat): surface generated-file artifacts in the run-overview rail
Extract generated-file download links from tool results — on the backend (persisted to message metadata for history) and on the frontend (live during SSE) — de-duplicate by URL, and render them as a Generated Files section with file-type icons and a rail badge.
2026-06-28 16:06:06 +08:00
倪程伟
fbbd1218e8
feat(wiki): KB processing-failure visibility (error-code chain + silent sub-step alerts + cross-KB failure center)
Propagates structured error codes through the KB processing pipeline, surfaces silent sub-step warnings as a non-failure warning state, and adds a cross-KB failure center for aggregated visibility.
2026-06-28 13:07:34 +08:00
倪程伟
7be8f81353
feat(agent): per-employee model-chain preference (provider + model, repeatable provider)
Lets an employee pin an ordered fallback chain of (provider, model) entries; the same provider may appear multiple times with different models. Build-time dedup keys on exact (provider, model).
2026-06-28 13:05:48 +08:00
倪程伟
e670bac3a8 fix(wiki): config tab auto-switches back to sources (#432)
Closes #431
2026-06-27 16:23:52 +08:00
倪程伟
1bce1fc1b9 fix(wiki): stop config tab from auto-switching back to sources
Two compounding causes made the management view jump from the config
tab back to 'raw' a few seconds after the user selected it:

1. The tab-snap watcher used a single getter returning a new array
   (`() => [currentKB?.id, workspaceMode]`). Vue compares the returned
   value with Object.is, so a fresh array reference reports a change on
   every re-evaluation — including background refreshCurrentKB() calls
   that reassign the KB object with the same id. That re-ran the snap and
   forced activeTab back to 'raw'. Switch to an array of getters so each
   source is compared individually and the callback fires only on a real
   id/mode change.

2. RawMaterialPanel's onBeforeUnmount cleared the SSE stream and the 60s
   fallback timer but not the per-raw jobPoller setTimeout chain. While a
   raw was still processing, leaving the sources tab left that 3s poller
   running, calling refreshCurrentKB() indefinitely. Clear jobPoller on
   unmount as well.
2026-06-27 00:08:17 +08:00
倪程伟
b426cffd48 fix(wiki): make processing-config tab scrollable so config cards are reachable (#429)
The config tab pane (.tab-content--config) was set to overflow:hidden,
mirroring the graph pane, but its inner .wiki-config has no bounded height
so its own overflow-y:auto never triggers. Tall config content (model
strategy / processing rules / search-preview cards) overflowed off-screen
with no scrollbar.

Switch the pane to overflow-y:auto like the generic .tab-content. The
existing <=980px media query (overflow:visible) keeps mobile page-scroll
intact. Pure CSS, no logic change.
2026-06-26 20:47:02 +08:00
matevip
d12e959add refactor(chat): replace external-project comment refs with functional descriptions
The chat composables (useStickToBottom / useStream / useMessages / useTyping)
carried '参考 @agentscope-ai/chat …' attribution comments. That package is not
a dependency and is never imported — the lines were pure citation. Rewrite them
as objective functional descriptions so shipped code does not name external
projects.
2026-06-26 17:04:06 +08:00
matevip
20b8b63320 fix(chat): fix type error and indentation in reconnect/scroll-lock change
- useChat.ts reconnectStream: cast the reused assistant message id to string
  when calling updateMessage; the id is optional in the Message type, so the
  raw value broke the vue-tsc build (TS2345, undefined not assignable).
- useStickToBottom.ts handleScroll: restore the block's indentation (it had
  drifted to 1/3-space) and add a comment for the scroll-up release branch.

Verified: vue-tsc --noEmit passes; snowflake precision check clean.
2026-06-26 16:56:59 +08:00
MIST
65f6a8c6b2
fix(chat): 修复滚动回弹和切会话消息异常两处核心bug,附加三项优化 (#425)
Bug 1 — 滚动条/触控板上滚后自动弹回底部
- useStickToBottom.ts: handleScroll 在 isScrolling 期间检测用户上滚方向,
  上滚时立即取消程序化滚动并设 escapedFromLock

Bug 2 — 切回生成中的会话显示"失败"且出现重复空气泡
- ChatConsole.vue: normalizeMessage 加 preserveGeneratingStatus 参数
- ChatConsole.vue: selectConversation 根据 conv.streamStatus 决定是否保留 generating
- ChatConsole.vue: 本地 reconnectStream 移除 isGenerating guard
- useChat.ts: reconnectStream guard 收窄为同会话+正在生成才跳过
- useChat.ts: reconnectStream 复用现有 generating/awaiting_approval 消息

优化1 — hydrateStateFromRoute 路径传 preserveGeneratingStatus=true
优化2 — useStickToBottom 新增 resetLock,MessageList defineExpose,
       selectConversation 切走时调用,避免上滚锁跨会话泄漏
优化3 — reconnect 复用 existingAsst 时清空 contentParts/segments,
       补充 _turnId 确保 flushSegmentsToMessage 正常写入
2026-06-26 16:55:17 +08:00
倪程伟
03a6d61131
feat(sso): 飞书 OAuth2 单点登录 (ISSUE #405 P0) (#419)
* feat(sso): feishu OAuth2 single sign-on (ISSUE #405 P0)

Implements the SSO design (ISSUE #405) with feishu as the first IdP
and a generic OAuth2 provider abstraction for future dingtalk/wecom
extensions. SSO is disabled by default — existing deployments are
unaffected until mateclaw.sso.enabled=true.

Backend:
- SsoProvider interface + SsoUserInfo record: generic IdP abstraction
- FeishuSsoProvider: OAuth2 authorization-code flow (app_access_token
  with Caffeine cache → user_access_token → user info). apiBase switches
  between feishu.cn / larksuite.com by domain config.
- SsoProviderRegistry: conditional registration, lists enabled providers
- SsoStateService: HMAC-signed OAuth2 state + self-contained bind_token
  JWT, both persisted to sso_state DB table for multi-node correctness.
  State is one-time-consumable (conditional UPDATE), bind_token jti
  anti-replay via PK insert. Hourly ShedLock purge (LambdaQuery + Java
  time, works on all 3 dialects).
- SsoService: authorize/callback/bind, user mapping (union_id first →
  external_id fallback), auto-create with concurrent idempotency
  (DuplicateKeyException → rollback orphan user → re-query), link-only
  mode issues bind_token for existing-account binding.
- SsoController: 4 endpoints (/providers, /authorize, /callback, /bind)
  all permitAll.
- V159 migration (h2/mysql/kingbase): mate_user_external_identity,
  sso_state, ALTER mate_user.password NULL (SSO-only users).
- AuthService: generateToken promoted to public; login() guards
  password=null (SSO-only users cannot password-login).
- SecurityConfig: /auth/sso/** added to permitAll whitelist.
- LoginRateLimitFilter: expanded to cover /auth/sso/bind (brute-force
  surface equivalent to /auth/login).
- application.yml: mateclaw.sso.* config block (all env-var driven).

Frontend:
- Login.vue: dynamic SSO buttons (only shown when providers configured),
  OAuth2 callback detection (?sso=callback), link-only bind dialog,
  shared applyLogin flow (localStorage + workspace + route).
- api/index.ts: ssoApi (providers, authorize, callback, bind).

Tests: SsoStateServiceTest (11) — state issue/verify/replay/tamper,
bind_token issue/verify/anti-replay/garbage. Regression: PAT (23) +
Approval resolve (13) all green.

Not in scope (P1/P2): link-only bind/unbind management endpoints,
user enable/disable endpoint, dingtalk/wecom providers, admin SSO
config page. Workspace assignment for auto-created users remains a
product decision (design doc §12 item 2).

* fix(sso): self-review fixes — P0 security + P1 quality

P0-1 BindRequired serialization: replaced the R.fail(200, Map.toString())
hack with a structured SsoCallbackResponse record. Controller no longer
catches an exception for a non-error path; frontend reads bindRequired
flag directly instead of regex-parsing a stringified map.

P0-2 createSsoUser unbounded recursion: added a retry flag — second
DuplicateKeyException (extreme race where identity was concurrently
deleted) now throws a 503 instead of recursing to stack overflow.

P0-3 state TTL not enforced: verifyState's conditional UPDATE now
includes created_at > cutoff, so a state unused for 5+ min is rejected
at consumption time, not just at the 1h purge. Without this the 5-min
window was advisory only.

P1-5 SsoStateService unused ObjectMapper: removed dead injection.

P1-6 audit JSON string concat: replaced with ObjectMapper serialization
(provider/externalId no longer risk breaking the JSON structure).

P1-7 LoginRateLimitFilter shared counter: documented the intentional
decision that login + bind share a per-IP counter (same brute-force
surface) with guidance on switching to per-path if finer isolation
is needed.
2026-06-26 10:00:31 +08:00
matevip
e4e7b4c377 fix(chat): suppress 403 console spam from polling unpersisted conversations (ISSUE #408) 2026-06-25 14:36:59 +08:00
MIST
f7f1c30557 feat(chat): floating back-to-bottom button with End-key shortcut
Add a floating back-to-bottom control to the chat message list that
appears when the user scrolls up away from the live bottom. The button
auto-docks to the right edge after 15s of inactivity (with a subtle
breathing pulse) and un-docks on mouseenter, keeping it unobtrusive
while reading history.

- End key jumps to the bottom, ignored when focus is in an input,
  textarea, or contentEditable field.
- Explicit jump (button click or End) forces past the stick-to-bottom
  escape lock and clears it so sticky auto-scroll resumes following new
  content; automatic scrolls still respect the escape lock so they do
  not fight the user reading history.
- Larger thumb-reach hit area and lower placement on mobile.
- New i18n key chat.scrollToBottom (zh-CN / en-US).
2026-06-25 09:44:43 +08:00
matevip
9013f5d780 refactor(dashboard): componentize operational export, restore DB chip, polish export dialog 2026-06-24 18:38:01 +08:00
matevip
9310335cc8 fix(operational): admin gate, atomic one-time download, lock safety and Excel ID precision 2026-06-24 17:48:42 +08:00
MIST
c2620720d2
feat(operational): one-click operational data export with 9-sheet Excel (#411)
Add an async export feature on the Dashboard page -- global admins can
generate and download a multi-sheet operational data report (.xlsx
packaged as .zip).  The export covers 9 sheets:

1. Overview - interval KPIs, system snapshot, 7-day trend, period comparison,
   model details (configured providers only), agent activity ranking top 10
2. Token Usage - daily breakdown by runtime_provider with avg tokens/msg
3. Skill Stats - skill list with usage count, last-call time, bound agents
4. User Stats - per-(workspace, user) aggregated tokens, duration, last active
5. User Conversations - detail rows pairing user-asst messages
6. Security and Audit - unified view across 6 sources (guard rules, audit logs,
   approvals, grants, config, business audit events)
7. Channel Stats - per-channel conversation count, tokens, unique users
8. Model Config - enabled plus API-key-configured models with parameters
9. Cron Jobs - execution records with duration and token usage

Backend highlights:
- generate/progress/download endpoints guarded by PreAuthorize hasRole ADMIN
- single AtomicBoolean lock (409 when busy), 90-day frontend cap, 5-min deadline
- metadata-based tool-call counting, deleted=0 filtering everywhere
- value label mapping (chat to dialogue, TRUE to enabled, etc.)
- one-time downloadToken, file auto-cleanup after 24h or download

Frontend highlights:
- SVG ring progress bar with smooth dashoffset transition plus slow rotation
- visibility gated by workspaceStore.isGlobalAdmin (v-if on button)
- 1-second polling driving progress state machine (idle/generating/done)
- Element Plus date-picker (30-day default, 90-day max)
2026-06-24 17:38:08 +08:00
matevip
93f40b6dac feat(chat): stabilize run overview rail with planning placeholder and responsive drawer 2026-06-24 17:13:31 +08:00
matevip
47dc5373d1 feat(chat): in-chat run overview side panel for live plan progress and sub-agent status 2026-06-24 15:53:58 +08:00
matevip
f08abad076 feat(skill): self-evolving skills — out-of-band reflection, curator consolidation, agent-authored skill files 2026-06-23 13:51:04 +08:00
matevip
a366c66d23 chore: bump version to 1.7.0-SNAPSHOT 2026-06-23 10:20:47 +08:00
matevip
5ff58b00ad fix(plans): scrub injected context from persisted plan goal (#402) 2026-06-22 17:54:27 +08:00
matevip
30252a377d feat(docs): structure the in-app help viewer to match the docs site 2026-06-22 17:28:35 +08:00
matevip
2cf08683a4 release: v1.6.0 2026-06-22 15:07:05 +08:00
matevip
eca4229751 feat(plans): per-step agent delegation + fix kanban pending column (issue #385) 2026-06-21 21:20:58 +08:00
matevip
1373b78b0a chore(repo): drop unused npm/yarn lockfiles and fix inline FQNs
- Remove mateclaw-ui/package-lock.json and yarn.lock. This is a pnpm
  monorepo where pnpm-lock.yaml is the only lockfile; the npm/yarn locks
  were stray duplicates. Add a .gitignore rule so they are not committed
  again by mistake.
- SourceEvidenceLedger: reference Pattern/Matcher by their imported
  simple names instead of inline fully-qualified names.
2026-06-21 10:06:28 +08:00
SuperCoderMan521
cb87569264 feat(wiki): make [n] citation markers clickable, linking to wiki pages (#305)
Backend (SourceEvidenceLedger):
- appendWikiSourceTable now normalizes existing source lines in-place to
  canonical "[N] Title - section - page N" format instead of skipping them
- Added replaceSourceLine helper that matches a full source line by regex
  and replaces it with the canonical form
- When source lines exist without a "来源:" header, automatically insert
  one so the frontend preprocessor can locate the source table

Frontend (useMarkdownRenderer):
- Added data-citation-index / data-citation-title to DOMPurify whitelist
- Added preprocessWikiCitations preprocessor: parses the canonical source
  table to build an index-to-title map, replaces [n] markers in the answer
  body with clickable <a> links, and wraps entire source-table rows so the
  full line is clickable
- Integrated into the render pipeline after wikilink substitution and
  before Marked parsing

Frontend (useGlobalWikilinkClick):
- Extended the click delegation selector to match both .wiki-link and
  .wiki-citation elements
- Title extraction falls back: data-citation-title || data-wiki-title

Tests: added three test cases for source-line normalization, idempotency,
and automatic header insertion
2026-06-21 09:58:41 +08:00