Commit Graph

173 Commits

Author SHA1 Message Date
matevip
2b3c068db9 feat(wiki): broken-link lint with job-based async scan 2026-05-28 08:17:04 +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
fe072191ea feat(approval): REST surface for auto-grant strategies with tiered authorization 2026-05-27 14:07:56 +08:00
matevip
2653356613 feat(approval): record human-approval and timeout resolutions, retire grants on conversation delete 2026-05-27 14:07:48 +08:00
matevip
b7e923fac4 feat(approval): grant-based auto-approve with safety floor and resolution log 2026-05-27 14:07:39 +08:00
matevip
ac090afde3 fix(workflow): pre-check unique name on create/rename, return 409 instead of 500 (Fixes Gitee #IJPYWA) 2026-05-26 23:35:04 +08:00
matevip
c8b25e1bfb fix(agent): deny skill-discovery tools when skillsDisabled (#184 follow-up) 2026-05-26 22:16:51 +08:00
matevip
0ac325a337 feat(agent): explicit "no skills / no tools" opt-out flags (#184) 2026-05-26 22:07:12 +08:00
matevip
ff2620dfcf fix(wiki): harden kbName/kbId routing — ambiguous fail-closed, kbId param, prompt cleanup (#224) 2026-05-26 14:31:07 +08:00
matevip
d2b23c049c fix(wiki): let agents reach every visible KB via kbName + wiki_list_kbs (#224) 2026-05-26 13:53:32 +08:00
matevip
7f5652b2f0 fix(agent): replace per-loop head/tail trim with anchored token-budget budgeter 2026-05-26 07:34:25 +08:00
matevip
07eb625d11 fix(agent): collapse SystemMessages at egress to fix LM Studio 400 (#218)
Some OpenAI-compatible providers (LM Studio's built-in server, certain
strict-mode vLLM / SGLang deployments) reject 400 "System message must
be at the beginning" when SystemMessages appear after user / assistant
/ tool messages. The reasoning loop currently emits four SystemMessage
segments — main prompt at index 0, skill catalog inserted at index 1,
progress-ledger snapshot and stale-reminder appended at the end of
nonHistoryPrefix after the runtime-context UserMessage. The latter two
violate the strict shape, so conversations on LM Studio 400 on the
first turn (reported in #218).

Add MessageNormalizer: collects every SystemMessage in the outbound
prompt regardless of position, joins their text with a blank-line
separator, and emits a single SystemMessage at index 0. Non-system
messages keep their relative order, so AssistantMessage(tool_calls) ↔
ToolResponseMessage adjacency is preserved verbatim (required by strict
pair validators).

Wire it into doStreamCall as the first pre-egress step so every node
(reasoning, step-execution, summarizing, plan-generation, limit-exceeded)
inherits the fix without per-node changes, and any future node that
emits multiple SystemMessages stays compliant.

The transformation is semantically equivalent on permissive providers
(OpenAI, DashScope, Ollama, DeepSeek, Kimi, Doubao, GLM) — the merged
token sequence matches what they would have seen across N SystemMessages
— and safe on non-OpenAI protocols (Anthropic, Vertex / Gemini), whose
adapters already extract SystemMessages into a top-level system field
and receive an identical payload.

Kill switch: -Dmateclaw.llm.message-normalizer.enabled=false reverts to
the prior behavior for emergency rollback.

Tests: 11 unit tests on MessageNormalizer cover empty / no-system /
canonical / mid-list / tail / blanks / tool-pair preservation / Prompt
option-reference preservation / kill switch. 1 wiring test pins the
call site in doStreamCall. Full vip.mate.agent.** suite (504 tests)
stays green.

Closes #218.
2026-05-25 17:57:03 +08:00
matevip
a37074a9a6 fix(tool): close three sandbox follow-up gaps surfaced by review
1. Relative parent traversal in shell commands (HIGH)

   validateShellCommand only scanned absolute path tokens, so commands
   like `cat ../mateclaw/CLAUDE.md`, `cd .. && cat foo`, or
   `ln -sf ../bar breakout` had no absolute path to trip the check.
   From a workspace cwd that's a real escape — `..` segments resolve
   against the JVM cwd at file-tool time and reach anywhere the user
   can read.

   Add a second pass: any token containing `..` as a path segment is
   resolved against the workspace root via root.resolve(token).
   normalize(); reject when the result falls outside. In-workspace
   traversal like `subdir/../sibling` normalizes back inside and
   passes. Identifiers without slashes (e.g. version strings with
   `1.2..3`) are not treated as paths.

2. Shell validation and process working directory used different
   context sources (MEDIUM)

   execute_shell_command validated with the explicit ToolContext, but
   buildShellProcess called WorkspacePathGuard.getWorkingDirectory()
   (no-arg), which only sees the ThreadLocal fallback. Today the
   ToolExecutionExecutor sets both so the discrepancy is latent, but
   a future direct Spring AI invocation passing only ToolContext would
   validate against one basePath and exec against another. Thread ctx
   through buildShellProcess and call getWorkingDirectory(ctx) so
   validation and execution agree on a single source of truth.

3. Absolute agent override could disable workspace scoping (MEDIUM)

   resolveAgentBasePath accepted an absolute override verbatim, even
   when it pointed outside the workspace root. An admin (or any
   account with agent-edit permission) could set workspaceBasePath="/"
   or another team's repo and bypass workspace boundaries entirely.

   When a workspace has its own basePath, require absolute overrides
   to sit underneath it. The caller in build() catches the rejection,
   logs WARN, and falls back to the workspace basePath so chat stays
   available rather than crashing agent construction. When the
   workspace has no basePath there's no boundary to enforce, so legacy
   behavior is preserved.

Test coverage: WorkspacePathGuardShellTest grows from 17 to 23 (six
new cases for `cd ..`, relative parent traversal, relative symlink
escape, deeper traversal, in-workspace normalization, and the
identifier false-positive guard). AgentGraphBuilderBasePathResolutionTest
grows from 7 to 10 (three new cases for in-workspace absolute,
outside-workspace absolute rejection, and no-workspace legacy
behavior). All 45 sandbox-area tests pass with no regressions.
2026-05-25 17:55:56 +08:00
matevip
7272d8f633 fix(tool): allow standard /dev/* character devices in shell sandbox 2026-05-25 16:38:31 +08:00
matevip
b09a220ec7 fix(tool): enforce workspace boundary on shell commands and file metadata tools 2026-05-25 16:26:16 +08:00
matevip
9e9a96f674 fix(agent): resolve relative workspaceBasePath under workspace root 2026-05-25 15:58:05 +08:00
matevip
692362e7a7 fix(channel): flush emergency save before SSE idle eviction disposes the run 2026-05-24 23:01:14 +08:00
matevip
f1d9104422 fix(channel): evict SSE RunState by inactivity, not wall-clock age 2026-05-24 23:01:04 +08:00
matevip
c36abf38b8 feat(agent): inject stale-ledger reminder when the model stops updating 2026-05-24 23:00:35 +08:00
matevip
9f2fb3db23 feat(agent): echo full ledger snapshot in progress_update tool result 2026-05-24 23:00:24 +08:00
matevip
7736f6b0ab fix(agent): serialise progress-ledger upsert per conversation 2026-05-24 23:00:17 +08:00
matevip
e953f8be5a feat(agent): age-based compaction of older tool-response bodies 2026-05-24 23:00:11 +08:00
matevip
05289e6bdb feat(agent): per-conversation progress ledger to survive context trims 2026-05-24 23:00:03 +08:00
matevip
fe9610dfa6 fix(dashboard): count tool calls from assistant.metadata, not role=tool rows 2026-05-24 22:58:02 +08:00
matevip
8030a41125 fix(api): return 400 on path-variable type mismatch instead of 500 2026-05-24 22:57:51 +08:00
matevip
c857d6dd45 fix(agent): retry empty LLM completion before treating it as final answer 2026-05-24 22:57:19 +08:00
matevip
481cece733 fix(channel): preserve queued chat inputs across turns 2026-05-24 22:57:08 +08:00
matevip
a9c2d45790 Harden goal approval and workspace flows 2026-05-23 22:55:16 +08:00
matevip
5cd6e841a4 feat(skill): broaden script security scan + GBK zip-import fallback 2026-05-23 22:55:10 +08:00
matevip
3fc121c6b7 fix(tool): show runtime names in tools admin 2026-05-23 22:54:57 +08:00
matevip
123d912f84 fix(skill): allow template file access 2026-05-23 09:08:01 +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
5f571e86a2 feat(agent,ui): multi-level subagent delegation tree 2026-05-22 13:44:01 +08:00
matevip
81915ccfae feat(tool): read_file can page through an oversized single line via startColumn (#190) 2026-05-21 22:27:09 +08:00
matevip
9e93c52d9a fix(goal): real evaluator, retry refactor, hardened node + extra edges 2026-05-21 22:27:00 +08:00
matevip
c34e8290ac feat(goal,ui): inline set-goal prompt, terminal system-line, sidebar dot 2026-05-21 22:26:40 +08:00
matevip
9c5ad29d42 chore(llm): drop unused imports, add XIAOMI_MIMO cross-turn cache tests 2026-05-21 17:24:53 +08:00
倪程伟
7861f603eb
fix(llm): MiMo thinking 模式 reasoning_content 多轮对话兼容修复 (#189)
MiMo V2 系列在 thinking 模式下,assistant 消息携带 tool_calls 时必须同时包含 reasoning_content,否则提供方返回 400。

- ModelFamily 新增 MIMO_THINKING 族,detect() 添加 mimo* 匹配
- FallbackPolicy 新增 XIAOMI_MIMO(patchCrossTurn=true, patchNonToolCall=true)
- 新增 ReasoningContentCache,按 tool_call_ids 回放真实推理内容
- 缓存作用范围:所有 patchCrossTurn=true 的 thinking provider(MiMo + DeepSeek)
- NodeStreamingChatHelper 流式响应完成后写入缓存

Closes #188
2026-05-21 17:15:35 +08:00
matevip
e61b05bba0 fix(tool): read_file no longer returns empty content + infinite retry on oversized single lines (#190) 2026-05-21 16:26:24 +08:00
matevip
a910004b3b feat(agent): digital-employee builder skill to auto-create agents and chain them into a workflow (#165) 2026-05-21 16:26:04 +08:00
matevip
03e68d3c74 fix(agent): structure-aware truncation to stop mid-JSON cuts inducing hallucination (#187) 2026-05-21 15:13:07 +08:00
matevip
c9e54e820f fix(goal,ui): live ring update after agent-triggered setGoal / addGoalCriterion 2026-05-21 14:43:59 +08:00
matevip
89f8413db8 test(agent): sync LaneDPerformanceFixesTest with MAX_RETRIES bump 2026-05-21 14:43:52 +08:00
matevip
6646e91585 feat(goal): built-in tools for agent-driven goal management 2026-05-21 14:43:20 +08:00
matevip
ce74a0ae48 feat(goal): graph topology + evaluation node wired into ReAct + Plan-Execute 2026-05-21 14:43:13 +08:00
matevip
ac6c8a18e3 feat(goal): persistent cross-turn goal with self-evaluation scaffolding 2026-05-21 14:43:01 +08:00
matevip
6a4318c268 fix(channel): IM conversations respect per-conversation model selection (#183) 2026-05-20 17:49:03 +08:00
matevip
43136fc663 fix(channel): sweep orphan tool rows + guard rules; scope rule name to channel 2026-05-20 16:35:57 +08:00
matevip
12ff190392 feat(feishu): transcribe inbound voice messages via SttService 2026-05-20 16:35:46 +08:00
matevip
6b4456043e fix(feishu): outbound generated-file URLs become native attachments 2026-05-20 16:01:03 +08:00
matevip
6b397a10ed feat(feishu): inbound file/audio/video download — SDK path + cache push 2026-05-20 15:53:40 +08:00
matevip
71e08b015e sync: Feishu approval card 5-chain hotfix — verified end-to-end in production 2026-05-20 15:24:47 +08:00
matevip
090bb64c6a sync: Feishu channel-native tool provider + DbRuleGuardian generic guard 2026-05-20 12:29:29 +08:00
matevip
85d7ee23c4 sync: ChannelToolProvider SPI + node-local reconcile framework for channel-native tools 2026-05-20 12:18:51 +08:00
matevip
a9fa8e7fb1 sync: interactive approval card on Feishu via Schema-2.0 button + card.action callback 2026-05-20 12:05:47 +08:00
matevip
3554da8dbc sync: inject sender context into agent prompt + Feishu DONE ack hook 2026-05-20 11:51:58 +08:00
matevip
35f010d7a1 sync: Feishu CardKit streaming-card adapter via cardkit/v1 SDK 2026-05-20 11:37:12 +08:00
matevip
0e1b8ca564 sync: componentized media upload SPI + Feishu SDK-backed file sender 2026-05-20 11:23:33 +08:00
matevip
3340885da3 fix(llm): skip chat-style probe for embedding-prefix models in DashScope discovery 2026-05-20 10:14:25 +08:00
matevip
a6b5e3b515 refactor(llm): extract testable embedding protocol routing + drop dead fromProviderId 2026-05-20 10:14:12 +08:00
matevip
73ab31a13c fix(feishu): fail open when bot open_id is unavailable 2026-05-20 10:13:34 +08:00
倪程伟
af3e68d271 fix(feishu): use SDK mentions field for require_mention group filtering (#163)
Closes #162

require_mention=true previously degraded to a no-op when botPrefix was unset:
shouldProcess() returned true for all messages and checkAccess() fell through
unconditionally, so any group message would be answered — including ones where
the @mention targeted another user.

FeishuChannelAdapter now consults the Feishu SDK's mentions field directly:

- WebSocket: read EventMessage.getMentions(); webhook: read mentions[] from the
  JSON payload. In both paths each mention's id.open_id is compared against the
  bot's own open_id.
- Bot open_id is fetched lazily via /open-apis/bot/v3/info and cached on the
  adapter instance. If the call fails the message is allowed through, matching
  the previous behaviour.
- The require_mention gate is applied at the top of handleFeishuMessage so 1:1
  chats are unaffected.

Tests: 15 unit cases covering null/empty inputs, bot mentioned, only-other
mentioned, bot among multiple mentions, and malformed payloads.
2026-05-20 08:49:11 +08:00
倪程伟
ee0c229f52
feat(feishu): support Interactive Card JSON for structured message rendering (#161)
Auto-route Agent replies to Feishu Interactive Card (schema 2.0) when the
content carries structure — JSON object / array, Markdown with code blocks
or headings, or long-form prose — and keep the original text path for
short plain replies.

- FeishuCardFormatter: package-private detect() + render() helper
  - JSON object → two-column summary card
  - JSON array (≤4 fields) → table component; (>4 fields) → div per item
  - Markdown → lark_md card with 'AI 助手' header
  - Long text (>300 chars with paragraph breaks) → plain_text card
  - JSON embedded in Markdown code blocks is recognised across all fences
- FeishuChannelAdapter
  - sendMessage() honours channel config 'card_format' (auto | always | never)
  - sendCard() POSTs interactive messages; ou_-prefixed targets use open_id
  - updateCard() PATCHes an existing message (streaming-update hook)
- Tests: 32 unit cases covering every detect path and render branch

Closes #141
2026-05-20 08:42:02 +08:00
matevip
db16ff02a5 chore: drop external project name references from code comments 2026-05-20 08:09:43 +08:00
matevip
c0f9d1d9fb test(wiki): add adversarial HTML normalization tests and harden skeleton-tag handling 2026-05-19 21:23:13 +08:00
matevip
c1b878b7e1 fix(agent): fail over to backup providers when the primary is rate-limited 2026-05-19 20:06:21 +08:00
matevip
c6d51f8ced fix(wiki): resolve an agent's own knowledge base before shared ones 2026-05-19 16:53:12 +08:00
matevip
3d643f909d feat(skill): typed wrapper tools for declared script entrypoints 2026-05-19 09:56:39 +08:00
matevip
31d4d014ed fix(skill): normalize runSkillScript JSON args 2026-05-19 09:56:33 +08:00
matevip
520429ac6f test(skill): end-to-end coverage for the lifecycle curator 2026-05-19 09:56:27 +08:00
matevip
4cd21056a0 feat(skill): automatic lifecycle archival for idle skills 2026-05-19 09:55:59 +08:00
matevip
d53d66abe3 feat(chat): per-conversation model selection (#150) 2026-05-18 16:27:27 +08:00
matevip
0ff8da0caa fix(llm): stop MODEL_NOT_FOUND from evicting the whole provider (#150) 2026-05-18 16:27:20 +08:00
matevip
3157dde1f4 fix(memory): route long-term memory edits to the file being edited (#148) 2026-05-18 11:28:01 +08:00
matevip
75107ac815 feat(llm): native Gemini chat builder, Nano Banana image gen, xAI/Grok provider 2026-05-18 10:00:55 +08:00
matevip
a88edbdd07 refactor(llm): decouple model construction from the agent graph layer (#147) 2026-05-18 07:47:49 +08:00
matevip
18df97a8e6 fix(agent): scope MCP tools to explicit per-agent selection (#117) 2026-05-17 09:24:56 +08:00
matevip
e647f1d6cf fix(cron): isolate scheduled-job runs from shared conversation (#142) 2026-05-17 07:58:10 +08:00
matevip
b4add8b139 fix(agent): keep wiki tools available to skill-bound agents (#143) 2026-05-16 23:00:45 +08:00
matevip
dca71b5a43 test(task): de-flake the submitOneShot enrolled-latch ordering test 2026-05-16 14:51:57 +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
81c6488a3c feat(tool): async sub-agent delegation with attribution gate 2026-05-16 14:51:20 +08:00
matevip
419ee57cc8 feat(agent): structured compaction on prompt-too-long preserves prefix 2026-05-16 14:51:14 +08:00
matevip
b9c0ead024 feat(workspace): keyword search across agent memory files 2026-05-16 14:51:09 +08:00
matevip
d90591fa35 feat(task): generic one-shot Callable runner with parent-conv cancel 2026-05-16 14:51:04 +08:00
matevip
c320aab1ba fix(skill): synthesize SKILL.md body for ACP-derived virtual skills (#136) 2026-05-16 14:50:51 +08:00
matevip
130dfd5278 fix(skill): synthesize SKILL.md for MCP-derived virtual skills (#136) 2026-05-16 14:50:46 +08:00
matevip
3b9b4d79d5 feat(skill): scope skill catalog and runtime by workspace (#135) 2026-05-15 20:01:25 +08:00
matevip
65dd4c1f49 fix(skill): cascade-delete agent-skill bindings on skill removal (#127) 2026-05-15 10:17:41 +08:00
matevip
adf5d93975 fix(wiki): align HTTP status with R envelope and harden config + edit paths 2026-05-14 23:01:00 +08:00
matevip
1bba59fc7e fix(skill): encode bridge virtual ids in the top two bits 2026-05-14 18:18:21 +08:00
matevip
139a478bcd fix(skill): give CJK-only MCP/ACP names a stable id-based slug 2026-05-14 18:18:15 +08:00
matevip
d1be02985c fix(agent): collapse model-predicted tool results that the actual tool replaced 2026-05-14 15:44:03 +08:00
matevip
bf3f4af913 fix(agent): structured tool-call replay + final-answer-only content (#120) 2026-05-14 07:46:30 +08:00
matevip
1ea90c25cb fix(agent): make head-orphan repair order-sensitive — a later same-id assistant does not redeem an earlier orphan 2026-05-13 09:03:16 +08:00
matevip
bff57924d6 fix(agent): repair head-side orphan tool responses on the pagination cut 2026-05-13 09:03:10 +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
7015d1513c feat(context): anchor the first user message after compaction so long tasks remember the original goal 2026-05-13 08:50:15 +08:00