Add the user-facing and API-reference docs that explain how an employee
can declare a primary knowledge base, what the runtime fallback chain
looks like, and how the binding is driven from the API.
agents.md (zh + en)
- New section "Knowledge base binding (per-agent primary KB)" right after
the tool-binding section, with a 1.5.0 New In badge
- Lays out the design intent explicitly: KBs stay workspace-shared, the
binding only chooses a default target, multiple agents may pick the
same KB as primary
- Documents the runtime resolution order used by wiki tools: explicit
kbName/kbId, agent.primaryKbId, most-recently-updated workspace KB
- Migration note about the legacy kb.agent_id to agent.primary_kb_id
backfill and the visibility change for anyone who relied on the old
one-to-one isolation
api.md (zh + en)
- Under Agents: document the primaryKbId field with the three-state PUT
semantics (omit / null / value) and example curl calls
- Under LLM Wiki: document GET /api/v1/wiki/knowledge-bases/bindable and
the explicit warning that PUT /api/v1/wiki/knowledge-bases/{id} no
longer processes the agentId field
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.
PR #237 introduced V129__agent_primary_kb.sql while dev also has
V129__wiki_page_broken_links.sql shipped from the broken-link lint work.
Flyway rejects duplicate version numbers at startup, so the agent
primary_kb migration moves to V130 across both H2 and MySQL dialects.
No content change beyond the rename — the column add, index, and
backfill SQL are identical to the V129 originals from #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