Commit Graph

48 Commits

Author SHA1 Message Date
matevip
57a459602e fix(ui): clipboard copy fails in non-HTTPS context 2026-05-08 15:08:27 +08:00
matevip
96840b0126 chore: bump version to 1.3.0-SNAPSHOT 2026-05-08 15:02:08 +08:00
lambert
a92f76ff87
fix(ui): clipboard copy fails in non-HTTPS context
Use textarea + execCommand fallback when navigator.clipboard is unavailable. Consolidates 5 call sites into a single helper.
2026-05-08 10:23:58 +08:00
matevip
42d406ffc8 fix(agent): drop brittle output policing, add evidence-grounded long-task safeguards 2026-05-04 11:55:44 +08:00
matevip
7d02841d1d fix(chat): per-event SSE ids for safe reconnect dedup + queue race recovery 2026-05-03 19:57:06 +08:00
matevip
66f09a968a feat(chat-stream): streaming UX overhaul + multi-agent stability layer 2026-05-03 17:15:02 +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
e3ab06d57c feat(generative): unified async pipeline + live SSE delivery for music/video/image 2026-05-01 20:15:20 +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
6a3df2a6e0 feat(llm): enabled column for providers + Add Provider drawer
Adds explicit user-intent gating to the provider catalog. Fresh installs
get an empty dropdown by default — built-in cloud + local providers
(OpenAI, Anthropic, Ollama, LM Studio, MLX, llama.cpp, etc.) live in a
new 'Add Provider' drawer until the user opts them in. Existing installs
upgrade conservatively: V55 promotes any provider with evidence of use
(real api_key, OAuth token, recent chat usage, or current default model).

Backend
- V55 migration (H2 + MySQL): adds enabled BOOLEAN DEFAULT FALSE on
  mate_model_provider, plus 4 promote-to-true UPDATE rules. Also
  CREATE INDEX idx_message_runtime_provider_time so the 30-day usage
  lookup doesn't full-scan mate_message on heavy users.
- ModelProviderEntity, ProviderInfoDTO: enabled field.
- ModelProviderService:
    * listProviders() now filters WHERE enabled = TRUE — chat path,
      ModelSelector, Settings/Models main grid see only opted-in rows.
    * listCatalog() new — full catalog (enabled + disabled) for the drawer.
    * setEnabled(id, enabled) flips the flag, publishes
      ModelConfigChangedEvent (re-probe via the existing listener), and
      on disable auto-promotes a replacement default model when the
      disabled provider owned the current default. Returns EnableResult
      so the frontend can fire a toast.
    * createCustomProvider sets enabled=true (user just made the row).
- ProviderInitProbe.listConfiguredProviders also filters enabled=true —
  no point probing rows the user can't see.
- ModelConfigController: GET /catalog, POST /{id}/enable, POST /{id}/disable.
- Plugin-registered ChatModels are unaffected — they live in
  pluginChatModels (in-memory map), don't go through DB listProviders,
  so the enabled filter doesn't strand them.

Frontend
- New types: ProviderInfo.enabled, EnableResult.
- New API: catalog / enableProvider / disableProvider.
- New composable useProviderEnablement: catalog ref, drawerOpen,
  togglingId, loadCatalog, openDrawer / closeDrawer, enableProvider,
  disableProvider (fires defaultSwitchedToast on auto-switch).
- AddProviderDrawer.vue: lazy-loaded, reuses DoctorDrawer's Teleport +
  overlay + slide-in panel pattern. Two groups (cloud / local),
  unenabled rows surface to the top of each group, enabled rows show
  an 'Enabled' badge instead of a button. Mobile: full-screen sheet
  that slides up from below.
- ProviderCard: new 'Disable' button with soft-danger styling on
  enabled providers — soft-hide that keeps the config; user can
  re-enable from the drawer.
- Settings/Models index.vue:
    * Two top CTAs: 'Enable Provider' (drawer) and 'Custom' (existing
      custom-create modal) — distinct workflows, both surfaced.
    * Empty state with prominent 'Enable Provider' CTA when zero
      enabled providers — paired with onMounted auto-open of the
      drawer (sessionStorage guard so closing it doesn't bring it
      back on the next route visit in the same session).
    * Deep-link: ?addProvider=1 query forces the drawer open and
      strips itself after, so a back/forward doesn't re-fire the open.
- ModelSelector: when groups.length === 0 and not searching, show
  'No providers configured -> Configure' CTA linking to
  /settings/models?addProvider=1 — the natural flow when a fresh
  user opens chat before configuring anything.
- i18n: 13 new keys per locale (zh-CN + en-US) plus common.close.

Migration safety
- Conservative default policy: only rows with concrete evidence of
  use are auto-enabled; everything else stays hidden. Upgrade users
  may notice unused built-ins disappearing from their dropdown —
  that's the intended cleanup.
- mate_message index added so the 30-day usage rule doesn't full-scan
  on large installations; FlywayRepairConfig handles redeploy idempotency.

Tests
- ModelProviderServiceEnableTest covers all 7 enable/disable branches:
  flag flip + event publish, no-op on already-{enabled,disabled},
  default-switch when disabled provider owned current default,
  no-switch when default belongs elsewhere, no-replacement returns
  unchanged, getDefaultModel exception path, candidates with no
  models are skipped.
- ProviderInitProbeTest: helper provider() now sets enabled=true so
  the new probe filter doesn't strand existing fixtures.
- vip.mate.llm.** suite: 125 tests green. vue-tsc 0 errors. Browser
  page renders with both new buttons + drawer.
2026-04-28 15:03:40 +08:00
matevip
c0c642380a feat(llm): provider liveness model + honor requireApiKey on chat path
Phase 1 of the model-module refactor: combine pool / cooldown / probe-
completion signals into a single Liveness state surfaced through the
provider DTO, so the dropdown stops listing providers that are provably
unreachable. Zero schema change; one PR backend + frontend.

Backend
- Liveness enum with five mutually-exclusive states: LIVE, COOLDOWN,
  REMOVED, UNPROBED, UNCONFIGURED. Computed in ModelProviderService
  from AvailableProviderPool / ProviderHealthTracker / ProviderInitProbe
  snapshots batched once per listProviders() call.
- ProviderInitProbe.hasBeenProbed exposes a monotonic Set so the UI
  can distinguish 'still booting' from 'probed and removed' — without
  it the startup window flashes false REMOVED states.
- ProviderInfoDTO gains liveness + unavailableReason +
  cooldownRemainingMs + lastProbedAtMs. The legacy 'available' boolean
  stays but is now derived from liveness == LIVE so the chat fallback
  walker and the dropdown agree about what's usable.
- ProviderInitProbe injected into ModelProviderService via
  ObjectProvider to break the startup cycle (probe already depends on
  the service).

Frontend
- ProviderInfo type extended with liveness + the three detail fields.
- ModelSelector filters UNCONFIGURED + REMOVED out of the dropdown,
  shows COOLDOWN / UNPROBED with a status dot and dimmed rows that the
  user can still click to override.
- ProviderCard renders a five-state badge driven by liveness instead
  of the old configured + pool-entry combo. Reprobe button now keys
  off liveness in {REMOVED, COOLDOWN}.
- useProviders drops loadProviderPool / providerPool — pool data ships
  inline on each ProviderInfo, saves a round trip per page load and
  keeps a single source of truth.
- i18n: 8 new keys across zh-CN and en-US for liveness labels and the
  cooldown countdown tooltips.

Bonus fix (discovered during verification): AgentGraphBuilder.buildOpenAiApi
hard-required a usable API key on every OpenAI-compat provider, ignoring
the per-provider requireApiKey flag. That bug stranded keyless local
runtimes (LM Studio / MLX / llama.cpp) the moment a user actually
launched them; Ollama only worked by accident because its seed row
carries a placeholder string in api_key. keyRequired now honors
requireApiKey, and Spring AI's NoopApiKey is used when no key is needed
so the Authorization header is omitted entirely.

Test
- ModelProviderServiceLivenessTest covers all five Liveness states +
  the probe-bean-absent fallback branch.
- vip.mate.llm.** suite (118 tests) green; vue-tsc clean.
- End-to-end browser sanity: 27 raw providers reduce to 6 LIVE groups
  in the chat dropdown; LM Studio / MLX / llama.cpp render REMOVED red
  badges with reprobe buttons; cloud providers without keys show
  UNCONFIGURED.
2026-04-28 14:59:11 +08:00
matevip
4e22b85557 fix(chat): surface SSE error in retry card and stop poll from wiping local-only failed turn
When SSE setup fails (e.g. workspace permission denied for shared channel
conversations opened from the web console), the failed turn is never
persisted on the backend. Two issues made the failure invisible to the user:

- The fallback errorInfo dropped data.message, so the inline retry card fell
  back to the generic "请求过程中遇到了意外问题" template instead of the
  actual reason. Carry rawMessage through, and lower the MessageBubble
  display threshold from >8 to >3 chars so short-but-informative messages
  (7-char Chinese / "Forbidden") aren't filtered out.

- The status-poll loop in useChat overwrote the local-only failed turn
  with the server's "no message" view, erasing the inline retry card.
  Skip the merge for turns that exist only locally and are in error state,
  so the user can still see the failure and retry.
2026-04-28 00:16:14 +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
fa5eaf83b4 fix(ui): code-block light-mode theme + cap header height at 38px 2026-04-26 19:09:10 +08:00
matevip
e2df16893e fix(wiki): smaller batch-create + resume button for partial generation 2026-04-26 18:42:27 +08:00
matevip
b7c911f01d feat(stt): DashScope realtime voice + language-aware routing + TalkMode polish
- DashScope paraformer-realtime-v2 WebSocket streaming
- Language-aware provider routing: Whisper for English, Paraformer for Chinese
- PCM WAV recording replaces WebM (provider filename bug + diagnostics)
- TalkMode push-to-talk fixes (audio drop, WS connecting race)
- Vite dev proxy WebSocket upgrade fix
- WebSocket binary buffer 8KB → 8MB (Tomcat default truncated voice clips)
- Audio chunk pacing at 100ms (DashScope returned 0 chars otherwise)
- Resolved language hint propagation + raw frame logging
- V46 seed idempotency fix on UI-toggled STT row
- Diagnostic cleanup after debugging session
2026-04-26 16:37:55 +08:00
matevip
5c98d1120e feat(ui): gray out thinking depth button on unsupported models 2026-04-24 18:16:23 +08:00
matevip
27c4c3e5e2 feat(wiki): config UI overhaul — model strategy, search preview modal, graph fullscreen 2026-04-24 10:03:45 +08:00
matevip
2e15369465 fix(delegate): fix parallel timeout + add real-time per-child visibility 2026-04-23 08:09:48 +08:00
matevip
95dd500a16 feat(ui): localize tool call display via useToolLabel 2026-04-23 08:09:37 +08:00
matevip
8762a79ec9 fix(delegate): reliability patches for multi-agent delegation 2026-04-22 05:08:08 +08:00
matevip
980b16109d feat(ui): plain-text user messages with 8-line auto-collapse
Pasted prompts (test cases, structured asks, JSON dumps) currently render
through the same markdown pipeline as assistant output, so '#'/'-'/'**'
characters are processed and long prompts dominate the scrollback.

- New UserMessageContent.vue: plain-text rendering (white-space: pre-wrap
  preserves user-typed newlines and indentation), with auto-collapse beyond
  8 lines and a "Show more (N more lines) / Show less" toggle. Soft mask
  gradient at the collapse boundary instead of a hard cut.
- MessageBubble.vue: route role==='user' messages through the new component;
  assistant messages keep the existing markdown pipeline unchanged.
- Add chat.expandLines / chat.collapse i18n keys (zh + en).

Verified end-to-end in browser preview: 15-line content collapses to 8,
toggle expands to full 15 with "Show less" label, raw '#' / '**' / '`' chars
shown literally with no <strong>/<h1>/<li> tags emitted.
2026-04-19 09:06:14 +08:00
matevip
7221d36bab fix: mysql migration compatibility + ollama tool-support gating + actionable error UI
- db/migration/mysql: replace ADD COLUMN/CREATE INDEX IF NOT EXISTS with
  idempotent checks via information_schema (MySQL 8.0 <8.0.29 and some
  forks don't support IF NOT EXISTS for ADD COLUMN). Affects V2/V4/V5/V7
  /V8/V9/V11/V12/V13/V14. Fix: gitee#IIYHLJ.
- application-mysql.yml: add createDatabaseIfNotExist=true so MySQL
  Connector/J auto-creates the schema on first connection (requires
  CREATE privilege — documented fallback for restricted accounts).
- llm/OllamaAutoDiscoveryRunner: rewrite seed tag when fuzzy-matching,
  prefer exact tag for default; skip models without tool support when
  auto-activating a default (prevents the phantom ':latest' trap when
  users pulled a specific size).
- agent/graph/NodeStreamingChatHelper: detect 'does not support tools'
  and 'model not found' errors from Ollama and emit actionable Chinese
  prompts guiding users to qwen3 / qwen2.5:7b+ / llama3.1:8b+ etc.
- ui/MessageBubble + types/chatError: surface the backend's actionable
  rawMessage in the failed-message card instead of a generic '未知错误';
  strip redundant prefixes (Bad request: / [错误] / LLM 调用失败:) since
  the title already conveys the category.
2026-04-17 11:17:27 +08:00
matevip
46f77c281b fix(agent): complete RFC-001 — Anthropic thinking, iteration budget, UI fixes 2026-04-12 17:28:15 +08:00
matevip
2a8b90365b feat(agent): add deep thinking toggle (RFC-001) 2026-04-12 11:29:32 +08:00
matevip
379422101c refactor(ui): minimalist login redesign, MCP fixes, Flyway upgrade compatibility 2026-04-11 23:01:08 +08:00
matevip
81ff1bf491 feat(i18n): complete backend i18n — guard rules, tool errors, response codes 2026-04-11 17:26:58 +08:00
matevip
e662cce91a fix(chat): improve thinking segment display and message bubble rendering 2026-04-11 17:09:25 +08:00
matevip
f98f4d68b9 refactor(ui): publish tested chat UI simplification 2026-04-11 14:25:37 +08:00
matevip
795fb5eb0a feat(ui): extract ModelSelector component with grouped layout and search 2026-04-11 10:29:37 +08:00
matevip
79c31ead32 fix(chat): prevent stale approval UI after SSE error/done 2026-04-11 10:04:41 +08:00
matevip
bfd1cbac56 feat(chat): ChatGPT tool calling + fix cross-turn message pollution 2026-04-11 08:46:21 +08:00
matevip
f28ad8d9d4 fix(chat): preserve refresh history and thinking order 2026-04-11 00:16:33 +08:00
matevip
16d22f7e6f feat(ui): design system upgrade — responsive layout, collapsible panels, and unified tokens 2026-04-10 18:14:23 +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
matevip
ba34f1eed3 fix(chat): preserve intermediate reasoning in segments via phase-based splitting 2026-04-10 07:58:19 +08:00
matevip
dafdcb4182 feat(chat): segmented message display, progressive loading, and real-time segment persistence 2026-04-10 07:36:24 +08:00
matevip
c4edcbd95c feat(ui): unify workspace and platform console surfaces 2026-04-09 19:48:17 +08:00
matevip
3d58a48eae feat(platform): add workspace foundation and channel execution upgrades 2026-04-09 10:29:16 +08:00
matevip
43acd2bf94 feat(image,tts): add image generation with 4 providers and TTS with 3 providers 2026-04-07 22:14:31 +08:00
matevip
2ac7cc4af4 feat(stream): add fine-grained phase status hints for frontend UX 2026-04-07 00:40:38 +08:00
matevip
eb78032752 feat(video): support video upload, preview, and multimodal analysis 2026-04-06 09:42:54 +08:00
matevip
d8cf5acf0f feat(chat,pdf): scanned PDF OCR fallback and authenticated attachment display 2026-04-06 07:48:28 +08:00
matevip
84a205509b feat(chat): multimodal image injection and upload UX improvements 2026-04-05 23:58:42 +08:00
matevip
30f42ca770 feat(ui): add mobile responsive layout and fix hardcoded i18n strings 2026-04-05 18:56:41 +08:00
matevip
64a1a699d6 fix(ui): widen suggestion cards grid to prevent misalignment 2026-04-05 06:40:51 +08:00
matevip
eea622099d chore: bump version to 1.0.101-SNAPSHOT with versioned docs 2026-04-05 06:22:28 +08:00
matevip
579d60125b Initial commit: MateClaw — Java + Vue 3 AI Assistant System
Full-stack AI assistant built on Spring AI Alibaba.
Features: ReAct Agent, Plan-and-Execute, MCP Protocol, Multi-Model, Multi-Channel.

Apache-2.0 License
2026-04-04 19:03:49 +08:00