- Revised usage steps in English, Korean, Russian, and Chinese localization files for clarity on saving credentials and adding cloud models.
- Introduced a new section in WeKnoraCloudSettings.vue to display the status of cloud model integration based on credential configuration.
- Added utility functions for managing WeKnoraCloud models, including model configuration and existing model checks.
- Enhanced ModelSettings.vue to improve model management actions and confirm deletion prompts.
- Implemented logic to handle adding cloud models with success and failure notifications.
The global Auth middleware allowlist (noAuthAPI) was missing the
share-link routes, so an unauthenticated invitee opening /register?token=
hit a 401 on /auth/invitations/lookup and the frontend bounced them to
/login instead of showing the register page. Add both share-link
endpoints to the allowlist and stop the request interceptor from treating
their 401s as a session-expiry redirect.
Refs: https://github.com/Tencent/WeKnora/issues/1617
- Added a new thinking mode control field in the ModelEditorDialog, allowing users to specify how the agent's thinking mode is formatted for API requests.
- Introduced localization strings for thinking mode labels and descriptions in English, Korean, Russian, and Chinese, enhancing user experience across multiple languages.
- Updated the model form data structure to include thinking control settings, ensuring proper handling during model edits and saves.
- Implemented utility functions for resolving and defaulting thinking control values based on provider and model, improving backend integration.
- Added tests for the new thinking control functionality to ensure reliability and correctness in handling user configurations.
The Nginx 413 error handler in request.ts calls t('error.fileSizeExceeded')
without the required {size} parameter, causing the toast to display
"文件大小不能超过 M!" instead of "文件大小不能超过 50M!".
Export MAX_FILE_SIZE_MB from utils/index.ts and pass it as {size} to the
i18n call, matching the sibling call site in kbFileTypeVerification().
- Added a mechanism to throttle retries for failed file fetches, preventing excessive 404 requests during streaming.
- Introduced a cooldown period for re-fetching files that previously failed, improving performance and user experience.
- Implemented a function to clear the failure cache, allowing immediate retries after streaming ends.
- Updated the `hydrateProtectedFileImages` function to utilize the new throttling logic, ensuring efficient image loading.
- Eliminated all instances of the final_answer tool from the agent's configuration and logic, transitioning to a model where the agent concludes responses with plain text instead.
- Updated event handling and response analysis to reflect this change, ensuring that the agent's output is now directly delivered as text without relying on a dedicated final answer tool.
- Adjusted localization strings across multiple languages to remove references to final_answer, enhancing clarity and consistency in user-facing messages.
- Improved the overall structure of the agent's response handling to streamline the process and reduce potential confusion regarding tool usage.
refactor(agent): streamline answer handling and preamble logic
- Updated the agent's response handling to treat any text streamed before a tool call as a preamble, ensuring it is not included in the final answer.
- Removed the superseded marker logic from the event emission process, simplifying the flow of answer content and enhancing clarity in the UI.
- Adjusted the event handling to ensure that preamble segments are correctly retracted and relocated into the steps tree, improving the overall user experience.
- Enhanced the agent's internal logic to better manage answer segments and their states during streaming, leading to a more coherent response structure.
- Introduced a new `ChatRequestInfoButton` component to display detailed request information for chat sessions.
- Enhanced the `useStream` function to track the last stream request, including request ID, URL, method, and sanitized body.
- Updated localization files to include new strings for request information in both English and Chinese.
- Integrated the request info button into the chat interface, allowing users to easily access and copy request details.
- Improved handling of stream requests by attaching debug information to messages for better tracking and debugging.
- Introduced new components: AgentCreateContextualGuide, KbCreateContextualGuide, TenantModelsGuide, and SpotlightGuide to enhance user onboarding.
- Implemented dynamic step configurations for each guide, allowing tailored user experiences based on context.
- Enhanced the existing NewUserGuide component to utilize the new SpotlightGuide for improved visual guidance.
- Updated localization files to include new strings for contextual guides, ensuring a comprehensive user experience across languages.
- Refactored existing components to integrate with the new guide system, improving maintainability and user interaction.
Introduce opendataloader and PaddleOCR-VL parser engines with tenant-level
settings UI, replace liteparse, and harden Excel/PPT/Markdown parsing.
Optional odl-hybrid sidecar stays local-build only and is excluded from
default dev-start and full profiles.
This commit introduces a new utility function, `knowledgeSpansPayloadHasTrace`, to determine if the knowledge spans data contains a valid trace. Key changes include:
1. Updated the `KnowledgeBase` component to utilize the new trace availability checks, improving the logic for displaying trace-related UI elements.
2. Enhanced the `fetchSpans` function in the `knowledge-processing-timeline` component to emit trace availability based on the new utility.
3. Implemented caching for trace availability to optimize performance and reduce unnecessary API calls.
These changes aim to improve user experience by providing accurate trace information and enhancing the overall responsiveness of the UI.
The user font-size preference applies CSS `zoom` on `<html>`
(see `composables/useFont.ts`). This breaks every popover that
anchors itself with `getBoundingClientRect()` + `position: fixed/absolute`,
because the rect is in visual pixels while CSS lengths are then
multiplied by zoom again — shifting popovers toward the lower-right
and miscomputing maxHeight / width / viewport-edge clamping.
PR #1459 patched only `AgentSelector.vue` (and left its width/maxHeight
unfixed). This PR introduces a shared helper `frontend/src/utils/zoom.ts`
(`getRootZoom`, `rectToCssPx`, `cssViewportSize`) and applies it to every
affected popover:
- `AgentSelector.vue` — refactored to use the helper; also normalizes
`width` and `maxHeight` (previously still in visual px).
- `Input-field.vue` — model dropdown, mention popup (typed @ and button-
triggered), and agent-mode dropdown.
- `KnowledgeBaseSelector.vue` — primary anchor path and fallback path.
- `UserMenu.vue` — tenant and IM floating submenus + viewport clamp.
- `FAQTagTooltip.vue` — fixed tooltip positioning + edge clamp.
- `AgentEditorModal.vue` — placeholder popups for system_prompt,
context_template, and rewrite/fallback prompts.
- `AgentStreamDisplay.vue` — `kb-float-popup` (absolute under body, also
under the zoom containing block).
Verified with `npm --prefix frontend run build`.
MinerU already returns markdown with embedded HTML blocks, but the current\nreader runs the whole document back through html-to-markdown. That\nsecond conversion escapes valid headings and image syntax, so chunk\nprofiling sees plain text instead of markdown structure and relative\nimage references stop matching the storage pipeline.\n\nKeep MinerU output in its original markdown form and only apply narrow\ncompatibility normalization for the specific over-escaped patterns we\nactually need to recover. The converter now matches image refs by the\npaths that are really present in markdown or embedded HTML instead of\nassuming a single images/<name> form.\n\nExtend ImageResolver so relative HTML <img src=...> references share the\nsame storage rewrite path as markdown images, deduplicate repeated saves,\nand keep the frontend sanitizer compatible with MinerU's details/summary\nblocks. Add focused docparser tests that cover escaped markdown repair,\nvariant image path matching, and relative HTML image persistence.
Updated the notification system to utilize the `tm` function for template resolution, ensuring that placeholders like `{name}` and `{role}` remain intact for proper rendering. This change improves the display of workspace and role information in login and tenant switch notifications, allowing for better localization and visual consistency across the application. Adjustments were made in `App.vue`, `Login.vue`, and related utility functions to accommodate the new template handling.
The login-success and tenant-switch toasts previously showed the
workspace name and role inline as bracketed plain text, which read
flat and made the two key data points hard to scan at a glance.
Render them through a shared `renderWorkspaceNotifyContent` helper
that produces a NotifyPlugin VNode with:
* a neutral rounded chip for the workspace name (with a generic
workspace icon), and
* a role-coloured chip for the role (with the existing per-role icon
from useRoleLabel), so owner / admin / contributor / viewer each
get a distinct visual identity that matches the role badges used
elsewhere in the product.
The i18n templates lose the surrounding 「」 / "" / «» quote marks
because the chip itself now provides the visual delineation; double
emphasis looked off. Translators control the surrounding wording via
`{name}` and `{role}` placeholders and the renderer splits on those
markers to interleave plain text and chips in the original order.
The PendingTenantSwitchToast payload (sessionStorage-stashed for the
hard-reload survival trick) grows a `roleEnum` field so the post-
reload toast can colour the chip — without that, the switch toast
would fall back to a neutral chip while the login toast got the
colour treatment.
Note on icon resolution: the chip renderer imports TDesign's `Icon`
component directly rather than referencing it by string tag in `h()`
— Vue's render function does not auto-resolve component names the
way templates do, so `h('t-icon', ...)` would silently render an
unknown HTML element.
Replace the plain "Login successful" toast with a TDesign Notify card
that surfaces the workspace the user just landed in and their role
there, so users immediately see which space they're working in —
especially useful now that login can drop them into a remembered
non-home tenant.
A small shared helper (utils/loginNotify.ts) handles both the password
login path (views/auth/Login.vue) and the OIDC callback path
(App.vue handleGlobalOIDCCallback), so the two flows stay consistent.
Role label goes through the same useRoleLabel composable used by the
rest of the role-aware UI, so locale + future role-name tweaks live in
one place. The membership lookup falls back gracefully (no role line)
when the active tenant isn't in the response's memberships list — e.g.
the auto-setup path that synthesises a single owner row.
The legacy auth.loginSuccess key is left in place; nothing else
references it, so a future cleanup PR can drop it safely.
Until now a fresh login (new device, expired refresh token, cleared
browser) always dropped the user into their home tenant, even if they
spend most of their time in a peer workspace. The session-local
X-Tenant-ID override in localStorage gave a "same browser sticky"
effect, but never crossed devices or new sessions.
This adds a small server-side preference, `users.preferences.
last_active_tenant_id`, persisted in the existing jsonb column (no
new migration), and threads it through:
* Backend
* `UserPreferences` gains `LastActiveTenantID *uint64` with sentinel
semantics (`*0` from the PATCH endpoint = clear preference).
* `resolveLoginTenantID` validates the stored id (tenant still
exists + active membership, or CanAccessAllTenants) and falls
back to home on any failure, best-effort clearing the stale
preference so subsequent logins don't pay for it again.
* `Login` and `LoginWithOIDC` resolve once and use the result for
both the JWT `tenant_id` claim and the returned `active_tenant`,
keeping the two in sync. `RefreshToken` rides through
`GenerateTokens` so refresh rotations also land the user back in
their preferred tenant instead of bouncing to home.
* `UpdateUserPreferences` learns to merge the new key.
* `PUT /auth/me/preferences` accepts the new field.
* Frontend
* `Login.vue` now writes the user's HOME tenant id into
`user.tenant_id` (matching the field's documented semantics) and
expresses any active-vs-home divergence via `setSelectedTenant`,
so `useHomeTenant` and the "current"/"home" badges stay correct
after the backend honours a remembered preference. `App.vue`'s
OIDC sync does the same reconciliation.
* `TenantSelector`, `UserMenu` and the post-tenant-create handlers
fire `persistLastActiveTenantPreference` after every successful
user-initiated switch (switching to home sends `0` to clear).
The call is raced against the existing reload-grace window so
most writes finish before the page tears down; lost writes are
recoverable on the next switch.
No new UI. Users will simply notice that, after re-logging in on
another device, they land back in the workspace they were last
using rather than always in their home tenant.
Note: `make docs` is unrelated-broken on `main` (audit_log.go
references `errors.AppError` which swag can't resolve), so the
Swagger artifacts under docs/ are intentionally not regenerated
in this PR. The handler code is the source of truth.
Replace the lightweight "switch success" message with a richer
NotifyPlugin notification that reports the new workspace name and the
user's role in it. Because the post-switch flow does a hard reload,
the notification is stashed in sessionStorage before navigation and
consumed by App.vue on the next mount, so the toast actually appears
on the destination page with its full 6s duration instead of being
torn down a frame after it is shown.
For the cross-tenant superuser path (TenantSelector), the role line is
omitted when the user has no membership row in the target tenant,
avoiding a misleading empty/raw role value. Role labels are formatted
through the shared useRoleLabel composable so any future role text
change still lives in one place.
i18n keys updated across zh-CN, en-US, ko-KR, ru-RU.
Updated the tenant switch logic to consistently redirect users to the platform's knowledge base list after a tenant switch, simplifying the navigation experience. Removed the previous handling of tenant-scoped routes, ensuring a more predictable behavior during tenant transitions. This change enhances user experience by avoiding potential empty states on reload.
Refs: #1303
Switching the active tenant triggers window.location.reload() to
re-key every cached store / open SSE stream / in-flight request.
The catch: when the user is currently sitting on a route whose URL
embeds a tenant-scoped resource id, the new tenant lands on a
404/403 and the user sees a blank screen.
Three risky route shapes today:
/platform/knowledge-bases/:kbId
/platform/knowledge-bases/:kbId/creatChat
/platform/chat/:chatid
Add a tiny tenantSwitch utility (navigateAfterTenantSwitch) that
matches the current path against this list and redirects to
/platform/knowledge-bases — the platform default landing, always
renderable regardless of role. Anything else (settings, agent
list, KB list, etc.) continues to reload its current path because
those views handle empty/forbidden data gracefully.
Both tenant-switch call sites (TenantSelector and UserMenu) use
the helper so the matrix lives in one place; future tenant-scoped
routes only need to add a regex to the list.
The previous PR removed the
"selectedTenantId === weknora_tenant.id → skip header" short-circuit
from the axios interceptor, but the same copy-pasted logic lived in
three more places that bypass axios:
- `api/chat/streame.ts` — `fetchEventSource` for the streaming chat
endpoint. Without this fix the chat reply would 404 with
"流式连接失败:HTTP 404" on the first message after switching to
a non-home tenant: the SSE call landed on the home tenant where
the freshly-created session did not exist.
- `api/initialization/index.ts` — native `fetch` for multimodal
test (FormData) requests. Misroutes the test to the home tenant.
- `utils/security.ts` — `getProtectedFileRequestHeaders` used by the
Markdown image proxy. Authenticated file fetches landed on the
home tenant, breaking image rendering after a tenant switch.
All three now mirror the simplified rule: if `weknora_selected_tenant_id`
is set, attach `X-Tenant-ID` unconditionally. The server's
`IsTenantAccessible` already accepts a header pointing at the user's
home tenant, so always attaching is safe.
Same root cause as the axios fix: any code path that writes the
active tenant into `weknora_tenant` (UserMenu's `loadUserInfo`, OIDC
sync, router hydrate) made the two values equal, after which these
non-axios paths silently dropped the header and re-routed to home.
When an Owner of tenant A invited user B as a Viewer, B could log in,
switch the active tenant from B's home to A via the user menu, and
still see every write button — Create KB, Upload Document, Edit/Delete
agent — because the role-gate plumbing on the client was wired to the
wrong tenant. The server's RBAC enforcement (PR 2 / PR 5) still blocked
the actual mutations with 403, so no data leaked, but the UI presented
authority the user did not have, which is a confusing and embarrassing
defect.
Five distinct root causes, all on the client / server boundary:
1. `currentTenantRole` (frontend/src/stores/auth.ts) read
`tenant.value.id` — the user's *home* tenant — instead of the active
tenant id. After switching to A, the helper still returned B's home
role (Owner), so every `hasRole(...)` gate in the codebase silently
short-circuited. Fix: read `selectedTenantId` first, fall back to
`tenant.id`.
2. `setMemberships` was only called once, on /auth/login. Hard reloads
(which the tenant switcher triggers) re-ran `getCurrentUser()` via
`App.vue` and `router/index.ts`, but those callers discarded the
`memberships` field of the response, so the auth store kept the
login-time snapshot forever. Role changes between sessions stayed
invisible. Fix: extract memberships in both /auth/me consumers and
feed them into `setMemberships`.
3. `KnowledgeBase.vue`'s `isOwner` compared `kb.tenant_id` to the
active tenant id, so any KB inside the current tenant was treated
as "owned by the caller" — bypassing every role gate below. Fix:
compare against `kb.creator_id` (the field PR 5 introduced) and
require an actual creator match. `canEdit` / `canManage` now layer
`hasRole('admin')` on top so a non-creator with sufficient role can
still manage.
4. `KnowledgeBaseList.vue` and `AgentList.vue` rendered the per-card
more-menu (Settings, Delete, Edit) unconditionally. With the
ownership column from PR 5 this is straightforward to gate on the
client: Settings/Delete now require creator-match or `hasRole('admin')`
per the server's `OwnedKBOrAdmin` / `OwnedAgentOrAdmin` matrix.
5. The axios interceptor (frontend/src/utils/request.ts) had a
"selectedTenantId === defaultTenantId → don't attach X-Tenant-ID"
short-circuit. Any code that wrote the active tenant into
`weknora_tenant` (UserMenu's loadUserInfo, OIDC sync, router
hydrate) made the two values equal, after which the header silently
stopped attaching and subsequent navigation requests landed on the
home tenant. Fix: drop the short-circuit; always attach when
selectedTenantId is set.
Server-side, /auth/me read `user.TenantID` (the immutable home tenant
id stamped at signup) when fetching the tenant for the response, so
the `tenant` field always pointed at home even after the auth
middleware had already resolved an active tenant from X-Tenant-ID.
The frontend then re-keyed `authStore.tenant` to the home tenant on
every refresh, undoing the switch. Fix: read the active tenant id from
context (`types.TenantIDFromContext(ctx)`) and only fall back to
user.TenantID when context is unset.
The server-side enforcement was correct throughout — every fix here is
purely about not lying to the user with the rendered UI.
Quick-answer agent mode retrieves purely through vector/keyword chunk
search and ships with no `allowed_tools`, so the existing capability
filter (which only reads from `allowed_tools`) let wiki-only KBs through
in every entry point. End result: users could @-mention, select, and
receive suggested questions from wiki-only KBs in quick-answer mode,
but the underlying retrieval always returned empty.
Treat "RAG-only" as an implicit property of `agent_mode = quick-answer`
and union it with the tool-derived filter. The same predicate is now
used everywhere the user can pick or be steered toward a KB:
Backend
- `tools.DeriveKBFilterForAgent` / `KBSatisfiesAgentRequirements`
layer the implicit quick-answer requirement on top of tool derivation.
- `ListKnowledgeBases`, `SearchKnowledge` (shared-agent `@file`),
`resolveKnowledgeBasesFromAgent` (chat runtime), `/search` IM command,
and `GetSuggestedQuestions` now all use the agent-mode-aware variant.
- `GetSuggestedQuestions` also skips the wiki-page fallback for
quick-answer agents to cover the `selected` / explicit-kb-ids paths
where a wiki-only KB could still slip through.
Frontend
- `deriveKbFilterForAgent` / `kbSatisfiesAgentRequirements` mirror the
Go helpers.
- `@` mention dropdown (`Input-field.vue`) uses the new helper.
- Agent editor's "specified KB" picker (`AgentEditorModal.vue`) grays
out wiki-only KBs for quick-answer agents with a tooltip, and the
pre-save warning fires for quick-answer mode too.
- i18n: add `agentEditor.agentType.kbMismatch.quickAnswer` across all
four locales.
The natural-stop path on the backend (observe.go Case 1) emits the same
content twice: once as streaming thinking chunks (from
streamThinkingToEventBus's per-chunk callback) which the frontend merges
into a single thinking event, and once as one big EventAgentFinalAnswer.
The result is that the intermediate-steps tree contains a thinking card
whose content is identical to the answer card rendered below it.
Detect this duplication and hide the offending thinking event from the
tree:
- New utils `normaliseForComparison` and `thinkingEqualsAnswer` perform
a tolerant comparison: strip <think>…</think> blocks (which leak into
raw thinking chunks but not into the post-StripThinkBlocks answer),
strip final-answer wrappers, collapse whitespace, then exact-equal or
±2% length with matching head/tail.
- `hiddenThinkingEventIds` (replacing the previous single-id
`promotedThinkingEventId`) now collects two cases of duplicate
thinking: the legacy promotion fallback (no answer event present) and
the natural-stop content-match case.
The final_answer-tool path is unaffected because reasoning thinking
events ("我找到了…让我整理…") and the answer payload have different
content and don't match the equivalence check.
Many models (especially smaller or non-OpenAI-style ones) do not reliably
call the structured final_answer tool, even when the system prompt
explicitly requires it. Two visible symptoms in the agent UI:
1. The natural-stop path emits the answer as a final_answer event whose
content is wrapped in <answer>...</answer>, <final_answer>...</final_answer>,
or prefixed with "Final Answer:" / "最终答案:". These wrappers were
rendered verbatim into the answer card.
2. When no answer event arrives at all, the trailing thinking event was
surfaced via the legacy fallback but kept its collapsed "思考" card
styling instead of rendering as a proper answer.
This change adds a small unwrap helper and wires it through the answer
rendering path:
- New util `unwrapFinalAnswerWrappers` strips conservative outer wrappers
(XML-style answer tags, fenced ```final_answer code blocks, and leading
"Final Answer:" / "最终答案:" prefixes) only when they cover the entire
trimmed content, so user markdown that happens to contain similar text
is left alone.
- `renderAnswerContent` and `getActualContent` apply the unwrap before the
markdown renderer / clipboard copy, so users see and copy clean text.
- The legacy "promote trailing thinking to final answer" fallback now
synthesizes a virtual answer event so it renders with the answer card
UI (expanded markdown + copy/add toolbar) instead of the collapsed
thinking card. The promoted thinking event is hidden from the
intermediate-steps tree to avoid duplication.
DOMPurify was configured with USE_PROFILES.svg, which implicitly allows
<style> tags so that inline SVG styling works. User-authored markdown
rendered via v-html therefore let a pasted nginx error page's
<style>body { width: 35em; margin: 0 auto }</style> through the
sanitizer and apply as global CSS, squashing the entire app layout.
Add 'style' to FORBID_TAGS so top-level style elements from document
content are dropped regardless of the SVG profile.
When WeKnora is mounted under a sub-path (Kubernetes Ingress with a
path-prefix rule, an Nginx `location /weknora/` block, a Cloudflare
Tunnel route, or any other reverse-proxy gateway), the frontend's
`getApiBaseUrl()` currently returns `''` and axios issues `/api/v1/...`
requests at the origin root — bypassing the sub-path entirely and
404'ing every backend call.
This change makes `getApiBaseUrl()` honor Vite's
`import.meta.env.BASE_URL` so that, when the bundle was built with e.g.
`vite build --base /weknora/`, axios produces `/weknora/api/v1/...`.
Trailing-slash stripped to avoid double slashes (`/weknora//api/v1/...`).
For deployments at the origin root (the common case), `BASE_URL`
defaults to `'/'` which strips to `''` — behavior unchanged from
upstream. No new build flag required; no behavior change for existing
users.
Reproduce the original problem:
1. cd frontend && vite build --base /weknora/
2. Serve dist/ behind Nginx at `location /weknora/`, proxy
/weknora/api/* → backend.
3. Open https://example.com/weknora/ → 404 on every API request
because axios calls /api/v1/auth/test instead of
/weknora/api/v1/auth/test.
After the fix the same setup just works.
Add Kingsoft Cloud KS3 as a supported storage provider, including
backend service implementation, storage config UI, and provider
scheme recognition throughout the codebase.
Add a list-view alongside the existing card grid (issue #957) and
multi-select batch delete (issue #1045) for documents inside a knowledge
base. The two views are toggled from the toolbar and the preference is
persisted in localStorage. Selection state is shared between views with
shift-range support and a sticky batch-action bar.
Backend
- POST /api/v1/knowledge/batch-delete: validates KB scope and editor
permission, then delegates to the existing DeleteKnowledgeList service
which already cascades vector/file/graph cleanup. Caps batch size at
200 and uses a single GetKnowledgeBatch call for membership validation.
Frontend
- DocumentListView: table layout with sticky header, checkbox column
(with indeterminate select-all), file-type icons, status badges,
per-row action menu.
- DocumentBatchBar: floating pill bar with selected count and delete
action; appears when items are selected.
- KnowledgeBase.vue: view-mode toggle, selection state, batch-delete
confirmation dialog, hover/active checkbox overlay on existing cards.
- Extracted formatFileSize and getFileIcon to utils/files.ts to share
with the new list view and avoid further drift from the existing
inline copies.
- i18n keys added for zh-CN, en-US, ko-KR, ru-RU.
Closes#1045Closes#957
The <t-icon> component from tdesign-vue-next lazily loads its SVG sprite
from https://tdesign.gtimg.com/icon/<ver>/fonts/index.js at runtime. In
air-gapped or intranet deployments this request fails and the whole UI
loses its icons (agent cards, knowledge-base breadcrumbs/cards, upload
buttons, etc.).
Ship the sprite (tdesign-icons-vue-next@0.4.1) as a static asset under
frontend/public/tdesign-icons/0.4.1/fonts/index.js and preload it from
index.html so every <t-icon name="..."> resolves against local symbols.
An offline guard injects stub <script>/<link> nodes that match tdesign's
dedup selectors, so checkScriptAndLoad / checkLinkAndLoad short-circuit
without ever hitting the CDN (covers both the 0.4.0 and 0.4.1 hardcoded
URLs for forward-compat).
Closes#867Closes#897
- Introduced a unified capability requirements system for agent tools, ensuring consistent filtering of knowledge bases based on their capabilities.
- Implemented derived `kb_filter` logic to streamline compatibility checks between agent tools and knowledge bases, reducing redundancy in configuration.
- Updated frontend components to reflect new filtering logic, including improved handling of empty states and user feedback when no compatible knowledge bases are available.
- Enhanced internationalization support by adding relevant messages for tool compatibility issues across multiple languages.
- Introduced a function to identify public authentication requests, preventing unnecessary token refresh attempts for specific endpoints.
- Simplified the redirection logic to the login page upon 401 errors, improving code readability and maintainability.
- Updated error handling to provide clearer messages for failed authentication attempts.
This update improves the request handling process, ensuring a smoother user experience during authentication flows.
- Removed support for video file uploads across the application, including updates to the knowledge base and document processing services.
- Updated internationalization files to reflect the removal of video-related terminology, changing labels and descriptions to focus solely on audio processing.
- Adjusted file type handling to exclude video formats, ensuring users receive accurate feedback regarding supported file types.
- Enhanced error handling to provide clear messages when users attempt to upload unsupported video files.
This update streamlines the application by focusing on audio processing capabilities and improving user experience through clearer messaging.
- Updated error handling in DataSourceSettings and DataSourceEditorDialog to provide more informative messages.
- Enhanced the UI to display error details more clearly, improving user experience during connection tests and resource loading.
- Adjusted HTTP response status checks in request utility for better accuracy in handling success responses.
- Added a new API for managing data sources, including CRUD operations and connection validation.
- Introduced UI components for data source settings, sync logs, and editor dialog, enhancing user experience in managing external data sources.
- Updated localization files to support new data source features in multiple languages.
- Implemented cron expression humanization for better scheduling visibility.
- Enhanced knowledge base editor to include data source management options.
The S3 storage adapter (s3.go) was added in e309e0b but the provider
scheme integration was incomplete — ParseProviderScheme() and frontend
security.ts were not updated, causing s3:// URLs to fail in the /files
proxy, VLM image processing, and frontend rendering.
Additionally, S3-compatible services (MinIO, Ceph, etc.) require
path-style addressing (endpoint/bucket/key) but the SDK client only
used virtual-hosted style. The deprecated WithEndpointResolver API
is replaced with BaseEndpoint, and path-style is auto-enabled for
non-AWS endpoints (detected by amazonaws.com in the URL).
Changes:
- types/knowledgebase.go: add "s3" to ParseProviderScheme()
- file/s3.go: auto path-style for S3-compatible endpoints + replace
deprecated WithEndpointResolver with BaseEndpoint
- frontend/security.ts: add s3 to 5 provider scheme allowlists
- knowledgebase_test.go: add ParseProviderScheme + InferStorage tests
- s3_test.go: add path-style detection + parseS3FilePath tests