Commit Graph

394 Commits

Author SHA1 Message Date
倪程伟
a4f2980240 feat(channel): position webchat as Web/API access with optional agentId & multi-session sessionId
Rename the webchat channel from "embed widget" to "Web / API access" (key
unchanged, docs/i18n only) and extend the backend SSE endpoint for pure
backend integration:

- WebChatRequest gains optional agentId (route one Key to multiple agents;
  rejected unless the agent shares the channel's workspace) and sessionId
  (one visitor, multiple isolated threads).
- sessionId is validated ([A-Za-z0-9_-]{1,64}) and only composed into the
  server-derived conversationId — raw conversationIds are never accepted, so
  the key+visitor namespace still bounds every thread.
- A `meta` SSE event echoes the effective sessionId/conversationId at stream
  start so callers can persist and re-address a thread.
- Memory stays attributed per visitor (api:<visitorId>), shared across that
  visitor's sessions.

All new fields are optional; omitting them reproduces the prior behaviour
byte-for-byte. Refs matevip/mateclaw#295.
2026-06-09 09:29:01 +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
matevip
21798d6be5 fix(wiki): guard page reclassification against concurrent re-trigger
A second POST to /reclassify on the same KB spawned an independent pass over
the same pages, doubling LLM spend and racing the first pass's page-type
writes. Add a per-KB in-flight guard that rejects a concurrent run with a
friendly message (409 via R.fail rather than a generic 500), released in a
finally once the async pass completes. Also count and broadcast per-page
failures so an all-failing run is visible instead of reporting changed=0, and
type the api modelId param as string|number per the snowflake ID convention.
2026-06-08 21:59:39 +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
倪程伟
c7ae406dcc feat(ui): 数字员工标签改为芯片式编辑器
将编辑弹窗的标签输入从逗号分隔文本框改为芯片编辑器:每个标签独立
展示并带 × 删除,回车/空格/逗号(含全角「,」)添加,自动去重 + trim。
输入法选词态的回车不会误提交半成品;删除后提供 5 秒内联撤销。

form.tags 仍为逗号分隔字符串,后端零改动、API 契约不变。Closes #145.
2026-06-08 20:58:18 +08:00
倪程伟
9488634372 feat(agent): add tag filtering to the roster (#146)
Adds a tag filter bar to the agent roster, orthogonal to the existing
type/status tabs. Multi-select narrows by intersection (an agent must
carry every selected tag). Tags also render as clickable chips on each
agent card. The bar is hidden when no agent has tags.

Tags are de-duped per agent and ordered by usage frequency. When a
workspace has more than 12 distinct tags, only the top-N show inline and
a search box filters the rest; selected tags stay visible regardless.
2026-06-08 20:41:31 +08:00
matevip
3c87efdb15 feat(chat): 购物推荐结果渲染为可点击商品卡片
- 聊天 markdown 渲染器解析 product-cards 围栏为卡片网格(图片/价格/平台/去购买按钮),整卡可点跳购买页
- DOMPurify afterSanitizeAttributes 钩子补回被 ALLOWED_URI_REGEXP 剥掉的 target/referrerpolicy,确保防盗链图片加载与新标签打开
- 后端在购物推荐工具结果尾部追加卡片渲染指令,保证模型稳定输出卡片而非表格
- 技能:购物意图优先调用参考价工具并约定 product-cards 输出格式
2026-06-08 15:11:56 +08:00
matevip
5ebdccb1f6 feat(agent): scope agent knowledge base access to a bound subset (#261) 2026-06-07 22:41:14 +08:00
matevip
396a54440f fix(wiki): type scanResult.errors so the scan error list type-checks 2026-06-07 18:05:15 +08:00
倪程伟
d2e1f9eb9c feat(wiki): support multi-path and glob patterns for KB source directory
Allow knowledge base source paths to be configured as a newline-separated
list of absolute paths or glob patterns rather than a single directory.

- Each non-blank, non-# line is treated as one path or glob pattern
- Plain paths (no wildcards) retain the existing recursive-scan behaviour
  filtered by SUPPORTED_EXTENSIONS
- Glob patterns (e.g. /data/ocr/**/*.txt) walk from the fixed-prefix base
  and apply Java's PathMatcher against each candidate's absolute path
- Patterns whose filename segment explicitly specifies an extension
  (*.txt, *.{xlsx,csv}) skip the SUPPORTED_EXTENSIONS secondary filter,
  respecting the user's explicit choice (key for OCR pipelines that
  produce .txt output and should ignore the original PDF scans)
- Candidates collected across multiple patterns are deduplicated by
  resolved absolute path so overlapping patterns don't double-count
- Symlink-escape check uses each pattern's own validated scan root
- parseSourcePatterns / extractBasePath moved into WikiSourcePathValidator
  to eliminate a static circular reference between the two services
- Frontend watcher panel: single-line <input> replaced with <textarea>
  supporting multiline editing; i18n updated with example patterns
- No DB schema change; fully backward-compatible with existing single-path
  configs stored in sourceDirectory

Closes #(pending issue)
2026-06-07 18:05:04 +08:00
matevip
6c8283e77a fix(wiki): use index as key for scan error list to avoid duplicate-key warnings 2026-06-07 16:22:04 +08:00
倪程伟
29fcfb5572
fix(wiki): surface scan errors and fix Chinese path handling in Docker (#260)
Surface directory-scan failures to the user via toast and render ScanResult.errors[]; expose MATE_WIKI_ALLOWED_SOURCE_ROOTS as a Docker env entry with blank-entry filtering in the path validator; set C.UTF-8 locale in the runtime image so non-ASCII file names decode correctly during scans.

Fixes #259
2026-06-07 16:18:49 +08:00
matevip
808047d723 feat(proxy): global outbound HTTP/SOCKS proxy with settings page (#109)
Add a single global-proxy switch that routes the backend's outbound traffic
through a configured HTTP/HTTPS/SOCKS proxy, for deployments that cannot reach
overseas APIs directly or must use a unified egress.

- ProxyManager installs the proxy via a default ProxySelector (honored by
  java.net.http and HttpURLConnection), the proxy system properties, and a
  --proxy-server arg for the browser tool; restores direct egress when
  disabled. One switch covers LLM, web search, media generation, channels,
  MCP and the browser.
- SOCKS applies to the HttpURLConnection-based egress only; the java.net.http
  LLM/streaming path uses an HTTP proxy, and the UI states this.
- New Settings -> Network Proxy page: enable toggle, address, bypass list,
  test-connection, and a coverage summary. Config stored as key/value in
  mate_system_setting (no migration).

refs #109
2026-06-07 16:12:02 +08:00
matevip
478f169782 fix(goal): hide inline 'set a goal?' prompt once the stream shows a setGoal call 2026-06-03 21:19:27 +08:00
matevip
3883b68cca fix(goal): drop score gate, bill failed evaluator calls, fix Evaluator SPI + tool prompt + bootstrap cap 2026-06-03 21:19:27 +08:00
matevip
da332f2fd8 feat(goal): checklist UI — progress ring, hover checklist card, criteria SSE 2026-06-03 21:19:27 +08:00
matevip
c92bfa1f12 fix(mcp): raise default tool read timeout from 30s to 60s (#247) 2026-06-03 09:47:18 +08:00
matevip
bb2cf12f49 feat(chat): add execution-plan & tool-call detail viewer (closes #246) 2026-06-02 20:17:53 +08:00
matevip
9073c94de1 fix(ui): intercept generated-file downloads so failures never wedge the SPA (#243) 2026-06-01 20:21:21 +08:00
matevip
3fe1f65bef fix(wiki-ui): use the shared employee picker and 'employee' wording in pageType permissions 2026-05-31 08:00:13 +08:00
matevip
4cde845e27 feat(wiki-ui): advanced management panel for page types, layers, permissions, watcher and pipelines 2026-05-31 08:00:06 +08:00
matevip
f3e6e1152a feat(chat): add in-chat /skill slash menu with searchable picker 2026-05-29 08:10:22 +08:00
matevip
69bea272dd fix(memory-ui): escape < in <!-- user-edited literals to unblock vite dep-scan
Vite's dep pre-bundling runs esbuild's lite parser over .vue script blocks
to find imports. On esbuild 0.27.5 that parser interprets the
HTML-style sequence `<!--` inside a JS string/regex literal as the start
of a legacy line comment, which made it conflate two unrelated string
literals on lines 95 and 110 of MemoryBrowser.vue and report a fake
"Unterminated string literal" against a phantom line that doesn't exist
in the source.

Replacing the raw `<` with `\x3c` keeps the runtime behavior identical
(includes/regex match the same `<!-- user-edited` marker) but breaks the
HTML-comment heuristic so the scanner no longer chokes. The two call
sites — userEdited detection in parseSections and the strip regex in
stripMarker — both need the escape.

Repro: `pnpm dev` from a cold cache surfaces the error during dep scan,
runtime tests passed already because the actual JS parser handles the
strings fine.
2026-05-29 06:16:41 +08:00
lichuan
bd02734d61 feat(agent): add knowledge base binding tab to agent editor (#237)
Agents now have a per-agent primary wiki KB stored on
mate_agent.primary_kb_id. KBs remain workspace-shared — selecting one in
the agent editor only chooses the default wiki target for that agent, it
does not change the KB's ownership or visibility.

Backend
- AgentEntity: add primary_kb_id field (FieldStrategy.ALWAYS so the UI
  can clear it back to "no primary")
- AgentController#update: switch body to Map<String, Object> so we can
  tell "field missing" apart from "explicit null" via containsKey, then
  convertValue back to AgentEntity
- WikiKnowledgeBaseService:
  - new resolvePrimaryKb(agentId): prefers agent.primary_kb_id when it
    points to a workspace-visible KB; falls back to legacy
    kb.agent_id marker, then to most-recently-updated workspace KB
  - listByAgentId now returns the full workspace set (KBs are
    workspace-shared under the new model)
  - update(id, name, description) no longer touches agent_id
- WikiController: new GET /knowledge-bases/bindable for the UI picker;
  PUT /knowledge-bases/{id} no longer reads agentId
- WikiKnowledgeBaseEntity: add FieldStrategy.ALWAYS on embeddingModelId
  and configContent so explicit nulls actually unbind/clear instead of
  being silently skipped by MyBatis-Plus's NOT_NULL default
- Migrations V129 (H2 + MySQL): add primary_kb_id column + index, backfill
  from legacy kb.agent_id, MySQL uses INFORMATION_SCHEMA guard +
  PREPARE/EXECUTE for idempotency
- WikiKnowledgeBaseServiceTest: 13 cases, all passing

Frontend
- Agents.vue: new "Knowledge Base" tab, radio-select bindable KBs
- API: listBindableKBs() + Agent.primaryKbId typed string | number | null
- IDs handled as strings throughout (Snowflake-safe)
- i18n keys for the new tab in zh-CN and en-US
2026-05-29 06:00:52 +08:00
matevip
0ef735588a fix(wiki): 3 bugs caught by browser-driven chat e2e + 12-round trace 2026-05-28 10:55:30 +08:00
matevip
0e01b2b526 feat(wiki): chat-rendered wikilinks navigate via cross-KB lookup 2026-05-28 09:25:58 +08:00
matevip
16eac232c4 feat(wiki): cascade delete + rename to keep wikilinks consistent 2026-05-28 08:17:19 +08:00
matevip
2b3c068db9 feat(wiki): broken-link lint with job-based async scan 2026-05-28 08:17:04 +08:00
matevip
66d3d90ea9 feat(wiki): slug-first wikilink resolution and safe DOM postprocess 2026-05-28 08:16:56 +08:00
matevip
b81660a2a1 polish(approval-grants-ui): fix active-count pill + reuse mcConfirm for revoke 2026-05-27 15:54:47 +08:00
matevip
fe4f051672 polish(approval-grants-ui): pin the Actions column to the right edge 2026-05-27 15:09:18 +08:00
matevip
5f2adf15f6 polish(approval-grants-ui): show granter name, fix note cell rendering, tighten layout 2026-05-27 15:09:11 +08:00
matevip
b34de4e078 refactor(approval-grants-ui): strip Element Plus, reuse project list+pagination 2026-05-27 15:09:04 +08:00
matevip
6a754f5bfa refactor(approval-grants-ui): rebuild create dialog to match ToolGuard pattern 2026-05-27 15:08:56 +08:00
matevip
b9c5ec03d4 refactor(approval-grants-ui): header aligned with project conventions 2026-05-27 15:08:49 +08:00
matevip
65cf53779a refactor(approval-grants-ui): paginated list, Element Plus icons, shorter sidebar label 2026-05-27 15:08:41 +08:00
matevip
2f5e06f286 fix(approval): three minor issues surfaced by end-to-end testing 2026-05-27 14:08:12 +08:00
matevip
f15b2dced3 feat(ui): auto-approve banner dropdown, management page, and workspace chip 2026-05-27 14:08:04 +08:00
matevip
f163c0b5bc feat(ui): rewrite chat welcome subtitle and suggestions around agent capabilities 2026-05-27 06:58:52 +08:00
matevip
0ac325a337 feat(agent): explicit "no skills / no tools" opt-out flags (#184) 2026-05-26 22:07:12 +08:00
matevip
3ae4498f38 fix(channel,agent,chat): unify channel binding / conversation agent / model pin state sources 2026-05-26 09:40:49 +08:00
matevip
9e9a96f674 fix(agent): resolve relative workspaceBasePath under workspace root 2026-05-25 15:58:05 +08:00
倪程伟
cbdd70379b
feat(agent): optional agent-level workspace basePath override (#212)
* feat(agent): optional agent-level workspace basePath override

Add workspaceBasePath field to AgentEntity that optionally overrides
the workspace-level basePath. When set, the agent uses its own directory;
when null, it inherits the workspace's basePath (existing behavior).

- AgentEntity: new workspaceBasePath field with ALWAYS update strategy
- AgentGraphBuilder: agent-level override takes priority over workspace
- Flyway migration V121 for H2 and MySQL
- UI: form input in basic tab with i18n (zh-CN, en-US)

* fix(agent): rename migration V121→V125 to avoid Flyway conflict with upstream

Upstream already has V121__tool_disclosure_tier.sql. Rename our
migration to V125 (next available after V124).

* fix(agent): make MySQL V125 migration idempotent

Use INFORMATION_SCHEMA check before ADD COLUMN to avoid
"Duplicate column name" error on re-deploy.
2026-05-25 15:42:01 +08:00
matevip
3fc121c6b7 fix(tool): show runtime names in tools admin 2026-05-23 22:54:57 +08:00
matevip
cef1730e6e feat(tool,skill,ui): progressive tool/skill disclosure (load_skill + enable_tool + tier UI) 2026-05-23 09:07:45 +08:00
matevip
26bf75fd2f fix(ui): stop chat content clipping in a narrow message column 2026-05-22 14:09:18 +08:00
matevip
5f571e86a2 feat(agent,ui): multi-level subagent delegation tree 2026-05-22 13:44:01 +08:00