Automatic tagging shipped with a few paths that quietly disabled it and a
prompt that spent most of its budget on data the model never needed.
Robustness:
- Treat an omitted confidence as a deliberate selection instead of zero.
Models frequently drop the field, and the 0.75 floor then filtered out
every match, silently turning the feature off. Percentage-scale values
are rescaled rather than accepted as out-of-range certainty.
- Classify the first 500 tags when a knowledge base has more, logging a
warning, instead of dropping the task entirely. Large knowledge bases
previously got no auto-tagging at all with no user-visible signal.
- Reuse common.ParseLLMJsonResponse for the model reply, and give that
helper a balanced-scan fallback. The local extraction cut the payload at
the last "}" or "]", so a trailing citation such as "see [1]" produced
invalid JSON and burned the task's retries.
Prompt:
- Address candidates by ordinal rather than UUID. Tag names are short while
a UUID is 36 characters, so this cuts candidate tokens roughly tenfold,
keeps the model from having to reproduce (and corrupt) an id, and is what
makes the raised 500 ceiling affordable. Ordinals are range-checked and
mapped back to ids server-side.
- Drop the rationale field. Nothing read it, and at max_tags=10 it competed
with the 1024-token output budget and risked truncating the JSON.
- Fence document text in <document> so file content cannot be read as
instructions.
Behaviour:
- Add auto_tag_config.skip_if_tagged, defaulting to true, so documents the
user already tagged at upload time keep their classification. Existing
tags are now loaded before the model call, so a skipped document costs no
LLM round-trip. Configs stored without the field adopt the default.
Also promote AddKnowledgeTagRelations to KnowledgeRepository instead of
reaching for it through a type assertion that failed at runtime, and route
the max_tags bounds through AutoTagConfig.Normalize so the prompt, the match
filter and the persisted config cannot drift apart.
Adds handler-level coverage for scope, cancellation, idempotency, ordinal
validation and the new toggle, plus SDK, Swagger and API doc updates.
Align product copy, API docs, Swagger descriptions, and i18n strings
with workspace terminology while keeping internal tenant identifiers
and headers unchanged for API compatibility.
Drop client-supplied target_id, generate IDs server-side, localize duplicate
names from request language, document the endpoint, and expand handler/client tests.
GET with a JSON body was non-standard and confused integrators. Register
POST as the preferred method and keep GET for existing clients; update SDK,
MCP server, and API docs accordingly.
Refs: https://github.com/Tencent/WeKnora/issues/1727
Wires KnowledgeBase.VectorStoreID and the ownership-aware retrieve factory
into the user-facing knowledge-base lifecycle:
- POST /knowledge-bases validates the requested vector_store_id against
the caller's tenant scope and the engine registry. New error codes
ErrVectorStoreBindingInvalid (2200) and ErrVectorStoreUnavailable (2201)
distinguish the typed branches without echoing UUIDs to the client.
- GET / POST / PUT / PUT-pin responses embed the bound store's display
metadata (name, source, engine_type, status) without exposing any
connection credentials. Cross-tenant shared KBs receive a suppressed
payload (vector_store_id stripped, source="shared") so operator-chosen
store names cannot be enumerated across tenants.
- POST /knowledge-bases/copy synchronously rejects clones whose target
has a different embedding model or vector store, before the async
clone task is enqueued. The async clone worker re-applies the same
checks for defense in depth.
- DELETE /vector-stores/:id refuses to remove a store with bound KBs,
inside a transaction that row-locks the store on PostgreSQL and
serializes via WAL on SQLite. unregister-from-registry is wrapped in
defer/recover so a panic surfaces as a structured warning instead of
silently leaking a stale engine.
- vector_store_id is immutable after creation. The GORM <-:create tag
blocks every ORM update path; the service-layer DTO omits the field
entirely; a reflection-based regression test catches any future
maintainer who adds it back to either layer.
- Empty-string vector_store_id is normalized to nil at both the create
path and inside SharesStoreWith, so rows persisted by callers that
did not run Normalize first cannot trip false same-store comparisons.
Part of #993. Depends on #994 and #1310.
- Introduced a new package for managing custom agents, including CRUD operations for agent creation, retrieval, updating, and deletion.
- Implemented API endpoints for listing agents and retrieving agent placeholders.
- Added data structures for agent configuration and requests, enhancing the overall agent management capabilities.
- Enhanced the client with methods to interact with the new agent management features, improving user experience in managing agents.
These changes significantly expand the application's functionality for handling custom agents, providing users with a comprehensive toolset for agent management.