- Added a new section for model type selection in ModelEditorDialog.vue, allowing users to choose between different model types with visual indicators.
- Updated the source selection logic to reflect changes in model type and ensure proper state management.
- Refactored related computed properties to utilize the active model type for better clarity and maintainability.
- Enhanced localization files (English, Korean, Russian, Chinese) to include new translations for model type and type label.
- Improved the layout and structure of ModelSettings.vue for better user experience and accessibility.
- 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.
- Added support for Tencent Cloud LKEAP Rerank, including new configuration options for SecretId and SecretKey.
- Updated frontend components to handle LKEAP-specific fields and enhance user experience with appropriate labels and placeholders.
- Enhanced backend logic to manage LKEAP credentials and integrate with the new rerank API.
- Improved localization for LKEAP-related terms across multiple languages, ensuring clarity and consistency in user-facing messages.
- Introduced tests for LKEAP Reranker functionality to ensure reliability and correctness in handling requests.
Added a connection test button in the ModelEditorDialog for remote sources, allowing users to verify API connectivity before saving. Improved the layout by restructuring the source selection section and updating the styling for better usability. Enhanced the drawer component with a customizable header and resizable width, improving the overall user experience. Updated localization files to reflect new UI elements and labels.
Test-connection's "连接失败" was nearly useless for debugging because
two layers conspired to swallow the actual upstream error:
Backend swallow
---------------
checkChatModelConnection and CheckASRModel pattern-matched on the
upstream error string (401 / 404 / timeout / ...) and replaced it with
a fixed Chinese hint. The original SDK message (request URL, response
body, provider's error code description) was discarded.
Refactor: extract classifyConnectionError(errMsg) — returns just the
short Chinese hint. Callers combine "<hint>:<raw err>" so the hint
indicates "where to start looking" and the raw error shows "what
actually happened". The status-400 special-case (endpoint reachable,
parameter mismatch only) still returns success.
Frontend swallow
----------------
ModelEditorDialog.testConnection ignored result.message on success
paths (fine), but also overwrote it with a generic i18n string on
failure paths and 4xx rejections — even though axios's interceptor
already lifts the backend's error.message to error.message. Failure
branch now uses error?.message || result.message as the toast content;
i18n fallback only when neither is present.
SSRF allowlist hint
-------------------
SSRF validation failures previously returned
"Base URL 未通过安全校验: <reason>" with no mention of how to recover
(the allowlist is server-side, not configurable in the UI). Operators
hit it and were stuck.
New utils.FormatSSRFError(label, rawURL, err) wraps the error with
guidance to add the host to SSRF_WHITELIST_EXTRA (the operator-facing
append-only escape hatch — SSRF_WHITELIST itself is the project's
baseline). The hint echoes the failed host so it can be copy-pasted
straight into the env var:
Base URL 未通过安全校验:DNS resolution failed for hostname
test.local.com ... 如该地址确实可信,请联系运维在服务端环境变量
SSRF_WHITELIST_EXTRA 中加入该主机(支持精确域名 / *.example.com
通配 / IP / CIDR),示例:SSRF_WHITELIST_EXTRA=test.local.com,
*.example.com,10.0.0.0/8
All SSRF call sites switch to the helper:
initialization (CheckRemoteModel / TestEmbedding / CheckRerank /
CheckASR / TestMultimodal / batch validation), model CRUD,
mcp_service CRUD, knowledge URL ingest, system ReconnectDocReader.
Direct regression from the previous credential subresource refactor: the
edit-mode ModelEditorDialog stopped binding apiKey into formData (the
field now lives in <CredentialResource>), so "Test connection" sent
apiKey="" and every upstream call (DeepSeek / lkeap / OpenAI etc.) 401'd.
Fix in the backend so the frontend stays simple:
- ModelTestRequest gains an optional ModelID field.
- New fillSecretsFromStoredModel helper: when ModelID is set AND a secret
field on the request is empty, copy it from the stored (decrypted) model.
Non-empty request values still win, so users typing a new key to verify
it before saving behave the same as before.
- The four test entrypoints (chat / embedding / rerank / asr) call the
helper right after ShouldBindJSON.
Frontend: ModelEditorDialog.testConnection forwards modelId when isEdit
is true. The four API client signatures accept the optional field.
WebSearch and MCP are unaffected: WebSearch already has a TestProviderByID
ID-based path, MCP has no standalone raw test endpoint.
Replace the legacy "redacted placeholder + Clear* boolean" pattern with
dedicated per-resource credential subresources across MCP services,
Models, Web search providers, and Data sources.
Why
---
The previous design had three problems:
1. Main PUT body carried secret fields. The frontend echoed back a
redacted "***" placeholder, and a fragile MergeUpdate / IsRedactedOrEmpty
defense in the service layer tried to detect "user did not change this"
vs "user wants to clear this". A regression in that defense (or a new
frontend forgetting it) silently overwrites the stored secret with the
placeholder.
2. The "remove this credential" UX was a red checkbox under a pre-filled
password input. Three intents (preserve / replace / clear) collapsed
onto one field, and credential changes were bundled with unrelated
config edits in the same submit. Users wiped working keys by mistake.
3. Secret presence was inferred from "did the response come back with a
'***' placeholder", which couples the contract to a magic string.
Design
------
Each of the four resources now exposes:
PUT /{resource}/{id}/credentials # write one or more fields
DELETE /{resource}/{id}/credentials/{field} # clear a single field
"Is this configured?" metadata travels on the main resource response as
a typed map (dto.MCPServiceResponse.Credentials etc.) — no separate GET
endpoint. The frontend reads the configured boolean from the main GET
and never sees secret values at all.
Main PUT endpoints now ignore any secret fields in the request body and
log a deprecation warning if they appear, so legacy clients fail loudly
rather than overwriting silently.
Frontend
--------
- New reusable <CredentialResource> component renders a three-state card
(unconfigured / configured / editing) and drives the dedicated
endpoints. Used by MCP, Model, Web search; DataSource has a bespoke
card with the same behaviour because its credentials are a single
atomic per-connector map.
- Cancel from edit mode now restores state synchronously from the meta
prop. The previous async refresh() was a no-op while state was still
'editing', leaving the input frozen open.
- Remove is single-click + toast. The danger-themed button is the
deterrent; a modal confirm adds friction without adding safety (the
plaintext is irrecoverable client-side either way — recovery means
re-typing).
DTOs (internal/handler/dto/) are deliberately separate from the GORM
models so "no secret in response" is a compile-time invariant: a future
contributor cannot leak a secret without explicitly adding the field to
the DTO, which is review-able in a single diff.
Storage is unchanged — credentials still live in the existing jsonb /
parameters columns. No schema migration.
Cleanup
-------
- types.MCPService / types.Model / types.WebSearchProviderEntity /
types.DataSourceConfig: drop ClearAPIKey / ClearToken / ClearAppSecret
/ ClearCredentials boolean fields, MergeUpdate(), RedactSensitiveData().
- utils/types/secret.go: drop PreserveIfRedacted / IsRedactedOrEmpty.
RedactedSecretPlaceholder constant is retained because VectorStore
still uses the old pattern and is out of scope here.
- Frontend hasExistingApiKey / clearApiKey / convertToLegacyFormat
redaction handling removed; i18n keys renamed secret -> credential.
Closes#988
Unify the "write-only secrets" pattern across MCP services, Models,
WebSearch providers, and DataSources. Fix two related defects:
1. GET responses leaked plaintext credentials — GetMCPServiceByID
while List masked, all Model / WebSearchProvider / DataSource GET
responses unconditionally.
2. When the frontend echoed a masked placeholder back on save, the
update path overwrote the stored secret with the mask — silently
wiping the real credential. MCP surfaced this most visibly:
ListMCPServices masked Token to "first4****last4" and
McpServiceDialog round-tripped that masked string back into the DB.
- internal/types/secret.go introduces the shared sentinel
RedactedSecretPlaceholder = "***" and two helpers:
- IsRedactedOrEmpty(s): true for "" or the sentinel
- PreserveIfRedacted(incoming, existing): merge predicate
- Each resource adds a RedactSensitiveData (mutates-in-place) or
Redacted (returns-a-copy) method and a MergeUpdate contract:
empty or placeholder preserves, any other value replaces, and a
write-only Clear* bool flag (gorm:"-", json omitempty) wipes with
precedence over preserve / replace. Clear* never persists.
- Every GET / List / Create / Update response path now redacts.
VectorStore's pre-existing "***" literal is refactored onto the
shared constant for consistency.
All four dialogs — McpServiceDialog, ModelEditorDialog,
WebSearchSettings, DataSourceEditorDialog — never pre-fill secret
inputs. The stored-state signal is collapsed into the input
placeholder: "•••••••• (Enter new value to replace)" when the server
reports a stored value, falling back to the connector-specific
placeholder otherwise. The input itself carries the "something is
there" cue, matching how password dots render.
An opt-in "Remove this credential" checkbox appears in edit mode when
a value is stored; checking it disables the input and triggers a
danger-themed confirmation dialog before submit. DataSource rolls the
clear up to a connector-level "Remove all credentials" flag since its
credentials are per-connector atomic bundles (e.g. Feishu app_id +
app_secret).
i18n updates across en-US, zh-CN, ko-KR, ru-RU:
secret.storedPlaceholder / clearHint / confirmClearTitle /
confirmClearBody.
- MCP update handler's manual map-to-struct projection was silently
dropping clear_api_key / clear_token / custom_headers on partial
updates. Pull them off the map explicitly.
- MCP configChanged detection now snapshots URL / StdioConfig /
TransportType before the merge so connection recycling still
triggers on real transport changes (not just whenever AuthConfig
is present).
- MCP CustomHeaders: nil preserves existing, non-nil replaces. Was
always overwriting, silently wiping headers on any auth-bearing
update.
- GetMCPServiceByID now redacts (was plaintext while List masked).
- WebSearchProvider update preserves Name / Description when empty
instead of clobbering them.
- WebSearchProvider TestProviderRaw rejects the "***" placeholder up
front with an actionable message rather than forwarding it to the
upstream provider API as a literal key.
- Model builtin hideSensitiveInfo now preserves non-secret metadata
(SupportsVision, Provider, ExtraConfig, InterfaceType,
ParameterSize, EmbeddingParameters) that were previously zeroed
out for builtin model cards.
- Replace local equalStringSlices / equalStringMaps helpers with
stdlib slices.Equal / maps.Equal (Go 1.21+).
- internal/types/{secret,mcp,model,web_search_provider,datasource}_test.go:
table-driven coverage of merge, redact, clear, and write-only flag
invariants for every resource.
- internal/application/service/mcp_service_test.go: full service layer
with a fake repo; covers ListMCPServices / GetMCPServiceByID
redaction, UpdateMCPService partial-update honoring of Clear*,
CustomHeaders preserve-on-nil / replace-on-non-nil, and
clear-flag precedence over submitted values.
Additive only. No changes to request or response JSON shape beyond
the write-only Clear* flags (omitted by default via omitempty). No DB
schema changes. No SDK struct field removals. Existing clients that
don't know about the new flags continue to function unchanged.
- DataSource.Config jsonb at-rest encryption. Pre-existing residual
risk; tracked as a follow-up.
- Renaming VectorStore.MaskSensitiveFields to match the new
RedactSensitiveData / Redacted naming convention. Left alone to
minimize diff; a follow-up rename PR can unify.
- Fix global `--td-brand-color-disabled` to use correct muted green instead of bright green
- Unify `variant="text"` buttons (refresh, download, check dimension) in model settings to inherit standard TDesign styles
- Adjust WeKnora Cloud credential status layout and change reconfigure button to outline
- Fix font size of external doc links in model settings hint blocks
- Increase font weight of KB chunking debug trigger for better visibility
- Add global .doc-link utility in theme.css (brand color text + link icon, underline on hover).
- Convert all external doc/console links across settings to use .doc-link with a trailing <t-icon name="link" />, matching the Ollama browse-library style.
- Switch primary section-toolbar 'Add X' buttons (Model/WebSearch/VectorStore/MCP/DataSource) to outline variant for a lighter, more consistent look.
- Drop redundant per-component CSS for builtin-hint-link, weknoracloud-hint-link, engine-doc-link, engine-link, hint-link, section-doc-link, ds-doc-link-inline, model-link, etc.
- Add global t-radio-button outline styles in theme.css (brand fill when checked).
- Align ModelEditor, share KB, datasource, agent/MCP settings with t-radio-button.
- Remove redundant :deep overrides in AgentEditorModal, KB editor, FAQEntryManager, etc.
- Use brand disabled tone for disabled+checked radio buttons so selection stays visible.
Aligns the three list-style settings pages (ModelSettings, WebSearchSettings,
McpSettings) under a consistent visual language, and replaces the modal editors
with right-side drawers for a calmer editing flow.
- Extract shared building blocks under frontend/src/components/settings/:
SettingCard (list-item card), SettingDrawer (500px right drawer with a
pinned footer), and useConfirmDelete (a single DialogPlugin.confirm path
that replaces the mix of window.confirm / t-popconfirm / ad-hoc dialogs).
- Swap the old bespoke overlay / t-dialog shells in ModelEditorDialog and
McpServiceDialog for SettingDrawer. Form logic is untouched.
- Model settings now use a single t-tabs filter (All/Chat/Embedding/ReRank/
Vision/Speech with per-type counts) and decouple "Add model" from the tab
state via a dropdown in the header. Type tags get a 5-color palette so
categories read at a glance. The list is a two-column grid.
- Web search and MCP lists are likewise rendered as two-column grids, with
richer cards: transport type / provider, on-off and default state, plus a
compact meta row showing base URL, proxy or service URL.
- Introduce modelSettings.typeShort.{chat,embedding,rerank,vllm,asr} in all
four locales for the shortened category labels.
Introduce per-model `custom_headers` config (similar to OpenAI Python SDK's
`extra_headers`) so users can inject gateway auth tokens, trace IDs, etc.
into every outbound API request for chat / embedding / rerank / VLLM / ASR
models. Reserved headers like Authorization / Content-Type are always
preserved to avoid breaking auth or signing flows.
Along the way, unify production and "test connection" paths onto a single
`ConfigFromModel(*types.Model, appID, appSecret)` constructor in each
model package. Both `service.modelService.GetXxxModel` and the four
`handler.initialization.Check*Model` / `TestEmbeddingModel` endpoints now
go through the same field mapping, so new parameters only need to be
added in one place.
Backend:
- Add `CustomHeaders map[string]string` to `types.ModelParameters` with
JSON/YAML `omitempty` tags for forward compatibility.
- New `internal/utils/extraheaders.go` providing `ApplyCustomHeaders`
(for hand-rolled HTTP paths) and `WrapHTTPClientWithHeaders` /
`CustomHeadersRoundTripper` (for SDK paths like go-openai). Reserved
headers (Authorization, api-key, Content-Type, Accept, Host,
Content-Length, User-Agent) are filtered out.
- Inject headers in every remote model path: chat (SDK + raw HTTP),
embedding (openai/aliyun/jina/volcengine/nvidia/azure_openai), rerank
(remote_api/aliyun/jina/nvidia/zhipu — via shared `customHeaderSetter`
interface), VLM and ASR (via http.Client wrapping).
- Add `ConfigFromModel` to each of chat/embedding/rerank/vlm/asr,
consolidating field mapping (ExtraConfig, CustomHeaders, InterfaceType
defaulting, WeKnoraCloud credentials, etc.) and cover it with
dedicated unit tests per package.
- Refactor `service/model.go`: replace ~100 lines of hand-written Config
literals with one-line `ConfigFromModel` calls; drop the now-unused
`stringMapToAnyMap` helper.
- Refactor `handler/initialization.go` test-connection endpoints: merge
four ad-hoc request structs into one `ModelTestRequest`, extract
`buildTestModel` and `resolveTenantWeKnoraCloudCreds` helpers, and
route all four endpoints through `ConfigFromModel` + `NewXxx` so the
test path is now behaviorally identical to production.
Frontend:
- Add `custom_headers` to the `ModelConfig` API type.
- `ModelEditorDialog.vue`: new Key-Value header editor (add/remove rows),
auto-converts map <-> array when loading/saving, and passes the
current header set to the `Test Connection` button so the preview
reflects exactly what production will send.
- `ModelSettings.vue`: serialize the header array back into a map for
the backend (drops empty rows).
- i18n: add custom-header labels / descriptions / placeholders to
zh-CN, en-US, ru-RU, ko-KR.
Tests:
- `internal/utils/extraheaders_test.go` covers reserved-header filtering
and round-tripper wrapping (including nil-client fallback).
- New `config_from_model_test.go` in chat / embedding / rerank / vlm /
asr verifies all fields (CustomHeaders, ExtraConfig, InterfaceType
defaulting, AppID/AppSecret) are propagated end-to-end.
- Updated the WeKnoraCloud settings and related components to utilize i18n for improved localization.
- Replaced hardcoded strings with translation keys for better maintainability and user experience.
- Enhanced user feedback messages for credential status, including configuration, expiration, and unconfiguration states.
- Improved UI elements to guide users in managing WeKnoraCloud credentials effectively.
This update streamlines the user interface and ensures consistent messaging across different languages.
- Introduced a new WeKnoraCloudSettings component for managing APPID and APPSECRET.
- Added functionality to save WeKnoraCloud credentials without automatically creating models.
- Implemented credential status checks across various components to provide user feedback on configuration status.
- Updated API endpoints to handle credential saving and status retrieval.
- Enhanced UI elements to guide users in configuring WeKnoraCloud settings.
This update improves the integration of WeKnoraCloud by allowing users to manage their credentials more effectively and receive real-time feedback on their configuration status.
- Implemented a new function to check ASR model connectivity via the /v1/audio/transcriptions endpoint.
- Updated ModelEditorDialog.vue to integrate ASR model checks and adjust UI elements accordingly.
- Enhanced localization files to reflect changes in ASR terminology and descriptions.
- Added ASR configuration options to the knowledge base and updated related migration scripts.
- Refactored model handling to support ASR as a distinct model type in the application.
- Added ASR configuration options to the knowledge base and model settings.
- Implemented ASR model selection and transcription capabilities in the knowledge processing pipeline.
- Enhanced file upload support to include audio formats for ASR processing.
- Updated localization files to include ASR-related labels and descriptions.
- Refactored model handling to accommodate ASR as a new model type.
- Simplified model filtering logic by removing the deduplication function and directly filtering models based on type.
- Updated SSRF validation to preserve backend-managed fields when parameters are not provided by the frontend.
- Clarified comments and improved code readability in the ModelEditorDialog and ModelSettings components.
Add Novita AI as a new model provider supporting chat, embedding,
and VLLM model types via OpenAI-compatible API endpoint.
- Add NovitaProvider implementation with OpenAI-compatible API
- Register ProviderNovita in provider registry
- Add ModelSourceNovita constant
- Add Novita to frontend fallback provider options
- Add i18n translations for en-US, zh-CN, ru-RU, ko-KR
- 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.
- Synchronize 2641 i18n keys across all 4 locales (en-US, zh-CN, ko-KR, ru-RU)
- Add TDesign ConfigProvider with dynamic locale to ensure all UI
components (select, input, empty states, dialogs) display in the
user's chosen language
- Fix provider dropdown in model editor: use i18n keys with API fallback
- Fix connection test messages: always use i18n for user-facing feedback
- Add explicit placeholders to t-select components in settings pages
- Add missing i18n keys: theme.selectTheme, organization role selectors,
lkeap provider translations
- Refactored CSS variables for consistent theming, replacing hardcoded colors with CSS variables for better maintainability.
- Updated various components including `AgentAvatar`, `AgentSelector`, and `AgentShareSettings` to utilize new theme variables for colors, backgrounds, and shadows.
- Enhanced SVG icons to use `currentColor` for better adaptability to theme changes.
- Improved overall UI consistency by aligning styles with the new theming approach, enhancing user experience across the application.
These changes significantly improve the visual coherence and maintainability of the UI, ensuring a more seamless user experience.
- Introduced a new option for users to upload entire folders, improving document management capabilities.
- Enhanced file type verification to provide better feedback for unsupported files during uploads.
- Updated UI components in the menu for clearer action items related to document uploads.
- Improved localization support for new upload messages in English, Russian, and Chinese.
- Introduced `is_builtin` property in the model configuration to identify builtin models.
- Updated frontend components to display a tag for builtin models in the ModelSelector and ModelSettings.
- Enhanced the ModelEditorDialog to prevent editing and deletion of builtin models.
- Implemented logic in the backend to hide sensitive information for builtin models and restrict their modification.
- Added informative UI elements to clarify the nature of builtin models in the settings and editor views.
- Added vue-i18n integration to various components for dynamic text translation.
- Updated text placeholders, button labels, and error messages to utilize translation functions.
- Enhanced user experience by providing localized content in the Knowledge Base, chat components, and settings.
- Removed hardcoded strings and replaced them with translation keys for better maintainability and scalability.
- Introduced a new method to handle navigation to agent settings, improving code organization and reusability.
- Updated tooltip content in the agent mode button to include a link for quick access to agent settings.
- Enhanced error handling in the KnowledgeBase component to provide actionable links for VLM configuration errors.
- Added initial section handling in the KnowledgeBaseEditorModal for improved user experience during knowledge base editing.
- Added 'logs/' and '*.pid' to .gitignore to exclude log files and process ID files from version control.
- Expanded Makefile with new development commands for easier local environment management, including 'dev-start', 'dev-stop', 'dev-restart', 'dev-logs', 'dev-status', 'dev-app', and 'dev-frontend'.
- Updated README_CN.md to include instructions for the new development mode and commands for improved developer experience.
- Replaced the dialog component with a custom modal layout for better user experience.
- Enhanced form structure with custom styles and validation for required fields.
- Updated model source selection and added dynamic placeholders based on model type.
- Improved API validation logic for model saving in both ModelEditorDialog and ModelSettings.
- Refactored styles for better alignment and responsiveness across components.