Commit Graph

57 Commits

Author SHA1 Message Date
matevip
ceb4da642b fix(memory): rebuild agent on workspace file change so memory edits apply 2026-05-29 16:05:21 +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
05289e6bdb feat(agent): per-conversation progress ledger to survive context trims 2026-05-24 23:00:03 +08:00
matevip
a9c2d45790 Harden goal approval and workspace flows 2026-05-23 22:55:16 +08:00
matevip
9e93c52d9a fix(goal): real evaluator, retry refactor, hardened node + extra edges 2026-05-21 22:27:00 +08:00
matevip
2d3afa6550 feat(sessions): paginate admin list, add back-nav, redesign with depth 2026-05-20 20:58:05 +08:00
matevip
82540a5fcb docs(conversation): bilingualize ConversationService comments (en/zh) 2026-05-20 20:57:53 +08:00
matevip
6a4318c268 fix(channel): IM conversations respect per-conversation model selection (#183) 2026-05-20 17:49:03 +08:00
matevip
32d633ae4b fix(workspace): verify a path-bound agent belongs to the request workspace 2026-05-19 20:07:02 +08:00
matevip
0a57cb3358 fix(workspace): harden workspace create and delete 2026-05-19 20:06:44 +08:00
matevip
d53d66abe3 feat(chat): per-conversation model selection (#150) 2026-05-18 16:27:27 +08:00
matevip
401c413a77 fix(chat): return 403 not 500 for conversation access failures 2026-05-17 17:55:21 +08:00
matevip
7fb47390af feat(chat): pin, multi-select delete and agent filter for conversations (#144) 2026-05-17 09:25:02 +08:00
matevip
f56f4b059a fix(workspace): reject impossible calendar dates in memory snapshot import 2026-05-16 14:51:52 +08:00
matevip
725fdd1e0f feat(workspace): memory snapshot export and import with whitelist 2026-05-16 14:51:25 +08:00
matevip
b9c0ead024 feat(workspace): keyword search across agent memory files 2026-05-16 14:51:09 +08:00
matevip
9fc2e5f04f feat(memory,dashboard,channel,cron): raise read endpoints out of viewer 2026-05-15 10:18:20 +08:00
matevip
3ba22b99f3 feat(workspace,system): add @RequireGlobalAdmin and gate admin-only controllers 2026-05-15 10:18:10 +08:00
matevip
f4964bc6d8 feat(workspace): return memberRole on list and add access endpoint 2026-05-15 10:17:49 +08:00
matevip
af56763156 fix(context): keep the latest summary even when its row sits outside the recent window; include summaryId in compact_status 2026-05-13 08:50:42 +08:00
matevip
faf7f98358 feat(context): consume compact_status on the frontend; load history from latest boundary; backfill summaryId 2026-05-13 08:50:35 +08:00
matevip
51b5eceb7d feat(context): preserve spill markers across compaction phases, persist enriched boundary, broadcast compact_status SSE (#110) 2026-05-13 08:50:28 +08:00
matevip
86a6829102 feat(executor): retention sweep and per-conversation purge for tool-result spill files 2026-05-13 08:50:22 +08:00
matevip
97e2b12f71 feat(chat): show reply model attribution in assistant message bubbles 2026-05-09 16:41:18 +08:00
matevip
f3b1cba6dc fix(conversation): render image/video/audio attachment markers for LLM (#66) 2026-05-08 15:03:42 +08:00
matevip
96840b0126 chore: bump version to 1.3.0-SNAPSHOT 2026-05-08 15:02:08 +08:00
matevip
023f0cfb06 fix(conversation): render image/video/audio attachment markers for LLM (#66) 2026-05-07 17:13:17 +08:00
matevip
bf8a533b19 fix(approval): clear in-memory pendingMap on conversation delete via domain event 2026-05-06 16:45:23 +08:00
matevip
73d69c1dfe fix(conversation): cascade-clean orphan rows on conversation delete 2026-05-06 16:45:16 +08:00
matevip
2ab0bd000b fix(chat): suppress duplicate assistant row on force-recycle 2026-05-05 10:39:54 +08:00
matevip
28c3b0e62f feat(model3d): Tencent Hunyuan 3D provider — Pro/Rapid action routing + <model-viewer> preview 2026-05-01 22:39:13 +08:00
matevip
977e181949 feat(cron): unify output, add reminder task type, in-flight progress UI
Three layers landed together because they share the same routing /
lifecycle plumbing:

1. Cron output unification
   - New CronConversationResolver routes web-origin jobs to the per-workspace
     tasks_<wsId> conversation; IM-bound jobs go to the channel session
     conversation when one exists (matched by senderId then targetId);
     legacy cron_<id> remains as the fallback.
   - CronJobLifecycleService inserts a system-role header divider when a
     run starts so users browsing the unified tasks_<wsId> view can tell
     which job started a run. BaseAgent.sanitizeForLlm filters these
     headers so they never reach the model.
   - WorkspaceService seeds tasks_<wsId> on workspace creation; V65
     migration backfills existing workspaces.
   - DeliveryConfig gains a userId field so IM session lookup can match
     by senderId (replyToken-based targetId is not stable across runs).
   - ConversationVO recognizes tasks_/cron_ underscore prefix as cron
     source. MessageList renders the system header as a labeled divider.
   - ChatConsole pins tasks_* conversations and tracks per-conversation
     read state so new cron output gets a visible unread dot.

2. Reminder task type
   - New task_type='reminder' in CronJobEntity + service validation.
   - CronJobRunner short-circuits 'reminder' jobs: hands trigger_message
     to finishRunAndPublish verbatim, no LLM call. Fixes a regression
     where reminders were rephrased into echoed wrappers.
   - New create_reminder tool alongside create_cron_job, with descriptions
     tightened so the model picks the right one (verbatim push vs LLM
     query that needs computation).
   - CronJobs.vue gets a third radio option + dedicated reminder field.

3. In-flight progress placeholder
   - Cron uses non-streaming chat()/execute(); tool-heavy ReAct loops
     can run 1-5 minutes between start and finish with no visible
     state, looking hung.
   - New GET /api/v1/cron-jobs/active-runs returns runs in status=running
     for a conversation. ChatConsole polls it on the existing 4s tick
     (and on conversation switch) and shows a spinner bar with elapsed
     time. When run count drops to zero, it refetches messages so the
     assistant bubble appears within ~1s of finish.
2026-04-30 15:01:24 +08:00
matevip
0ecfec474e fix(conversation): tolerate non-path-safe ids when cleaning attachments (issue #36) 2026-04-29 15:07:36 +08:00
matevip
709a0db200 fix(chat): surface stored path for uploaded attachments
Chat attachments with non-ASCII filenames (e.g. Chinese) get sanitized
at upload time — `人人有虾.docx` is stored as `1777391026594_____.docx`.
Tools then receive only the original filename via '[Attachment] foo.docx'
and fail with 'file not found'.

- renderMessageContent now appends the actual server-side path so any
  tool the LLM picks (read_file / extract_document_text /
  detect_file_type) gets a path that resolves directly.
- New ChatUploadResolver helper performs basename-suffix matching inside
  the conversation's chat-upload directory; ReadFileTool, DocumentExtractTool
  and FileTypeDetectorTool fall through to it when the literal path does
  not exist (defense in depth for cases where the LLM ignores the path
  hint).

Refs https://github.com/matevip/mateclaw/issues/29
2026-04-28 23:59:27 +08:00
matevip
ae820f0f94 fix(workspace): make default-workspace owner bootstrap first-run-only
Replace the per-startup admin reconciliation in
WorkspaceSchemaMigration.ensureDefaultWorkspaceMembership() with a
one-shot bootstrap. Once the default workspace has any owner, the
method returns immediately, so an operator's deliberate removal of an
admin from the default workspace persists across restarts. If no owner
exists yet, pick the lowest-id active admin and add them as owner; if
no admin exists at all, log a warning and skip rather than failing
startup.

Refs https://github.com/matevip/mateclaw/issues/29
2026-04-28 23:41:56 +08:00
matevip
a73b640c87 fix(workspace): scope default workspace backfill to admins only
Restart-time backfill in WorkspaceSchemaMigration was inserting every
existing user into the default workspace and copying mate_user.role
('user'/'admin') into mate_workspace_member.role, whose valid domain is
{owner, admin, member, viewer}. Result: non-admin users assigned to
other workspaces were silently re-attached to the default workspace
with role='user', failing roleLevel() lookup and 403'ing on Agents.

- Filter the INSERT on u.role = 'admin' and hard-code the membership
  role to 'owner', removing the role-domain mismatch and the
  workspace-isolation violation in one change.
- Add V60__fix_invalid_workspace_member_roles.sql (h2 + mysql) to
  drop already-corrupted default-workspace rows for users who have a
  valid membership elsewhere, and downgrade the orphan rows to
  'member' so those users aren't locked out entirely.

Refs https://github.com/matevip/mateclaw/issues/29
2026-04-28 23:40:21 +08:00
matevip
e64752a830 fix(approval): unify tool-approval state machine across DB / message metadata / memory
- Reconcile approval status atomically: DB row, message metadata, in-memory store
- Approve and deny both flip the tool-call card + timeline segment to a terminal
  state on the gate message — no more orange spinner stuck after a decision
- Frontend hydrate matches by pendingId and reverse-converges to expired so a
  refresh after server-side timeout / consume clears the banner without restart
- Stop sweep, GC timeout, and JVM restart all close the loop with consistent
  state
- Remove the dead REST /approve endpoint + matching frontend client export so
  there is only one resolve path to maintain
2026-04-27 22:25:27 +08:00
matevip
03c8584910 fix(channels): resolve issue #19 — non-admin member errors on channel page
Three bugs surfaced when a non-admin workspace member opened the channel
admin page:

- vue-i18n "Invalid linked format" when '@' appeared in message strings
  without the linked-format escape. Replaced literal '@' with vue-i18n v9
  literal interpolation {'@'} in both zh-CN.ts and en-US.ts (6 strings:
  QQ guide step3, accessControl requireMention/Tooltip).

- 403 from WorkspaceAccessInterceptor was being treated as 401 by the
  axios interceptor and the chat SSE handler, clearing the token and
  redirecting to /login. Split the two:
    * 401 = authentication failure  -> handleAuthFailure (logout)
    * 403 = authorization failure   -> keep session, surface to caller
  Now a member who lacks workspace permission sees a toast instead of
  being silently logged out.

- Two backend exception sites threw with the default code=500 for what
  is semantically an auth/authz event, contradicting the codes returned
  elsewhere for the same business event:
    * AuthService.login() bad credentials  500 -> 401
    * WorkspaceService.requirePermission() 500 -> 403
  This aligns service-layer denials with SecurityConfig (401 for missing
  JWT) and WorkspaceAccessInterceptor (403 for permission denied), so
  the same business event always produces the same code.
2026-04-27 19:31:46 +08:00
matevip
2f93d53737 refactor(approval): unify state machine across DB/metadata/memory
Foundation for the ghost-approval root-cause fix.

Adds ResolveOutcome / MetadataDecision; rewrites ApprovalWorkflowService so
every resolve / consume / timeout / supersede transitions through one
two-phase contract: snapshot → DB UPDATE conditional on status=PENDING →
metadata reconciliation → afterCommit memory mutation. ChatController,
ChannelMessageRouter, and ApprovalController all switch to the workflow;
ApprovalService.resolve / resolveAndConsume / consumeApproved /
cancelStalePending / denyAllByConversation are physically removed so
DB-bypass is no longer reachable at compile time.

Specific fixes:
- recoverFromDb preserves DB pendingId + createdAt (was generating fresh
  random ids, breaking every later DB sync)
- effectiveExpireAt = expireAt ?? createdAt + PENDING_TTL: legacy rows
  with NULL expireAt no longer resurrect as live PENDING after restart
- markPendingApprovalsResolved flips pendingApproval.status + currentPhase
  + MessageEntity.status atomically (was only flipping the first field;
  message.status uses existing completed/stopped, not approved/denied,
  to stay within the frontend Message.status union)
- GC scheduler moves to ApprovalWorkflowService; timeouts and overflow
  evictions now sync DB + metadata + memory through markTimeout
- DB UPDATE rows=0 returns alreadyResolved (concurrent-resolve safe);
  exception propagates so @Transactional rolls back; memory stays untouched
- expireRecoveredRow gates metadata write on DB success (was writing
  metadata even when DB update failed, producing the worst-case ghost)
- Mockito JDK 21 agent attach fixed via maven-dependency-plugin properties
  + surefire argLine (no more flaky self-attach across machines)

Tests: 34 new across 4 classes (recovery, resolve, GC, metadata sync).
Full suite: 788 / 788.
2026-04-27 19:30:52 +08:00
matevip
349f4d7d3c refactor(bootstrap): drop legacy tools-sync.sql in favor of per-tool Flyway migrations
The two tools-sync scripts ran on every startup and used H2 MERGE INTO
... KEY(id), which overwrites every column on existing rows. That
silently reverted UI-toggled `enabled` and was the proximate cause of
a recent WriteFileTool/EditFileTool outage.

They were also a strict subset of the fresh-install seed (data-zh.sql /
data-en.sql register all 19 builtins; the sync scripts only 16) and out
of date. Per-tool Flyway migrations (V3, V31) are already the canonical
'register a new builtin' path, so the sync layer was duplicated and
error-prone.

Delete both files and the runToolSyncScript() loader. Tool descriptions
shown to the LLM come from @Tool annotations in code, not the DB row,
so removing per-startup metadata refresh has no functional impact.
2026-04-27 14:00:08 +08:00
matevip
bc002fd302 fix(delegate): address P2 review findings for multi-agent delegation 2026-04-22 10:12:52 +08:00
matevip
11fa7487d0 fix(delegate): reliability patches for multi-agent delegation 2026-04-22 10:12:48 +08:00
matevip
639d1c80d4 fix(delegate): address P2 review findings for multi-agent delegation 2026-04-22 05:08:15 +08:00
matevip
8762a79ec9 fix(delegate): reliability patches for multi-agent delegation 2026-04-22 05:08:08 +08:00
matevip
762218cd32 refactor(db): drop @TableLogic on all entities, purge soft-deleted rows 2026-04-18 23:31:48 +08:00
matevip
8fbe30d7ac feat(auth): password change dialog + workspace member provisioning improvements 2026-04-17 00:11:10 +08:00
matevip
80b7b8e126 feat(agent): multi-agent delegation with parallel execution (RFC-004) 2026-04-12 23:40:27 +08:00
matevip
af9addaaec feat(i18n): structured i18n keys for exceptions and auto-translate 100+ error messages 2026-04-11 17:52:25 +08:00
matevip
cc28f665f1 feat(db): introduce Flyway migration framework and unify H2/MySQL schemas
- Add Flyway baseline migration (V1) for both H2 and MySQL
- Remove 5 legacy SchemaMigration ApplicationRunner classes
- Add WorkspacePathGuard for file tool sandbox enforcement
- Inject workspace basePath context into agent graph state and tool executor
- Add workspace basePath config UI in frontend
- Fix workspace slug preservation on update
2026-04-11 16:34:09 +08:00
matevip
367dd4bed0 fix(agent): preserve per-subtask results in multi-task answer synthesis, add listAvailableSkills tool 2026-04-10 17:10:02 +08:00