Commit Graph

1393 Commits

Author SHA1 Message Date
倪程伟
8e339f083a docs(security): correct generated-file TTL comment (7 days, not 10 min)
The permitAll comment claimed a 10-minute TTL, but GeneratedFileCache.TTL
is 7 days. The stale figure could mislead future security reasoning about
how long an unauthenticated capability URL stays live. Align the comment
with the actual value; the unguessable UUID remains the access guard.

Refs matevip/mateclaw#344
2026-06-17 23:21:08 +08:00
倪程伟
7f4c62c3d6 fix(conversation): surface webchat visitor sessions in the admin console
WebChat conversations are owned by an external visitor principal
(webchat:<visitorId>) so each visitor's threads stay isolated for the
self-service session API. But the console list/page/owner-check only
recognized the current user + system owners, so these conversations were
invisible in the sidebar and the Sessions page — and would 403 on open
even if surfaced.

Treat webchat: owners like system owners for the console: include them in
the lenient list/page queries and in isConversationOwner. The strict
listConversations overload (used by the visitor self-service path) is
unchanged, so a visitor's own access is not widened.

Refs matevip/mateclaw#340
2026-06-17 23:21:08 +08:00
倪程伟
981c3d56d9 fix(channels): don't gate webchat creation on auto-generated API Key
The Web/API (webchat) onboarding wizard marked api_key as required while
it is also readOnly and platform-generated on save. The readOnly field
could never be filled during creation, so canSubmitConfig never passed
and "Continue" stayed disabled.

Exclude readOnly fields from the wizard's required/optional field sets so
they neither gate "Continue" nor render as fillable inputs. The api_key
still appears as required + readOnly in the edit modal once a value
exists.

Refs matevip/mateclaw#338
2026-06-17 23:21:08 +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
fe68f22aa8 feat(memory): bound always-on memory growth with injection budget, consolidation, and file ceilings
Always-on memory (structured user/feedback blocks, PROFILE.md, MEMORY.md) is injected into every system prompt but only ever grew, inflating per-turn context over time. This adds deterministic size control across all always-on sources:

- Injection budget: cap the always-on structured block by total chars and per-type entry count, keeping the most-recently-updated entries (LRU by Updated date) and disclosing how many were omitted
- Nightly consolidation: a dedicated scheduled pass merges duplicate/stale user & feedback entries via the LLM, preserving each entry's original Updated date; runs per owner bucket (shared + personal) with a per-run cap and a never-grow safety guard
- File ceilings: deterministic backstop truncates PROFILE.md / MEMORY.md at a section boundary when a rewrite overruns its budget
- Manual trigger endpoint for the consolidation maintenance task

All knobs under mate.memory.*; covered by unit tests.
2026-06-17 11:04:19 +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
85ceafa055 fix(agent): scope KB grounding to wiki-equipped agents and wiki tools
The knowledge-base trust verification recorded wiki citations from every
non-readFile tool response by sniffing its JSON for a top-level title /
pages / chunks field. Tools like getGoalStatus return a top-level title,
which falsely populated the citation set and then forced [n] citations on
the final answer (otherwise flagged EVIDENCE_INSUFFICIENT). Gate citation
mining on the wiki_* tool name instead.

Likewise, the grounded answer contract (cite-or-refuse) was appended to
every ReasoningNode call unconditionally, degrading general agents that
have no knowledge base. Append it only when the agent has a wiki_* tool
bound, scoping the strict regime to KB-grounded scenarios.

Adds a regression test asserting a non-wiki tool with a top-level title
creates no wiki citations.
2026-06-16 07:48:04 +08:00
jack
88be1f748a
[#305] [Feature] Add knowledge base trust verification (#334)
Co-authored-by: SuperCoderMan521 <SuperCoderManqq.com>
2026-06-16 07:47:04 +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
6a13cc2f50 perf(chat): throttle streaming markdown render and defer chart mounts
- add useStreamingMarkdown: cap mid-stream markdown re-render to ~140ms,
  full-fidelity render once the segment completes
- skip code-block language auto-detection while streaming (escaped plain
  text), restore full highlighting on the final render
- defer echarts/mermaid blocks to a lightweight loading placeholder while
  streaming so their parsers never run on truncated source
- bypass the render cache for streaming-mode output
- wire into ContentSegment and MessageBubble (content + thinking)
2026-06-15 11:39:24 +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
matevip
710b756281 test(chat): cover gateway-resilience error classification; fix PKIX casing
Add ErrorClassificationTest regression cases for the AI-gateway retry
hardening: 5xx-before-4xx ordering (a proxy 502 whose body says
"bad request" stays retryable), Chinese / numeric provider billing
patterns, and DNS / TLS infrastructure-fatal detection.

Fix the cert-trust pattern while adding its test: Java's ValidatorException
emits "PKIX path building failed" with an uppercase PKIX and the error
chain is not lower-cased, so the previous lowercase pattern never matched
— an untrusted/expired cert chain fell through to the retryable
SERVER_ERROR bucket and was retried in vain instead of failing over.
2026-06-15 08:09:59 +08:00
MIST
42f1d5b685 fix(chat): resilient retry for transient AI gateway errors 2026-06-15 08:02:02 +08:00
倪程伟
7c4380a116
feat(docs): expose bundled help docs via in-app viewer
Closes #330
2026-06-15 07:48:49 +08:00
matevip
a0eba17688 fix(db): keep Integer-mapped wiki flag columns as SMALLINT in the PostgreSQL-family tree
The blanket SMALLINT->BOOLEAN flag-column conversion over-reached: six wiki
columns map to Integer (1/0) entity fields, not Boolean. On vanilla PostgreSQL,
reading a BOOLEAN into a JDBC int throws 'Bad value for type int : f', breaking
every wiki KB list / SSE chat. Revert only those six back to SMALLINT (V133/V134/
V135/V136/V146 in the PostgreSQL-family tree) with guard comments; genuine
Boolean-entity columns stay BOOLEAN.
2026-06-15 07:37:04 +08:00
matevip
839cb2c1ba docs(readme): refresh roadmap — v1.4.0/v1.5.0 shipped, v1.6.0 in progress (en + zh) 2026-06-14 20:06:37 +08:00
matevip
e28e5c8377 chore(deps): upgrade Spring Boot to 3.5.15 and Spring AI to 1.1.8
Spring AI Alibaba stays at 1.1.2.3 (already the latest released version).
2026-06-14 20:03:12 +08:00
matevip
6bebfed07c fix(feishu): surface recent-file disk-scan failures at warn level
The disk fallback's catch block logged at debug, so a failed scan
silently dropped recovered files — reproducing the same 'bot can't see
the file' symptom the fallback was added to fix. Promote to warn with
the full stack trace, matching cacheRecentFile's logging.
2026-06-14 17:25:26 +08:00
倪程伟
f361e0e917 fix: reuse shared HttpClient to prevent thread-leak OOM on model test
openAiCompatibleClientBuilder() was creating a new java.net.http.HttpClient
per request. Each instance spawns a selector thread and connection pool that
are never closed, exhausting the OS thread limit under frequent model-test
calls (e.g. DeepSeek provider).

Elevate the HttpClient to a static singleton so all OpenAI-compatible
provider requests share one connection pool and one selector thread.

Closes matevip/mateclaw#328
2026-06-14 16:57:13 +08:00
倪程伟
515cba88ee test(feishu): add TTL filter and unit tests for recent-file disk fallback
loadRecentFilesFromDisk now filters out files older than RECENT_FILE_TTL_MINUTES
(60 min) so the disk fallback matches the Caffeine cache TTL and does not inject
stale attachments into future conversations.

Testability refactoring:
- recentFileCache: private → package-private (tests can seed the cache directly)
- chatUploadsRoot: new package-private Path field (tests redirect to @TempDir)
- loadRecentFilesFromDisk: add (Path dir, long cutoffMs) package-private overload;
  private (String) wrapper delegates to it
- injectRecentFiles: private → package-private

New test class FeishuRecentFileCacheTest (14 cases):
- loadRecentFilesFromDisk: non-existent dir, empty dir, fresh files sorted
  newest-first, stale files excluded by TTL, mixed fresh+stale, >5 files capped,
  timestamp-prefix stripping, MIME guessing from extension
- injectRecentFiles: Caffeine cache hit, cache-miss disk fallback, empty disk,
  duplicate-path dedup, image vs file part typing, null textContent guard

Relates to #325
2026-06-14 16:57:13 +08:00
倪程伟
39a55db65f fix(feishu): recover recent files from disk when in-memory cache misses
The per-chat recent file cache (Caffeine, 60 min TTL) is purely
in-memory.  After a process restart, GC eviction, or TTL expiry the
cache is empty, but the staged copies under data/chat-uploads/ survive
on disk.  A follow-up text message that should have seen the cached file
instead found nothing — the bot replied as if no file was ever sent.

Changes:
- injectRecentFiles(): fall back to scanning data/chat-uploads/{id}/
  when the Caffeine cache misses, sorted by last-modified time, capped
  at RECENT_FILE_MAX_PER_CHAT (5).
- cacheRecentFile(): promote catch log from debug → warn with full
  stack trace so silent download failures are visible in production
  logs.  Add entry-level info log for correlation.
- New helper loadRecentFilesFromDisk() + guessContentType().

Closes #325
Relates to #201
2026-06-14 16:57:13 +08:00
matevip
32ad11d6c4 fix(db): cover remaining boolean columns (ALTER-added and primitive-boolean) 2026-06-14 16:47:38 +08:00
matevip
1ac1df12bf fix(db): store JSON columns as TEXT in the PostgreSQL-family tree 2026-06-14 16:47:31 +08:00
matevip
f3119e0217 fix(db): declare boolean flag columns as BOOLEAN in the PostgreSQL-family tree 2026-06-14 16:47:23 +08:00
matevip
1887dd3f70 fix(docker): honor SPRING_PROFILES_ACTIVE instead of pinning the mysql profile 2026-06-14 16:47:16 +08:00
matevip
5685b09fd2 docs(release): add v1.6.0 release notes (changelog index mirror) 2026-06-14 16:47:09 +08:00
matevip
07da1d610b feat(db): add PostgreSQL Spring profile 2026-06-14 16:47:02 +08:00
matevip
d7418e49df fix(db): make the PostgreSQL-family SQL portable to vanilla PostgreSQL 2026-06-14 16:46:25 +08:00
matevip
ed6eac310a fix(cron): restore ShedLock DB-time for dialects that support it
The KingbaseES change removed usingDbTime() unconditionally, which made
every deployment (MySQL/H2/PostgreSQL) fall back to app-server time for
distributed lock timing — reintroducing node clock-drift risk in
multi-instance setups. Re-enable usingDbTime() for databases in ShedLock's
built-in dialect map and skip it only for KingbaseES, which is not covered
and would otherwise throw at lock acquisition.
2026-06-14 10:44:52 +08:00
matevip
25a83ad858 fix(db): make KingbaseES driver opt-in and restore default SSRF guard
The KingbaseES JDBC driver is not on Maven Central; declaring it as a
required runtime dependency broke the default build for anyone without
the proprietary jar. Move it into an opt-in `kingbase` Maven profile
(build with `mvn package -Pkingbase`). No Java code imports the driver
classes — it is loaded at runtime via driver-class-name only, so the
default build no longer needs it.

Also drop `mateclaw.browser.ssrf-check-enabled: false` from the default
application.yml: the code default is true, and disabling the SSRF guard
globally is unrelated to KingbaseES support.
2026-06-14 10:34:35 +08:00
铭萱
446f34b6b5
feat(db): support KingbaseES (人大金仓) domestic database (#324)
Add KingbaseES support as an opt-in profile: dedicated migration tree, bilingual seed data, runtime DbType detection (KINGBASE_ES / POSTGRE_SQL), and JDBC URL handling in the datasource manager.
2026-06-14 10:30:09 +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
936c8621ed fix(wiki): extract uploaded documents via a sandbox-exempt path (#323) 2026-06-13 07:29:39 +08:00
matevip
48024e4a83 fix(wiki): dedup pages by title and bound route prompt growth (#321) 2026-06-12 15:17:32 +08:00
matevip
c1691e466c fix(agent): stop ProgressLedger from pinning virtual-thread carriers under parallel progress_update 2026-06-12 11:07:55 +08:00
matevip
e6f8da9606 fix(agent): recover tool-call follow-up on interleaved-thinking models (#256) 2026-06-12 11:07:55 +08:00
matevip
5235e30138 fix(tool): keep Snowflake ids precise across the tool boundary (#319) 2026-06-11 15:17:51 +08:00
matevip
bad216d686 feat(tool): add image_analyze for on-demand image re-analysis (#303) 2026-06-11 13:53:56 +08:00
matevip
aaf06b262c feat(agent): retain image context across turns for follow-ups (#303) 2026-06-11 13:53:56 +08:00
matevip
dfc8e4c786 fix(channel): warn when wecom inbound image is stored URL-only (#303) 2026-06-11 13:53:56 +08:00
matevip
4a3d4cf568 fix(mcp): auto-heal stale MCP connections after server restart (#317) 2026-06-11 09:59:25 +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
matevip
83615593cd fix(tool/guard): harden workspace filesystem sandbox (#313)
- Fail closed to a global fallback sandbox root when a conversation has no
  per-workspace base path, instead of leaving file/shell tools unconstrained
- Refuse shell commands that delete the workspace root directory itself
- Block workspace-boundary escapes at the policy layer before the approval
  prompt, not only at execution time
- Approval bar now shows the actual command / target path being approved
2026-06-10 17:17:07 +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
7478491652 feat(llm): add Claude Fable 5 support 2026-06-10 10:14:51 +08:00