Commit Graph

347 Commits

Author SHA1 Message Date
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
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
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
倪程伟
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
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
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
30252a377d feat(docs): structure the in-app help viewer to match the docs site 2026-06-22 17:28:35 +08:00
matevip
c656aff349 feat(plans): Kanban boards in the Agents workspace
Live lifecycle board (grid<->board toggle) plus an assignee-swimlane plan
board that groups follow-up re-runs of one goal into a single xN card.
Custom right-side detail/goal panels with markdown output. Fixes plans
being persisted under the per-run trace id so the board actually populates.

Closes #385
2026-06-20 17:52:29 +08:00
倪程伟
22a212a2e6 feat(agent): add wiki_disabled opt-out flag for knowledge bases
Issue #304. Operators who want an agent with NO knowledge base had no
way to express it: leaving the KB picker empty fell through to "inherit
workspace-wide" (every KB visible), so the agent ended up ingesting
every KB's context. This adds the same opt-out toggle that
skills_disabled (V126) / tools_disabled already provide.

Backend:
- V154 migration (h2 + mysql + kingbase): mate_agent.wiki_disabled
  BOOLEAN/TINYINT/SMALLINT NOT NULL DEFAULT FALSE. Legacy agents stay
  bit-identical.
- AgentEntity.wikiDisabled: Boolean field, @TableField("wiki_disabled").
- AgentBindingService.getBoundKbIds: short-circuit at the top —
  wiki_disabled=true returns Set.of() regardless of binding rows. Mirrors
  the precedence contract of getBoundSkillIds vs skills_disabled.
- AgentBindingService.setKbBindings: a non-empty save auto-clears a
  stale wiki_disabled flag (same contract as setSkillBindings /
  setToolBindings on their respective flags). Empty saves leave the flag
  untouched — the UI toggle owns the bit, not the binding writer.
- AgentBindingServiceWikiDisabledTest: 5 cases covering all three
  return states + the stale-flag auto-clear + empty-save no-op.

Frontend:
- Agents.vue KB picker: add the "此智能体不使用任何知识库" /
  "This agent uses no knowledge bases" toggle, mirroring the skills /
  tools picker layout. Tab badge shows "Off" when the toggle is on.
- types/index.ts: add Agent.wikiDisabled?: boolean.
- Save logic: when wikiDisabled is on, send an empty KB list (the
  setKbs contract then leaves the flag alone server-side, exactly as
  setSkills / setTools behave for their opt-out flags).
- i18n (zh + en): new strings for toggle label, hint, badge, and the
  scope description shown when the toggle is on.

Stacked on top of #382 (which introduced AgentBindingResolver
.getBoundKbIds). No agent-runtime changes — wiki tools already degrade
cleanly when getBoundKbIds returns Set.of().
2026-06-20 07:21:07 +08:00
matevip
4804954ad2 feat(wiki): configurable entity types, type legend filter & theme-aligned graph colors (#336)
- per-KB entity-type whitelist (config UI + persistence; empty = built-in defaults)
- entity graph: legend grouped by type with click-to-filter; nodes colored by type
- always show entity names on graph nodes (not only on hover)
- earthy categorical palette aligned to the app theme, shared by entity & page graphs
- theme-aware graph label color (resolve CSS var for canvas, light/dark correct)
- manual extract = full rebuild: idempotent force re-extraction + orphan pruning,
  guarded against data loss on a fully-failed run
- regression test for force re-extraction; zh/en i18n
2026-06-19 07:18:09 +08:00
matevip
1522009aec feat(agent): one-sentence AI employee creation wizard
Turn a single natural-language requirement into a ready-to-review
employee: the model proposes name, persona, runtime type and a
validated set of skills/tools/knowledge base, which the user confirms
or tweaks before the agent is created.

- backend: POST /api/v1/agents/generate builds a draft from the
  workspace's real capability catalog; every suggested tool/skill/KB is
  re-validated against the catalog so nothing hallucinated is offered
- frontend: 3-step wizard at /agents/create reusing the existing
  create + binding endpoints; reusable capability picker shows selected
  items as compact chips with an on-demand searchable catalog
2026-06-17 17:38:42 +08:00
matevip
6e7c137154 feat(wiki): entity-level knowledge graph extraction (#336)
Add an opt-in named-entity extraction pass so the wiki knowledge graph
captures fine-grained entities (people, organizations, locations, ...)
and their relations, not just page-level link relations.

- new tables mate_wiki_entity / _mention / _relation (h2/mysql/kingbase)
- structured LLM extraction per chunk with entity resolution
  (normalized-key dedup + embedding near-merge), mention/relation
  persistence and page linking via chunk citations
- per-KB opt-in toggle (off by default); async dispatch after embedding
- read API: entity list, KB graph, entity ego-graph, manual extract
- UI: entity-layer toggle in the graph view + KB config toggle
- replace inline fully-qualified class names with imports in WikiProcessingService

Closes #336
2026-06-17 14:17:54 +08:00
matevip
1affbd7b82 feat(agent): loop-engineering robustness — goal continuation, plan re-plan, stall detection
- goal: continue (not skip) on max-iterations and evidence-insufficient turns.
  A max-iterations turn grants a fresh iteration budget ("hard continuation"),
  bounded per run and sized into the graph recursion ceiling, so a task too big
  for one budget keeps going instead of stalling until the next user message.
- plan-execute: re-plan the remaining work on a step exception, and on a
  signature-based stall (repeated failures / identical results / no usable
  result) instead of advancing dependent steps with junk; bounded by a per-run
  re-plan cap, with a graduated change-strategy nudge before the hard stop.
- plan-execute: auto-derive a goal from a genuine multi-step plan, seeding the
  acceptance criteria from the plan steps, so the goal subsystem engages without
  the model calling setGoal; broadcast goal_created so the UI hydrates.
- react: refund the iteration for setup-only rounds (load_skill / enable_tool)
  so a tight budget is not eaten by the load-then-use two-step.
- ui: re-fetch the active goal when a turn finishes so a goal created or mutated
  mid-conversation surfaces without depending on an SSE event.
- streaming: make retry backoff / total-time budget instance fields with a
  test-only seam; clarify that the wall-clock budget (not max-retries) bounds a
  sustained SERVER_ERROR loop to ~8 attempts, fixing the slow/flaky retry test.
2026-06-17 06:37:08 +08:00
matevip
d9a9d07704 fix(wiki): broken-link rescan precision, slug/title resolution, and dangling-link reconcile (#333)
- rescan: keep the KB id as a string end to end so the 19-digit snowflake id
  isn't truncated past Number.MAX_SAFE_INTEGER (rescan no longer 404s)
- lint: resolve [[...]] targets against page slugs AND titles like the viewer,
  so a title reference to an existing page is no longer reported broken
- ingest: derive the slug deterministically from the title (no inconsistent
  romanization), auto-recompute broken links once a KB finishes importing,
  and reconcile dangling [[concept]] links — redirect to the covering page via
  declared aliases, or demote to plain text when uncovered
- add the page aliases column migration for h2 / mysql / kingbase
2026-06-15 16:14:25 +08:00
matevip
4cbd2b50f3 feat(dashboard): show the connected database on the dashboard
Surface the connected database product as a subtle chip in the Dashboard
header. SystemHealthService now reports a database label on /system/health
(reused by the front-end — no extra request), derived from a new
DatabaseBootstrapRunner.getDatabaseLabel() that reads the JDBC product name
once and normalizes it to a canonical label (MySQL / MariaDB / PostgreSQL /
H2, and 人大金仓 for the KingbaseES family), collapsing driver version noise.
2026-06-15 08:47:53 +08:00
倪程伟
7c4380a116
feat(docs): expose bundled help docs via in-app viewer
Closes #330
2026-06-15 07:48:49 +08:00
matevip
ac035d6d99 style(wiki): replace related-page signal emoji with Element Plus icons 2026-06-13 07:29:39 +08:00
matevip
4b6e0b2e0e fix(wiki): keep the open knowledge base and page in the URL 2026-06-13 07:29:39 +08:00
matevip
ec4bb9061c fix(wiki): align read-only reading-toggle label with the unified Sources tab
The raw-materials surface was renamed to "Sources" when upload, paste,
directory scan and per-KB auto-sync were unified into one tab. The read-only
viewers' reading-toggle segment still carried the old "Raw materials" label,
so managers saw "Sources" while read-only viewers saw "Raw materials" for the
same panel. Point the segment at the same i18n key for a consistent name.
2026-06-11 09:31:41 +08:00
倪程伟
18daad79b2
feat(wiki): unify raw materials & source watcher into a Sources tab with per-KB auto-sync (#316)
* feat(wiki): unify raw materials & source watcher into a Sources tab with per-KB auto-sync

The raw-material directory scan and the Advanced "source watcher" sub-tab were
the same engine (same kb.sourceDirectory, same WikiDirectoryScanService) split
across two surfaces with two editable directory inputs. Merge them into one
"Sources" tab (upload / paste / directory manual scan + auto-sync toggle +
the raw-material list) and drop the watcher sub-tab from Advanced.

Auto-sync is now per-KB opt-in: a new watcher_enabled column (V146) gates the
periodic scan per knowledge base. The server-global mate.wiki.watcher-enabled
stays as an ops master switch — a KB is auto-scanned only when both are on
(AND). Manual scans are unaffected. Scan interval stays global for now
(tracked separately).

Closes matevip/mateclaw#314

* docs(wiki): document source-watcher global switch env vars

Expose MATE_WIKI_WATCHER_ENABLED / MATE_WIKI_WATCHER_INTERVAL_MS as
explicit placeholders in application-mysql.yml, .env.example and
docker-compose.yml, mirroring MATE_WIKI_ALLOWED_SOURCE_ROOTS. Notes the
AND semantics (global ops gate + per-KB toggle) so operators know the
global switch alone is not sufficient.
2026-06-11 09:29:26 +08:00
matevip
92d401bc1f fix(wiki): keep raw-materials & recent-activity readable for read-only viewers
The KB workspace split into a reading view (pages + graph) and a manage view
(raw materials, config, transformations, advanced, recent-activity snapshot)
gated behind manage:wiki. That moved the raw-materials and recent-activity
surfaces — which read-only viewers (view:wiki without manage:wiki) could
previously browse — entirely behind the management gate, silently dropping
their access.

Re-surface both in the reading-view segmented toggle for viewers who lack a
management view. Managers keep the focused pages/graph toggle and still reach
these surfaces through the management view, so nothing is duplicated for them.
The content panels already render by activeTab, so this only widens the
reading toggle and the activeTab/readingTab types.
2026-06-10 17:48:01 +08:00
倪程伟
8da01432da
feat(wiki): add guided form editor for pageType profile (JSON kept as review) (#311)
The pageType profile could only be edited as a raw JSON string. Add a
structured form editor (default) that builds the profile without writing JSON:
profile-level settings (fallbackType / allowAdditionalFields), an ordered page
type list (add via a small wizard, remove, reorder), and a per-type form for
label / description / layer / field schema, with stage prompts (route/create/
merge) and the markdown template folded into an "advanced" section that carries
inline descriptions and examples. A form/JSON toggle keeps the JSON view as the
final review surface; serialization preserves unknown keys for forward-compat,
and save/validate/reset reuse the existing endpoints (no backend change).

Closes matevip/mateclaw#310
2026-06-10 13:42:02 +08:00
倪程伟
347e42b795
feat(wiki): split KB management vs reading into separate workspace views (#309)
The KB workspace previously stacked all seven surfaces in one tab strip.
Split them by intent: a gear on each library card opens the management view
(raw materials, config, transformations, advanced, hot cache), while clicking
the card body opens the reading view (pages + graph). The reading view drives
page/graph via a header segmented control with the page tree shown only for
the page viewer; the two views share loaded data and toggle without refetch.

Closes matevip/mateclaw#308
2026-06-10 13:40:57 +08:00
matevip
fb93f99425 fix(chat): 工具框乱序 + 流式/调试开关失效 + 思考堆积修复 2026-06-09 16:04:41 +08:00
matevip
64b8e167d5 fix(mcp): refresh agent cache on MCP connection change + non-blocking connect (#289)
Closes #289 — after an MCP server (re)connects, chat queries kept replying
"from memory" instead of calling MCP tools.

Root cause: agents snapshot their tool set at build time and are cached in
AgentService.agentInstances, but MCP server lifecycle changes never
invalidated that cache (unlike model-config / tool-guard changes which do).
A stale, tool-less agent graph survived until process restart.

Changes:
- Add McpServerChangedEvent; McpServerService publishes it on connect /
  disconnect / reconnect / delete / (re)connect-failure / batch refresh /
  startup init. AgentService listens and calls refreshAllAgents(), so the
  next turn rebuilds against the live MCP tool set. Also closes the boot
  race where the web server accepts requests before the @Order(200) MCP
  init runner finishes.
- Make create/update/toggle connect asynchronously on a dedicated pool
  ("mcp-connect") so a slow/unreachable server can no longer freeze the
  admin request; status returns immediately as "connecting".
- UI: render the new "connecting" status (pulsing amber dot), show a
  friendly "connecting in background" toast, and poll until the status
  settles (window widened to ~40s to outlast the default connect timeout).
- UI: MCP config modal no longer closes on outside/backdrop click — only
  the × and Cancel buttons close it, so an accidental click can't discard
  unsaved config.

Verified E2E: ckjia-shopping (参考价) MCP server connected at runtime with
no backend restart; the cached 通用助手 agent immediately enabled and called
ckjia_shopping_recommend, returning real product cards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 14:14:08 +08:00
matevip
a9cf3cbd55 fix(llm): show all enabled chat models in multimodal sidecar selector
The vision/video sidecar dropdown filtered candidates through the built-in
capability heuristics, so provider-compatible models whose custom names match
no known prefix (and carry no declared modalities) were hidden and could not be
selected as a sidecar — even when they natively support the modality.

- listByType now returns every enabled chat model, annotating each row with a
  transient modalityCapable flag and sorting known-capable rows first, instead
  of hard-filtering recognized models only.
- MultimodalRouter honours an explicitly configured sidecar model instead of
  dropping it when the heuristics don't recognize it; a wrong pick degrades
  gracefully through the caption path rather than silently disabling routing.
- ModelPicker gains an optional capability badge; the sidecar UI tags
  recognized vision models while keeping every enabled model selectable.
2026-06-09 10:30:37 +08:00
matevip
b95ee90c64 fix(wiki,agent): tidy up post-merge review nits
- WikiPageTypeProfile: normalise pageType keys to lowercase on set, so a
  user-authored profile with an uppercase key still matches the
  case-insensitive hasPageType/get lookups.
- WikiDirectoryScanService: normalise the symlink-resolved glob base to
  forward slashes so directory-scan globs work on Windows paths.
- Agents roster tag filter: keep selected tags that no longer exist on any
  agent visible and deselectable (and show the filter bar when only such
  orphan selections remain) instead of silently filtering with no way to clear.
2026-06-08 22:48:53 +08:00
倪程伟
e3ddea9a70 feat(wiki): reclassify existing pages against the current pageType profile
Add a backfill path so pages created before a KB's pageType profile changed
can be migrated into newly-added types. A per-page classify-only LLM call
(title + summary in, single page_type out) is normalised through the profile
and written back via a partial update that never touches page content.

Exposed as POST /knowledge-bases/{id}/reclassify (admin) and a "re-classify
existing pages" action in the Wiki advanced panel.
2026-06-08 21:04:24 +08:00
倪程伟
28f2ba973d feat(wiki): honour KB pageType profile in transformations, agent pages & UI
Wiki page classification was only profile-aware in the main ingest pipeline.
Transformation outputs hard-coded "synthesis", agent-created pages were left
untyped, and the frontend hard-coded the built-in ten types for ordering,
colouring and labels — so custom/synthesis types sank to the bottom, rendered
grey and showed raw keys.

Backend:
- Add nullable target_page_type column to mate_wiki_transformation (V142,
  mysql + h2) plus the entity field and CRUD normalization (blank = use
  profile fallbackType; membership validated at save time, not edit time).
- Route transformation single-run + KB-aggregate page saves through
  WikiPageTypeProfileService.normalizePageType so output joins the KB
  classification; agent wiki_create_page now lands on the profile fallbackType
  instead of an untyped page.

Frontend:
- Load + parse the KB pageType profile into the wiki store (order, labels,
  fallbackType) on KB select / refresh.
- New useWikiPageType composable: profile-driven label (3-tier fallback) and
  colour (built-in fixed + deterministic hash palette for custom types).
- Sidebar grouping order, graph colouring, node panel, graph filter and the
  page header badge now follow the profile; transformation editor gains a
  target-type dropdown sourced from the profile when output target is a page.

Refs #292
2026-06-08 21:02:50 +08:00
倪程伟
da5aaba0f7 feat(agents): open AGENTS.md editor in a modal, as a settings row, with section reordering
Move the AGENTS.md section editing into a click-to-open modal so the Basic
tab no longer expands the full document inline. Present the entry as a
settings-style row (title + description on the left, a "manage" button on the
right) instead of stacked label/hint/button.

Add optional move-up/move-down controls to MemorySection (off by default, so
MemoryBrowser is unaffected) and wire reordering in AgentGuideEditor: adjacent
sections swap and the whole file is re-saved, with a synthetic preamble pinned
to the top.
2026-06-08 21:00:07 +08:00
倪程伟
4f11a444c1 feat(agents): manage AGENTS.md from the agent editor + clarify context-file roles
Add a friendly AGENTS.md section editor inside the edit-agent modal's
"高级" (Advanced) collapsible, alongside the existing additional-instructions
field. New AgentGuideEditor reuses MemorySection cards, parses the file into
## sections, and saves whole-file via the workspace API (no backend change).
Empty files offer a "create" scaffold flow.

Reword the collapsible to a generic "高级" and add a role-clarifying note that
fixes the boundary: factory identity goes in the form fields, evolving
memory/rules go in the context files. Also fix the additional-instructions
textarea so it fills the form width.

Closes matevip/mateclaw#290
2026-06-08 21:00:07 +08:00