Introduce tenant-scoped storage backend registry so workspaces can register
multiple storage instances and bind each knowledge base to a specific backend,
with migration from legacy tenant-level storage config and new settings UI.
Align product copy, API docs, Swagger descriptions, and i18n strings
with workspace terminology while keeping internal tenant identifiers
and headers unchanged for API compatibility.
Enable agents to configure starter prompts and async follow-up questions after completed answers, with durable caching, analytics events, and chat/embed UI integration.
Replace the standalone /platform/system/* routes with a single
"系统设置" section inside the canonical Settings modal. The previous
SystemLayout.vue / SystemAdmins.vue surfaces are removed and their
functionality (system admin roster, global settings) is hosted directly
in SystemSettings.vue under the standard `.section-header` /
`.settings-group` skeleton. Legacy URLs redirect to the modal section
so external bookmarks don't 404.
Backend:
- SystemSettingService.Reset + repo.Delete: drop the DB override for a
key so the 3-tier resolver falls back to ENV / built-in default.
Idempotent (resetting a never-persisted key returns nil); emits an
audit row only on real deletions, invalidates the local cache, and
publishes to peers via the existing pubsub channel.
- TenantService.BulkSetStorageQuota: overwrite every tenant's
storage_quota in one statement. Powers POST /system/admin/tenants/
apply-default-storage-quota; bypasses the per-tenant whitelist on
PUT /tenants/:id which intentionally forbids storage_quota edits.
- AuditAction{SystemAdminPromoted,SystemAdminRevoked} constants and
emitAdminAudit() in SystemHandler — promote / revoke now leave an
audit trail with TenantID=0 and {target_email,target_username,
idempotent|changed} in details.
- SystemSetting.LastModifiedByName: derived per-request display label
(username, email fallback) so the UI shows "wizardchen" instead of
a UUID prefix without storing a denormalised column.
Frontend:
- SystemSettings.vue rewritten against the Settings modal skeleton with
auto-persisting controls (switch/select @change, input/inputnumber
@blur, tag-input + per-delta popconfirm for SSRF whitelist and admin
roster). auth.registration_mode change goes through an inline
popconfirm; cancel rolls back. Reset / bulk-apply also inline
popconfirms — no dialog modal for these per-row affordances.
- Priority hint panel surfaces the DB > ENV > default resolver order
so operators can reason about "I set the env but it doesn't show up".
- Router: /platform/system, /platform/system/settings, /platform/system/
admins are now compatibility redirects to /platform/settings?section=
system-global.
- Settings modal sized 900x700 → 1080x780 and content-wrapper 600 → 760
so the wider tables (members, system settings) breathe; <1100px
viewport still flexes to the screen.
- i18n: system.globalSettings.* keys for title / description / loading /
empty / badges / priority hint / per-key labels / reset / bulkApply /
admins (label, placeholder, save messages, popconfirm copy) across
zh-CN, en-US, ko-KR, ru-RU.
Misc:
- internal/utils/filesize.go doc: clarify MAX_FILE_SIZE_MB is a
deploy-time-only knob (nginx + docreader + frontend each cache the
env at startup); a SystemAdmin UI override would mislead operators
because nginx would still 413. Until all four layers can hot-reload
the limit in lockstep, this stays env-only.
- internal/utils/security.go: SSRF whitelist parser/runtime now drives
off SystemSettingService for live updates; ENV remains the fallback
for never-overridden deployments.
- Added WEKNORA_BOOTSTRAP_SYSTEM_ADMIN_EMAIL environment variable to promote a specified user to system admin on startup.
- Introduced a new bootstrap process in `bootstrap.go` to handle the promotion logic.
- Updated `.env.example` to document the new environment variable and its behavior.
- Created new views for managing system administrators and system settings, including listing, promoting, and revoking admin privileges.
- Enhanced the frontend to reflect the new system admin features, including UI elements for admin management and settings configuration.
- Updated API interfaces to support system admin functionalities, ensuring proper data handling and user management.
Updated the memory management logic to utilize a server-side per-user preference for enabling memory. The `enable_memory` field is now conditionally set based on user preferences, allowing for better control in both normal and embedded contexts. Adjusted relevant API handlers and request structures to support this change, ensuring backward compatibility with existing clients.
Refs: #1303
PR #1309 plumbed user-scope into the session/message service layer so
non-owner / wrong-tenant lookups now surface as ErrSessionNotFound at
every entry point that goes through sessionRepo.Get. The handler-side
mapping, however, only existed in 4 of the 8 affected sites:
- handler/session/handler.go:GetSession ✓ already mapped (with `==`)
- handler/session/handler.go:UpdateSession ✓ already mapped (with `==`)
- handler/session/handler.go:DeleteSession ✓ already mapped (with `==`)
- handler/session/handler.go:BatchDeleteSessions ✓ already mapped (with `==`)
- handler/session/handler.go:ClearSessionMessages ✗ always 500
- handler/session/stream.go:ContinueStream session lookup ✓ (with `==`)
- handler/session/stream.go:ContinueStream message lookup ✗ always 500
- handler/message.go:LoadMessages (recent + before-time) ✗ always 500
- handler/message.go:DeleteMessage ✗ always 500
Result: a Contributor in tenant A asking for a Contributor B's session
messages got a 500 instead of 404 — the wire response leaked
"something is broken" rather than "you can't see this URL", which
breaks SDK / frontend axios interceptor error handling that keys on
HTTP status.
Two changes:
1. Add ErrSessionNotFound → 404 mapping to the 4 sites that lacked it
(ClearSessionMessages, ContinueStream's GetMessage, LoadMessages's
two paths, DeleteMessage).
2. Replace `err == errors.ErrSessionNotFound` with
`stderrors.Is(err, errors.ErrSessionNotFound)` everywhere. Sentinel
error comparison must use errors.Is so wrapped errors
(`fmt.Errorf("...: %w", ErrSessionNotFound)`) still match. Today no
service-layer caller wraps, but a future refactor that does would
silently turn 404s into 500s with no test catching it.
Tests:
- internal/handler/message_session_not_found_test.go covers the four
new mapping sites in handler/message.go (LoadMessages-recent,
LoadMessages-before-time, DeleteMessage) and pins the wrapped-error
behaviour with a dedicated regression test that fmt.Errorf("%w") a
sentinel must still be detected as ErrSessionNotFound. The bare
handler is hit through gin.Engine + middleware.ErrorHandler so the
response shape matches production exactly.
- PR #1309's existing service-level tests (session_user_scope_test,
session_test on the repository) still pass — this PR is a strictly
handler-layer follow-up.
The Agent ran a parallel context cache (Redis/in-memory) on top of the
messages table to feed multi-turn history into the LLM. That dual-write
caused subtle drift (e.g. compression diverging from DB, system-prompt
swaps lost on restart) and required a separate ClearContext path on
session/IM clear.
Make the messages table the single source of truth:
- Add service.LoadAgentHistory: rebuilds chat.Message history per turn
from the persisted messages, expanding AgentSteps into proper OpenAI
assistant_with_tool_calls + tool messages and replaying the canonical
final answer (with <think> blocks stripped). final_answer tool calls
are filtered to avoid duplicating the trailing answer.
- Make AgentEngine stateless across turns: drop ContextManager / sessionID
cache plumbing from the engine, agent service, and CreateAgentEngine
signature. The engine only uses sessionID for logging/event emission.
- Wire AgentQA to load history from DB on demand using HistoryTurns
(default 5) when MultiTurnEnabled, otherwise run with empty history.
- Delete the llmcontext package (ContextManager interface, Redis/memory
storage, factory) and the SessionService.ClearContext API path; IM
/clear and session message clear no longer need to invalidate cache.
Behavior preserved: KnowledgeQA-mode replay is unchanged (turns with
empty AgentSteps just produce the single canonical assistant message),
and Agent-mode turns now consistently see prior tool calls and results.
- Apply the session-list additions to the SQLite init migration (Lite build)
and make QueryPaged dialect-aware: LOWER(..) LIKE on SQLite, ILIKE on
Postgres, drop NULLS LAST on SQLite. Escape LIKE wildcards in the keyword
via the existing escapeLikeKeyword helper.
- SetPinned now returns rowsAffected so the handler can respond 404 on
unknown / unauthorized session IDs instead of a misleading 200.
- GET /sessions always returns the enriched shape (pin state + IM origin
fields) so the frontend never needs a second roundtrip; the dual-path
legacy branch in the handler is gone.
- Register pin routes with the wildcard name that matches each verb's
existing radix tree (POST :session_id, DELETE :id) and accept either
param name in the handler; avoids gin's "wildcard conflicts" panic.
- Drop the redundant [platform] prefix from IM session titles now that
the list renders a platform icon alongside the title; add unit tests
for shortID / buildUserSessionTitle / buildThreadSessionTitle.
- Frontend: remove the submenu search input and its i18n/keyword wiring
(search lives elsewhere in the app); pin icon uses the TDesign `pin`
glyph and inherits color so the active session turns green; optimistic
pin moves the item to the top of the list so it shows up at the top
of the Pinned group; IM text badge replaced by the platform SVG icons
from assets/img/im, desaturated by default and full-color on hover
or when the session is active.
Sessions today are a flat list ordered by updated_at. Two gaps showed up in
practice:
- Users cannot find specific chats as the list grows beyond a screen.
- IM-created sessions (WeCom/Feishu/Slack/...) are indistinguishable:
every title was "IM-<platform>" or "IM-<platform>-<username>" and the
list API hid the underlying im_channel_sessions mapping, so admins had
no way to tell which Feishu group a session came from.
Backend
- Migration 000039 adds sessions.user_id (owner), is_pinned, pinned_at
plus a composite index for the list query. Existing rows keep user_id
NULL and stay visible at the tenant level for backward compatibility.
- CreateSession now writes the caller's user_id from auth context.
- GET /sessions accepts keyword / source / agent_id. When any filter is
set, the response switches to enriched items that LEFT JOIN
im_channel_sessions and expose im_platform / im_chat_id / im_thread_id
/ im_user_id / im_agent_id / im_channel_id. No filters => legacy shape,
existing clients unaffected.
- Ordering: is_pinned DESC, pinned_at DESC NULLS LAST, updated_at DESC.
- POST/DELETE /sessions/:id/pin for user-scoped pin/unpin.
- IM session titles: "[platform] <user|chat|thread>" with short ID
suffixes so group/DM/thread sessions are visually distinct without
needing a round-trip to fetch a display name from the IM adapter.
Frontend
- Search input debounced at 300ms drives the keyword filter.
- Pinned chats render in a dedicated group above the time-based groups,
with a pin icon and a pin/unpin entry in the per-chat dropdown.
- IM chats get a short [platform] badge in the list.
- Pin toggle is optimistic and guards against double-clicks.
- zh/en/ko/ru i18n keys added for the new strings.
- Implemented a new API endpoint to clear all messages in a session, enhancing session management capabilities.
- Updated the frontend to include a clear messages option in the session menu, allowing users to easily remove chat history.
- Added localization support for the new feature in English, Korean, Russian, and Chinese, improving accessibility for a broader audience.
- Enhanced the chat view to handle session message clearing events, ensuring a responsive user experience.
These changes significantly improve the user experience by providing a straightforward method to manage session messages effectively.
- Updated configuration to support three tasks in the assistant's prompt: rewriting questions, classifying intent for knowledge base retrieval, and analyzing attached images.
- Implemented backend functionality to update image descriptions in user messages, ensuring that image context is preserved across conversation history.
- Modified session handling to return complete session data after updates, improving the accuracy of session information provided to users.
- Enhanced the chat pipeline to include detailed image descriptions and manage image captions effectively, enriching user interactions with visual content.
These improvements significantly enhance the application's multimodal capabilities, providing a more robust and user-friendly experience when handling image-based queries.
- Added functionality for image uploads in chat, allowing users to attach images for multimodal Q&A.
- Enhanced the input field to handle image selection via drag-and-drop and paste, with validation for file types and sizes.
- Updated the backend to process images alongside text queries, including support for image analysis.
- Introduced new UI components for image previews and management, improving user interaction with uploaded content.
- Added localization strings for image upload features and error messages, enhancing accessibility for users in multiple languages.
These changes significantly improve the chat experience by enabling users to incorporate images into their queries, facilitating richer interactions and responses.
- Introduced a new API function `deleteAllSessions` to allow deletion of all sessions for a tenant.
- Updated the `BatchManageDialog` component to support a confirmation dialog for deleting all sessions.
- Enhanced the menu component to reflect the new delete all functionality with appropriate confirmation messages.
- Added internationalization support for the new delete all confirmation message in multiple languages.
These changes improve session management by providing users with the ability to delete all sessions at once, enhancing the overall user experience.
- Updated the AgentSelector component to improve agent selection logic, ensuring accurate representation of selected agents.
- Introduced new AgentShareSettings component for managing agent sharing with organizations, including UI for selecting organizations and displaying shared agents.
- Enhanced API interactions for sharing agents, including new methods for listing and managing agent shares.
- Improved localization support for agent sharing features across multiple languages.
- Updated various components to reflect changes in agent capabilities and sharing status, enhancing user experience and clarity.
This update strengthens the agent management features, providing users with better tools for sharing and selecting agents within organizations.
- Added support for tracking the status of FAQ import tasks, including progress indicators for ongoing imports.
- Introduced new localization strings for processing tasks and batch operations in multiple languages.
- Updated the FAQ entry manager to display import progress and improved user feedback during the import process.
- Enhanced the KnowledgeBase component to reflect the processing state of knowledge items, improving user experience during document uploads.
- Implemented batch deletion functionality for chunks, streamlining the management of knowledge base content.
- Removed outdated DEVELOPMENT.md, consolidating development instructions into relevant documentation.
- Updated conversation configuration to include new parameters such as max rounds, embedding thresholds, and rewrite prompts.
- Enhanced UI components to support new conversation settings, including AgentSettings.vue and related views.
- Improved localization in English, Russian, and Chinese for new conversation configuration fields and UI elements.
- Implemented logic to apply tenant-specific conversation settings, ensuring defaults are respected.
- Added new ConversationConfig interface and API endpoints for retrieving and updating conversation settings.
- Enhanced AgentSettings.vue to include UI for configuring conversation parameters such as prompt, context template, temperature, and max tokens.
- Updated localization files in English and Chinese to include new strings for conversation settings.
- Implemented logic to load and save conversation configuration for tenants, ensuring defaults are applied when no specific configuration exists.
- Updated RegisterMCPTools and GetMCPToolsInfo functions to accept a context parameter, improving control over timeouts and cancellations.
- Implemented timeout handling for ListTools operations to prevent hanging during long-running requests.
- Enhanced GetFunctionDefinitions to include all MCP tools regardless of the allowed tools list, ensuring comprehensive tool access.
- Improved MCP service management by adding checks for service enabled state and critical configuration changes, ensuring robust client connection handling.
- Refactored session handling to utilize AgentModeEnabled for better session configuration management.
- Added Swiper library to package dependencies for improved UI components.
- Updated chat API to include summary model ID in message handling, allowing for more flexible model selection.
- Enhanced InputField component to manage model selection and state more effectively.
- Improved event handling in chat components to support new model features and ensure accurate message processing.
- Refactored SVG assets for better visual consistency and updated styles for improved user experience.