Commit Graph

598 Commits

Author SHA1 Message Date
Claude b7f9f155b3 fix(knowledge): prevent infinite scroll race condition causing missing documents
The knowledge base file list infinite scroll had a race condition:
- page++ executed before the condition check, causing page numbers
  to be skipped when scroll events fired rapidly
- No loading guard meant concurrent API requests could overlap,
  with later responses overwriting earlier ones

This caused documents to not load when scrolling to the bottom
of the file list, especially noticeable with 100+ files where
only the first page would reliably appear.

Changes:
- Add scrollLoading flag to prevent concurrent scroll-triggered fetches
- Move page++ inside the condition check (was unconditional before)
- Use resetPage() helper to consistently reset both page and loading state
- Change scroll trigger threshold from >= scrollHeight to >= scrollHeight - 10
  for better trigger sensitivity
2026-05-16 16:55:30 +08:00
wolfkill 5a81441637 fix(model): hide Ollama tip for remote models 2026-05-16 02:20:58 +08:00
wizardchen 6f95c75ed2 feat(system-info): surface DB migration errors with troubleshooting links
When a startup database migration fails (e.g. issue #1319: pg_trgm not
available so 000041 cannot build its trigram index), the application
intentionally keeps booting so operators can reach the UI to diagnose.
However, before this change the system info page silently dropped the
"DB Version" row because the value was empty:

  - migration.go only cached the version after a successful m.Up(); the
    error path returned early and left migrationVersionSet=false.
  - system.go used CachedMigrationVersion's ok=false to skip emitting
    db_version, and the JSON tag was already omitempty.
  - SystemInfo.vue gated the entire row on v-if="systemInfo?.db_version".

The end result was the most useful diagnostic surface vanishing in the
exact failure mode that needs it most — Wiki ingest and KG features
would silently produce nothing with no UI hint.

Changes:

  - migration.go: replace sync.Once-based setter with an RWMutex-guarded
    state struct holding {version, dirty, err}. Every failure path now
    calls captureMigrationFailure(m, err), which best-effort reads
    m.Version() so the cached value still reflects the partial state.
  - system.go (handler): always emit db_version (falling back to
    "unknown" when no version could be read), append " (failed)" when an
    error is recorded, and add db_migration_error to the response.
  - swagger / client SDK: keep the API contract in sync with the new
    response field.
  - SystemInfo.vue: render the DB version row whenever either field is
    present, show a "Migration failed" danger tag, and add a full-width
    alert below the row carrying the error message plus two links:
      1. View troubleshooting guide -> new docs/migration-troubleshooting.md
      2. Report an issue -> github.com/Tencent/WeKnora/issues/new,
         prefilled with the captured error and environment metadata.
  - docs/migration-troubleshooting.md: new self-service guide covering
    the common failure modes (missing extension, dirty state, privileges,
    out of disk, schema drift) with concrete psql / make commands.
  - i18n: add the new keys to zh-CN, en-US, ko-KR, ru-RU.

Refs #1319.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 16:34:50 +08:00
guangyang1206 a7d30f73ca fix(frontend): make rerank model optional in agent editor save
The runtime chat pipeline (internal/application/service/chat_pipeline/rerank.go:56)
already skips rerank when rerank_model_id is empty, so it should not be
required at save time.

The editor incorrectly required rerank_model_id whenever a RAG KB was
selected, even though the field is optional. This fix removes the
validation so users can save agents without configuring a rerank model.

Fixes #1252
2026-05-14 10:48:19 +08:00
wizardchen 6cb493eda2 feat(frontend): show UI build version on system info page
Inject the frontend package.json version at build time via Vite and
render it as a dedicated "UI Version" row in System Info, alongside
the existing app (backend) version returned by /system/info. When the
two versions differ a warning tag is shown so users can tell at a
glance that their weknora-ui image is out of sync with weknora-app
(e.g. missing config fields for newer providers like SearXNG).

Rename the existing version row label from "System Version" to
"App Version" to distinguish it from the new UI version row in all
four locales (zh-CN, en-US, ko-KR, ru-RU).
2026-05-13 17:54:15 +08:00
wizardchen 80bd268862 chore: release v0.5.2
Bump version to v0.5.2 across VERSION, Helm chart, frontend package
files, and cloud-image script comment. Update CHANGELOG and all four
language READMEs with v0.5.2 highlights (Wiki Mode at scale, MCP
human-in-the-loop approval, new LLM/vector/storage/search backends,
adaptive 3-tier chunking, global command palette, CLI preview, etc.).
2026-05-13 15:04:15 +08:00
wizardchen ec2b44494f fix(frontend): show reasoning_content in historical agent steps
Tool-calling rounds emit reasoning into the OpenAI-protocol
reasoning_content field rather than visible content, so AgentStep.Thought
is often empty in DB. The history reconstructor only read step.thought,
which made the historical step card silent for those rounds even though
the user saw the reasoning live.

Fall back to step.reasoning_content when step.thought is empty so
reload mirrors the live experience.
2026-05-13 13:36:51 +08:00
wizardchen 1ae06fb857 docs(frontend): clarify Wiki page-link graph vs entity-relation knowledge graph
The Wiki browser exposes a page-link graph (references between Wiki pages)
while KB Settings → Knowledge Graph configures an LLM-extracted
entity-relationship graph. Both are labeled "图谱"/"Graph", which is easy
to confuse.

- Expand graphSettings.description to call out the distinction
- Add tabGraphTip tooltip on the Wiki "图谱" breadcrumb tab
- Extend wikiBrowser.graphNoData empty state with the same clarification
- Update zh-CN, en-US, ko-KR, ru-RU consistently
2026-05-13 00:43:38 +08:00
wizardchen f58139a945 fix(frontend): persist graph extract toggle state on KB save (#1297)
The "启用实体关系提取" switch in GraphSettings was silently dropped on
save: buildSubmitData only attached extract_config to the request when
both indexingStrategy.graphEnabled AND nodeExtractConfig.enabled were
true. When the graph indexing strategy was off (the default), the
toggle change never reached the backend and reloading the KB always
showed the switch as off.

Always emit extract_config based on the user's actual toggle state so
the value round-trips correctly through updateKBConfig regardless of
the indexing strategy selection.
2026-05-13 00:40:58 +08:00
wizardchen 55caeefc3d feat(observability): log end-to-end TTFB on both ends of chat stream
To diagnose where latency lives between "user hits send" and "first
token appears" we need a single number that can be matched across
the browser console and the server log. Add correlated TTFB markers
keyed by X-Request-ID:

Frontend (streame.ts)

* Generate the X-Request-ID once and reuse it for logging.
* Log request:start when fetchEventSource is invoked, response:headers
  when onopen fires, and response:first_answer the first time an SSE
  payload with response_type === 'answer' arrives. Filtering by event
  type avoids treating session_title / references / tool_call as the
  "first token".

Backend (session handler)

* parseQARequest records the wall-clock entry time and logs TTFB:start
  with the same X-Request-ID.
* qaRequestContext carries receivedAt through to the stream handler.
* AgentStreamHandler emits a one-shot TTFB:first_answer_chunk log the
  first time it observes an AgentFinalAnswerData chunk, so the delta
  against TTFB:start is the server's request-in → first-token-out
  budget.

The frontend delta minus the backend delta is then attributable to
network + gin middleware, which were previously invisible.
2026-05-12 21:16:37 +08:00
wizardchen 64b20a2d87 feat(agent): support dedicated model for query understanding step
Quick-answer (RAG) agents can now configure a separate chat model for
the query-understanding stage (rewrite + intent classification),
decoupling it from the main conversation model so users can route the
lightweight rewrite call to a cheaper / faster model.

- Add CustomAgentConfig.QueryUnderstandModelID and plumb it through
  PipelineRequest and ChatManage.Clone.
- query_understand plugin prefers QueryUnderstandModelID on the
  text-only path; falls back to ChatModelID if the configured model
  cannot be resolved (with a warn log). Multimodal path is unchanged
  to keep vision-capable model selection intact.
- AgentEditorModal exposes a ModelSelector under the existing Query
  Rewrite block; empty means reuse the main chat model.
- Add i18n strings (queryUnderstandModel / placeholder / desc) for
  zh-CN, en-US, ko-KR, ru-RU.
- Extend Go SDK AgentConfig with the new field.
2026-05-12 20:27:20 +08:00
wizardchen 1f60d19f1b fix(agent-editor): move data-analysis toggle to retrieval section
The data-analysis pipeline stage is a retrieval-strategy concern (it only
runs after chunk search/rerank), so the toggle belongs alongside the other
retrieval knobs rather than under knowledge base settings.

Refs: https://github.com/Tencent/WeKnora/issues/1244
2026-05-12 19:46:31 +08:00
wizardchen 3f9b09e306 fix(pipeline): make data-analysis stage opt-in per agent (#1244)
The legacy in-pipeline DuckDB SQL data-analysis stage used to run on every
quick-answer RAG request whose retrieved chunks included a CSV/Excel file,
adding one extra LLM round-trip (~3s) to generate a SQL query that most
plain Q&A users never wanted. There was no way to disable it.

Introduce a per-agent DataAnalysisEnabled flag (default off), wire it
through PipelineRequest, and gate the DATA_ANALYSIS stage on it. Surface
the toggle in the agent editor for quick-answer agents with at least one
knowledge base attached.

Refs: https://github.com/Tencent/WeKnora/issues/1244
2026-05-12 19:39:35 +08:00
wizardchen cacca049d9 feat(knowledge-base): document list filters and explicit batch-management UX
Add three new optional filters to the document list under a knowledge base
detail page — parse status, source/channel, and updated time range — and
rework multi-select to no longer cause the card title to jitter on hover.

Backend
- Introduce types.KnowledgeListFilter to aggregate optional filter dimensions
  (tag, keyword, file_type, parse_status, source, updated_from/to) and switch
  ListPagedKnowledgeByKnowledgeBaseID (repository/service/interface) to accept
  it instead of a growing positional parameter list.
- The ListKnowledge HTTP handler accepts new parse_status, source, start_time
  and end_time query params; time params accept RFC3339, "YYYY-MM-DD HH:MM:SS"
  and "YYYY-MM-DD". The repository routes source="manual"/"url" onto the type
  column to stay consistent with file_type semantics; other source values match
  the channel column.
- Update the four other callers (agent_service, initialization) to pass an
  empty filter struct, preserving prior behavior.

Frontend
- Add three controls in the doc-filter-bar (status select, source select,
  date-range picker with future-date disabled) wired through getKnowled /
  listKnowledgeFiles into the new backend params.
- Replace the hover-triggered card checkbox with an explicit "批量管理" mode
  (mirrors the session list UX): in card view the checkbox only renders while
  batch mode is on, entered via the per-card "..." menu; the list view keeps
  its leading checkbox column. Switching from list to grid auto-enables batch
  mode when something is already selected, so the selection stays visible.
- DocumentBatchBar now stays open whenever batch mode or selection > 0, and
  its "取消选择" button both clears the selection and exits batch mode.

API surface sync
- Regenerate Swagger artifacts (docs/docs.go / swagger.json / swagger.yaml).
- Update docs/api/knowledge.md with the new query parameters.
- Add backward-compatible ListKnowledgeWithFilter + KnowledgeListFilter to the
  Go SDK; the existing ListKnowledge keeps its signature.

i18n
- New filter labels in zh-CN / en-US / ko-KR / ru-RU; reuse existing
  menu.batchManage / batchManage.cancel for the multi-select strings.
2026-05-12 18:29:47 +08:00
langcaiye 42d98261e7 feat: support Anthropic chat provider 2026-05-12 17:33:16 +08:00
wizardchen 5949be739f fix(agent): relax rerank model requirement for custom agents
Previously the custom agent editor hid the rerank model field when no
RAG-type knowledge base existed in the configured scope, but the
not-ready check and runtime hard-failed whenever knowledge_search was
in allowed_tools. Users with wiki-only or empty scopes saw "Rerank
Model required" warnings they could not resolve, and "All knowledge
bases" agents broke later if a RAG-type KB was added.

- Backend: when knowledge_search is enabled, fall back to the tenant
  default rerank model (ConversationConfig.RerankModelID) before
  erroring out, matching the built-in agent behaviour.
- Editor: always show the rerank field once a KB scope is selected;
  only mark it required (red *) when the scope contains a RAG KB, with
  a hint explaining the tenant-default fallback.
- Editor: only render rerank top_k / threshold sliders when a rerank
  model is actually selected.
- Input field: drop the eager "missing rerank" not-ready reason; the
  backend is now the single source of truth for rerank availability.
- i18n: add agent.editor.rerankModelOptionalHint across all locales.
2026-05-12 16:57:24 +08:00
wizardchen d199628701 fix(agent): exclude wiki-only KBs from quick-answer (RAG) mode
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.
2026-05-12 16:27:28 +08:00
dependabot[bot] d2fb51b809 chore(deps-dev): bump typescript from 5.8.3 to 6.0.3 in /frontend
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.8.3 to 6.0.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.8.3...v6.0.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 6.0.3
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-12 14:29:51 +08:00
dependabot[bot] ae1ea181f5 chore(deps): bump the frontend-deps group in /frontend with 15 updates
Bumps the frontend-deps group in /frontend with 15 updates:

| Package | From | To |
| --- | --- | --- |
| [axios](https://github.com/axios/axios) | `1.15.0` | `1.16.0` |
| [mermaid](https://github.com/mermaid-js/mermaid) | `11.14.0` | `11.15.0` |
| [pagefind](https://github.com/Pagefind/pagefind) | `1.3.0` | `1.5.2` |
| [pinia](https://github.com/vuejs/pinia) | `3.0.3` | `3.0.4` |
| [swiper](https://github.com/nolimits4web/Swiper) | `12.1.2` | `12.1.4` |
| [tdesign-icons-vue-next](https://github.com/Tencent/tdesign-icons/tree/HEAD/packages/vue-next) | `0.4.1` | `0.4.4` |
| [tdesign-vue-next](https://github.com/Tencent/tdesign-vue-next/tree/HEAD/packages/tdesign-vue-next) | `1.17.2` | `1.19.2` |
| [vue-demi](https://github.com/antfu/vue-demi) | `0.14.6` | `0.14.10` |
| [vue-i18n](https://github.com/intlify/vue-i18n/tree/HEAD/packages/vue-i18n) | `11.1.12` | `11.4.2` |
| [webpack](https://github.com/webpack/webpack) | `5.105.2` | `5.106.2` |
| [@tsconfig/node22](https://github.com/tsconfig/bases/tree/HEAD/bases) | `22.0.2` | `22.0.5` |
| [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue) | `6.0.0` | `6.0.6` |
| [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue-jsx) | `5.0.1` | `5.1.5` |
| [@vue/tsconfig](https://github.com/vuejs/tsconfig) | `0.7.0` | `0.9.1` |
| [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) | `3.2.5` | `3.2.8` |


Updates `axios` from 1.15.0 to 1.16.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.15.0...v1.16.0)

Updates `mermaid` from 11.14.0 to 11.15.0
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.14.0...mermaid@11.15.0)

Updates `pagefind` from 1.3.0 to 1.5.2
- [Release notes](https://github.com/Pagefind/pagefind/releases)
- [Changelog](https://github.com/Pagefind/pagefind/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Pagefind/pagefind/compare/v1.3.0...v1.5.2)

Updates `pinia` from 3.0.3 to 3.0.4
- [Release notes](https://github.com/vuejs/pinia/releases)
- [Commits](https://github.com/vuejs/pinia/compare/v3.0.3...v3.0.4)

Updates `swiper` from 12.1.2 to 12.1.4
- [Release notes](https://github.com/nolimits4web/Swiper/releases)
- [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nolimits4web/Swiper/compare/v12.1.2...v12.1.4)

Updates `tdesign-icons-vue-next` from 0.4.1 to 0.4.4
- [Changelog](https://github.com/Tencent/tdesign-icons/blob/develop/packages/vue-next/CHANGELOG.md)
- [Commits](https://github.com/Tencent/tdesign-icons/commits/HEAD/packages/vue-next)

Updates `tdesign-vue-next` from 1.17.2 to 1.19.2
- [Release notes](https://github.com/Tencent/tdesign-vue-next/releases)
- [Changelog](https://github.com/Tencent/tdesign-vue-next/blob/develop/packages/tdesign-vue-next/CHANGELOG.en-US.md)
- [Commits](https://github.com/Tencent/tdesign-vue-next/commits/tdesign-vue-next@1.19.2/packages/tdesign-vue-next)

Updates `vue-demi` from 0.14.6 to 0.14.10
- [Release notes](https://github.com/antfu/vue-demi/releases)
- [Commits](https://github.com/antfu/vue-demi/compare/v0.14.6...v0.14.10)

Updates `vue-i18n` from 11.1.12 to 11.4.2
- [Release notes](https://github.com/intlify/vue-i18n/releases)
- [Changelog](https://github.com/intlify/vue-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n/commits/v11.4.2/packages/vue-i18n)

Updates `webpack` from 5.105.2 to 5.106.2
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.105.2...v5.106.2)

Updates `@tsconfig/node22` from 22.0.2 to 22.0.5
- [Commits](https://github.com/tsconfig/bases/commits/HEAD/bases)

Updates `@vitejs/plugin-vue` from 6.0.0 to 6.0.6
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@6.0.6/packages/plugin-vue)

Updates `@vitejs/plugin-vue-jsx` from 5.0.1 to 5.1.5
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue-jsx/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@5.1.5/packages/plugin-vue-jsx)

Updates `@vue/tsconfig` from 0.7.0 to 0.9.1
- [Release notes](https://github.com/vuejs/tsconfig/releases)
- [Commits](https://github.com/vuejs/tsconfig/compare/v0.7.0...v0.9.1)

Updates `vue-tsc` from 3.2.5 to 3.2.8
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v3.2.8/packages/tsc)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: mermaid
  dependency-version: 11.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: pagefind
  dependency-version: 1.5.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: pinia
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: swiper
  dependency-version: 12.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: tdesign-icons-vue-next
  dependency-version: 0.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: tdesign-vue-next
  dependency-version: 1.19.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: vue-demi
  dependency-version: 0.14.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: vue-i18n
  dependency-version: 11.4.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: webpack
  dependency-version: 5.106.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: "@tsconfig/node22"
  dependency-version: 22.0.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: "@vitejs/plugin-vue"
  dependency-version: 6.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
- dependency-name: "@vitejs/plugin-vue-jsx"
  dependency-version: 5.1.5
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: "@vue/tsconfig"
  dependency-version: 0.9.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: frontend-deps
- dependency-name: vue-tsc
  dependency-version: 3.2.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: frontend-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-12 13:30:24 +08:00
wizardchen 0f5dc41f4e feat(searxng): enhance SearXNG configuration and validation
- Updated .env.example to clarify SEARXNG_SECRET generation and added SSRF_WHITELIST_EXTRA for improved security.
- Modified docker-compose files to bind SearXNG to localhost by default and introduced a one-time initialization service to set up settings.yml correctly.
- Enhanced SearxngProvider with stricter URL validation, ensuring no query or fragment is present in the base URL.
- Added unit tests for SearXNG validation and date parsing to ensure robustness.
- Updated frontend WebSearchSettings to reflect changes in SearXNG instance URL handling.

This commit improves the security and usability of the SearXNG integration, addressing potential misconfigurations and enhancing the developer experience.
2026-05-11 16:53:47 +08:00
wizardchen d2a1006beb fix(web-search): address review fixups for SearXNG provider
- utils: 合并 SSRF_WHITELIST 与 SSRF_WHITELIST_EXTRA,避免部署侧默认值
  (如 docker-compose 注入的 searxng 主机名)被用户的 SSRF_WHITELIST
  自定义值覆盖。
- docker-compose.yml: 把 searxng 默认值挪到 SSRF_WHITELIST_EXTRA。
- searxng: 抽出导出函数 ValidateSearxngBaseURL,让 service 层保存校验
  和 provider 构造校验完全一致;service 改为调用同一函数。
- searxng: language 由非法的 "auto" 改为 "all";移除强制 safesearch=1
  让实例 settings.yml 决定。
- searxng: publishedDate 增加多格式 fallback(RFC3339Nano/无时区/
  日期-only/RFC1123 等),无法解析时 debug 日志记录。
- searxng: 解析 unresponsive_engines;结果为空时打 warn 日志,便于排查
  "配置正确却搜不到结果"的情况。
- frontend: WebSearchSettings 的 Instance URL 标签/占位符走 i18n,
  zh-CN / en-US / ru-RU / ko-KR 四个 locale 补齐 baseUrlLabel /
  baseUrlPlaceholder。
2026-05-11 16:53:47 +08:00
wizardchen 1110615300 feat(web-search): add SearXNG provider (#1166)
支持对接自建/公共 SearXNG 实例作为网络搜索引擎,缓解免费搜索引擎在国内
网络环境下访问受限的问题。

- types: 新增 WebSearchProviderTypeSearxng 与 BaseURL 参数字段;
  类型元数据新增 RequiresBaseURL,前端可动态渲染 Instance URL 表单。
- infrastructure/web_search/searxng.go: 调用 /search?format=json,强制
  utils.ValidateURLForSSRF 校验 base_url,可选 api_key 透传给反代鉴权。
- service: isValidProviderType 与参数校验接入 searxng。
- container: 注册 NewSearxngProvider 工厂。
- frontend: WebSearchSettings 表单根据 requires_base_url 渲染 Instance
  URL 输入框;编辑回填、free 判定同步更新。
- docker: 新增可选 searxng 服务(profile=searxng/full),附带最小化
  settings.yml(启用 JSON 格式、关闭 limiter、关闭遥测),
  docker-compose 默认 SSRF_WHITELIST 包含 searxng 容器名。
- .env.example: 补充 SEARXNG_PORT / SEARXNG_SECRET 说明。

Closes #1166
2026-05-11 16:53:47 +08:00
wizardchen 9dcb61fb45 feat(frontend): enable gzip compression for static resources in nginx configuration
- Added gzip compression settings to improve loading times for static assets, significantly reducing the size of files served and enhancing performance for users, especially in low bandwidth regions.
2026-05-11 15:51:11 +08:00
wizardchen 5510ea8f5a feat(agent): human-in-the-loop approval for MCP tool calls (#1173)
Add an opt-in human approval gate so Agent runs pause before executing
MCP tools that operators flag as dangerous, surface an approval card in
the chat UI, and only resume after the user approves (optionally with
edited args) or rejects.

Backend
- New mcp_tool_approvals table + repo/service to mark per-tool approval
  required (PG migration 000042 + sqlite init).
- approval.Gate coordinates RequestAndWait / Resolve with sync.Once
  delivery, configurable timeout, and Redis Pub/Sub fan-out so multi-
  replica deployments work without sticky sessions.
- MCPTool.Execute integrates the gate; uses a round-level ApprovalCtx
  (without the per-tool 60s timeout) for the wait, and re-derives a
  fresh 60s exec ctx after approval so CallTool keeps a full window.
- New SSE response types (tool_approval_required / _resolved) and
  EventBus events plumb approval state to AgentStreamDisplay.
- REST: list/set per-tool approval flag, resolve pending approval.
- Configurable via agent.tool_approval_timeout_seconds (yaml) or
  WEKNORA_AGENT_TOOL_APPROVAL_TIMEOUT env (accepts seconds or Go
  duration).

Frontend
- MCP settings: per-tool "require approval" switch on the test panel.
- Chat: ToolApprovalCard renders the pause point with editable JSON
  args, validation feedback, mm:ss countdown that turns warning/danger
  near deadline, and a resolved state that retains context.
- i18n strings added for zh-CN / en-US / ko-KR / ru-RU.

Docs
- docs/zh/mcp-approval.md covering behavior, config, API, deployment
  considerations (Redis cross-instance, restart limitations).
2026-05-10 22:57:12 +08:00
wizardchen c1826030ab fix(frontend): 修正 LLM 调用超时文案与实际行为一致,上限放宽至 3600s
前端原文案'0 表示无限等待(不推荐)'与后端实际行为不符——
internal/agent/const.go 中 getLLMCallTimeout 在配置为 0 时回退到
defaultLLMCallTimeout (120s),并不会无限等待,文案误导用户。

- 同步 zh-CN/en-US/ru-RU/ko-KR 四种语言 hint 为'0 表示使用默认值(120s)'
- placeholder 推荐范围由 60-600 调整为 60-1800,与后端兜底超时上调保持一致
- AgentEditorModal 输入框 :max 由 600 放宽到 3600,避免长推理模型场景被卡住
2026-05-10 00:26:53 +08:00
dependabot[bot] a842e2335b chore(deps): bump dompurify and @types/dompurify in /frontend
Bumps [dompurify](https://github.com/cure53/DOMPurify) and [@types/dompurify](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dompurify). These dependencies needed to be updated together.

Updates `dompurify` from 3.4.1 to 3.4.2
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.1...3.4.2)

Updates `@types/dompurify` from 3.0.5 to 3.2.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/dompurify)

---
updated-dependencies:
- dependency-name: "@types/dompurify"
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: dompurify
  dependency-version: 3.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 13:00:58 +08:00
dependabot[bot] f4c2934499 chore(deps): bump vue from 3.5.17 to 3.5.34 in /frontend
Bumps [vue](https://github.com/vuejs/core) from 3.5.17 to 3.5.34.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.5.17...v3.5.34)

---
updated-dependencies:
- dependency-name: vue
  dependency-version: 3.5.34
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 13:00:07 +08:00
dependabot[bot] fb47d84d98 chore(deps): bump @types/papaparse from 5.5.0 to 5.5.2 in /frontend
Bumps [@types/papaparse](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/papaparse) from 5.5.0 to 5.5.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/papaparse)

---
updated-dependencies:
- dependency-name: "@types/papaparse"
  dependency-version: 5.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 12:58:48 +08:00
dependabot[bot] 0bbb41de27 chore(deps-dev): bump less-loader from 12.3.0 to 12.3.2 in /frontend
Bumps [less-loader](https://github.com/webpack/less-loader) from 12.3.0 to 12.3.2.
- [Release notes](https://github.com/webpack/less-loader/releases)
- [Changelog](https://github.com/webpack/less-loader/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/less-loader/compare/v12.3.0...v12.3.2)

---
updated-dependencies:
- dependency-name: less-loader
  dependency-version: 12.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 12:56:51 +08:00
dependabot[bot] 466dcc1c65 chore(deps-dev): bump less from 4.3.0 to 4.6.4 in /frontend
Bumps [less](https://github.com/less/less.js) from 4.3.0 to 4.6.4.
- [Release notes](https://github.com/less/less.js/releases)
- [Changelog](https://github.com/less/less.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/less/less.js/commits)

---
updated-dependencies:
- dependency-name: less
  dependency-version: 4.6.4
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-09 12:52:29 +08:00
wizardchen 21a4259fc5 feat(wiki/graph): 优化操作帮助入口与图例视觉
- 把"操作帮助"按钮从图例底部挪到搜索框右侧,使用 placeholder
  色的图标按钮,hover 高亮主题色,更易被发现且不与图例操作项
  混在一起
- 状态卡片(全库概览/当前焦点)简化排版:去掉大写字母+字间距,
  主标题降字号去粗体,分隔改为 1px 虚线,整体视觉更轻
- 抽屉打开时图例自动向左平移 480px(抽屉宽度),避免被覆盖,
  使用与 TDesign drawer 一致的 cubic-bezier 缓动
2026-05-09 00:49:28 +08:00
wizardchen d0144f3586 perf(wiki): move ingest log to event table and index to on-demand API
Fixes O(n²) write amplification during wiki ingest on large KBs. Previously
every ingest/retract op re-wrote the single `slug='log'` row end-to-end and
every batch re-wrote the entire `slug='index'` directory markdown. On a 40k-
doc KB the log row grew to tens of MB and the index row to several MB, so
each batch triggered giant TOAST updates that dominated ingest wall time.

Log: new `wiki_log_entries` event table (`id DESC` indexed per KB) replaces
the single TEXT row. Batch ingest now collects entries and flushes them
once per batch via `AppendBatch`. Each entry stores `pages_affected` as
JSONB `[{slug,title}]` so the UI can render real titles; custom Scan falls
back to legacy `[]string` so older rows still deserialize.

Index: `wiki_pages[slug=index].content` keeps only the LLM-generated intro
(a few KB). The directory is now served by a structured paginated API
(`GetIndexView`) that reads `slug/title/summary` per type with cursor
pagination, so the agent and the frontend only pull the slice they need.
`RebuildIndexPage` degrades to a no-op; agent `wiki_read_page('index')`
synthesizes a small top-K overview and points callers at `wiki_search`.

Ingest resilience: LLM calls wrap with 3-attempt exponential backoff on
transient errors (5xx/408/429, transport resets/timeouts). Summary/extract
failures now bubble up so the batch's failed-op requeue path runs instead
of silently dropping the doc.

Frontend: sidebar Index/Log entries switch to dedicated views. Index view
streams intro → Summary → Entity → Concept → Synthesis → Comparison via
IntersectionObserver (with a nextTick re-check so small KBs still load
every section). Log view uses cursor pagination; pages_affected renders
titles with slug tooltip.

- new migration: migrations/versioned/000040_wiki_log_entries.{up,down}.sql
- tests: log repo pagination + legacy Scan, ListByTypeLight windowing,
  renderIndexOverviewForAgent output, isTransientLLMError classifier

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:48:52 +08:00
DuYunfan 16d31cb87b fix(frontend): use npm to match committed lockfile
The Dockerfile invoked corepack + pnpm install, but the repo only
ships package-lock.json (no pnpm-lock.yaml). On node:24-alpine
corepack resolves to pnpm v10, whose default --strict-dep-builds
rejects unbuilt postinstall scripts (esbuild, vue-demi,
@vue-office/pptx) and aborts with ERR_PNPM_IGNORED_BUILDS, breaking
docker compose build.

Switching to npm ci / npm run build aligns the image build with
CLAUDE.md and the local dev workflow that already uses npm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:10:04 +08:00
wizardchen 86f11d98e8 fix(frontend): configure pnpm v11 build approvals in workspace file
pnpm v11 no longer supports onlyBuiltDependencies in package.json and does not
accept install-time --allow-build flags. Move build-script approvals to
pnpm-workspace.yaml and copy it before install in Dockerfile so CI Docker builds
can apply allowBuilds during pnpm install.
2026-05-08 16:34:33 +08:00
wizardchen de7a241f8b fix(frontend): pass allow-build flags to pnpm install in Docker build
Some CI runners still fail with ERR_PNPM_IGNORED_BUILDS even with package-level
configuration. Pass explicit allow-build flags to `pnpm install` in Dockerfile so
required postinstall scripts are always permitted during image builds.
2026-05-08 16:28:12 +08:00
wizardchen 483576a9b6 fix(frontend): allow build scripts for pnpm to unblock Docker build
pnpm 10+ refuses to run dependency build scripts by default and exits
with ERR_PNPM_IGNORED_BUILDS, causing `pnpm install` to fail in the
frontend Docker image. Whitelist the packages that legitimately need
their install scripts (esbuild native binary, @vue-office/pptx,
vue-demi) via `pnpm.onlyBuiltDependencies`.
2026-05-08 16:17:52 +08:00
wizardchen a4c3c39556 perf(wiki): lazy-load sidebar page list with virtual-scroll tabs
?tab=wiki used to call listWikiPages({page_size: 500}) in a loop up to
50 times, loading ~25k pages into memory before rendering the sidebar
on knowledge bases with tens of thousands of pages. All rows were then
materialized as DOM nodes inside collapsible groups stacked vertically.

This commit reshapes the sidebar around per-type buckets that are
fetched on demand and rendered through a single virtual scroller:

* pagesByType holds one bucket per page_type (summary / entity /
  concept / synthesis / comparison), each with its own items list,
  pagination cursor, KB-wide total, and loading flag. Initial load
  fires one 50-item request per type in parallel.
* Index and Log are fetched directly via getWikiIndex / getWikiLog
  instead of scanning the full page list to find them.
* Groups are surfaced as a horizontal tab bar; switching tabs swaps
  the RecycleScroller's items. Only one bucket is visible at a time,
  so we never stack multiple virtual viewports.
* The scroller runs in page-mode with the outer .wiki-page-list as the
  scrollable ancestor; a 1px sentinel after the list is watched by
  IntersectionObserver to trigger the next page fetch. After each
  batch lands we call scroller.updateVisibleItems(true) on the next
  tick so appended rows render in order without requiring the user
  to jiggle the scroll.
* Switching tabs resets scrollTop so the retained position of the
  previous tab can't re-trigger the sentinel and cascade loads on
  the new (shorter) list.
* Search enters a dedicated flat-result mode (searchResults ref);
  clearing the query flips back to the bucketed view without
  refetching the buckets the user already had open.

Adds vue-virtual-scroller dependency and imports its stylesheet.
2026-05-08 15:07:59 +08:00
wizardchen df1e9a1bfd perf(wiki): subgraph API and interactive exploration for large graphs
Wikis with tens of thousands of pages used to crash the browser trying
to render the entire link graph at once (30MB+ JSON, 100k+ SVG elements).
This change moves the graph viewer from "fetch everything, render
everything" to "fetch a slice, expand on demand" with several matching
UX improvements.

Backend

* GET /wiki/graph now accepts `mode` (overview | ego), `center`, `depth`,
  `types`, `limit` query params. Default is overview top-500 by
  link_count, capped at 2000. Response includes a Meta object so the
  frontend can render a truncation hint and drive the UI.
* Pure helper `computeGraphSubset` extracted for testability; six unit
  tests cover overview truncation / type filter / ego BFS / missing
  center error.
* WikiLintService passes Limit=0 (uncapped) so link integrity checks
  still walk every page.
* Repo `Search` adds CASE-based relevance ranking (title 4, slug 3,
  summary 2, content 1) so full-text results put the most obvious
  matches first instead of whatever was updated most recently.

Frontend

* Graph viewer fetches overview on entry; ego pivot on double-click,
  search, wiki-link click, URL ?slug=, global issues jump.
* Shift+click or hover ⊕ button blooms neighbors onto the current
  canvas additively. Bloom tracks generations and LRU-evicts oldest
  when total exceeds 1500 nodes; ego center / selected node / latest
  anchor are always protected.
* "Grow frontier (N)" legend action expands every dashed-ring node in
  one click (6-way concurrency) while skipping Index/Log super-nodes
  that would otherwise dump the whole wiki onto the canvas.
* Node dashed expansion ring + drawer "X/Y neighbors shown" hint tell
  users which nodes still have neighbors to load.
* Search dropdown uses remote full-text search (debounced, sequence-
  numbered to drop stale responses) and falls back to the overview
  top-500 snapshot when the input is empty.
* Type filters now round-trip to the server so top-N is always
  computed from the user's active type set rather than hiding nodes
  client-side and shrinking the view.
* Status card replaces the cramped "centered on X · N hops · M nodes"
  line with a structured focus/overview summary, resolving slugs to
  page titles.
* Help popover in the legend lists every canvas shortcut.

i18n entries added for zh-CN / en-US / ko-KR / ru-RU.
2026-05-08 13:32:54 +08:00
wizardchen 6019c4b661 fix(frontend): polish model settings UI and fix disabled brand color
- 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
2026-05-07 21:51:22 +08:00
wizardchen c77cef5a69 feat(frontend): unify external doc-link style and outline add buttons
- 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.
2026-05-07 21:51:22 +08:00
wizardchen cc6ac6ac50 fix(frontend): unify radio button theme and disabled selection
- 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.
2026-05-07 21:51:22 +08:00
wizardchen 627e9e436d fix(frontend): render markdown tables in chat wiki drawer
The wiki page drawer opened from the chat view rendered tables without
borders or padding because the global `.wiki-graph-drawer .wiki-reader-body`
style block was missing GFM table rules. Add the same table styles already
used by `WikiBrowser.vue` so tables show consistent borders, header
background, and hover states across both entry points.
2026-05-07 18:29:36 +08:00
wizardchen 56058287dd fix(agent): drop whitespace-only thinking events from the steps tree
Some LLMs (e.g. qwen3 series) emit blank lines like "\n\n" before tool
calls. The backend faithfully forwards these as thought_chunk events
because streamThinkingToEventBus only filters chunk.Content == "" and
treats whitespace as content. The frontend then merges them into a
thinking event whose content is non-empty in JS truthiness terms but
visually empty, producing a "思考" card with a chevron and no text.

Filter such events out at the end of buildFullEventList so neither the
intermediate-steps tree nor the displayEvents fallback path renders
them.
2026-05-07 17:33:03 +08:00
wizardchen 921e4c015a fix(agent): hide trailing thinking event when it duplicates final answer
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.
2026-05-07 17:33:03 +08:00
wizardchen 4677caba01 fix(agent): unify answer rendering when model skips final_answer tool
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.
2026-05-07 17:33:03 +08:00
bingxiang.cheng a3c3ba5acf fix(markdown): 修复小概率情况下公式加载失败问题 2026-05-07 16:34:20 +08:00
bingxiang.cheng a232b12ff0 fix(agent): 修复WeKnora对话完前端未显示结束标记问题
fix(agent): 修复流式回答think内容与answer混淆问题
2026-05-07 16:34:20 +08:00
wizardchen 4a5caf54af fix(frontend): make general-settings font picker actually work
The font picker in 常规设置 silently failed in three distinct ways:

1. Font family changes were invisible on macOS because 6 of the 7 options
   (Inter / Roboto / Segoe UI / Cascadia Code / JetBrains Mono / Fira
   Code) aren't installed by default and fell back to system SF. Swap
   the picker to a platform-aware list — Mac / Windows / Linux each see
   only the fonts their OS actually ships. The "third sans slot" now
   always serves a serif face (Georgia / Times New Roman / DejaVu
   Serif) so the difference is unambiguously visible instead of being
   three near-identical sans families.

2. Font size flipped --app-font-scale on <html>, but that variable was
   only consumed by a handful of TDesign tokens and the body reset, so
   the ~1000+ hard-coded font-size: NNpx rules across the frontend
   stayed put. Apply the multiplier via `zoom` on <html> so the whole
   document scales, then fix the 15 `100vh` rules that would overflow
   under zoom (html / body / #app are already height: 100%, so the
   descendants can use 100% too).

3. The monospace picker had no visible effect even on a working stack
   because `<t-input style="font-family: ...">` is forwarded to the
   inner <input>, but TDesign applies `font: var(--td-font-body-medium)`
   — a shorthand that resets font-family. Reach the real <input> /
   <textarea> via `:deep()` instead of inline style.

Additional polish:
- Add a live preview row under each picker so users can see the effect
  without hunting for a code block or API Info screen
- Rename "等宽字体 / Monospace Font" → "代码字体 / Code Font" to match
  VSCode / GitHub / Notion convention; the old label was jargon
- Rewrite descriptions to explain the actual purpose and scope
2026-05-07 15:07:24 +08:00
wizardchen fb9ae11aa8 fix: 为前端静态资源设置正确的 Cache-Control 响应头
修复升级前端版本后,用户必须退出重新登录才能看到新版页面的问题。

根因:nginx 和 Lite 版 Go 静态服务均未设置 Cache-Control,浏览器按
启发式策略长期缓存 index.html,导致刷新仍加载旧版入口 HTML,旧版
引用的 hash 文件名也就不会变更。

改动:
- frontend/nginx.conf: index.html 及 SPA fallback 设 no-cache,
  must-revalidate;/assets/* (Vite 产物带 hash 文件名)设一年
  immutable 长缓存。location 内重复声明原有安全头,避免 nginx
  add_header 不继承导致安全头丢失。
- internal/router/router.go: Lite 版 serveFrontendStatic 按同样
  策略设置 Cache-Control。
2026-05-07 12:08:02 +08:00
wizardchen c577d0e474 fix(knowledge): polish chunking-settings debug trigger and strategy hint
The chunking-settings debug trigger and strategy picker had two UX
issues reported by real usage:

- The test button used theme=primary + variant=outline, a combo that
  appears nowhere else in the project. A green-bordered green-text
  pill in the corner of the section header read as a misplaced
  promotional element rather than a secondary action.
- The strategy select's placeholder was "选择策略(默认使用经典递归分块)"
  / "Select strategy (defaults to classic recursive splitting)". Naming
  the fallback strategy inside the placeholder made the empty select
  look as if the user had already picked "classic recursive" — even
  though the value is actually empty.

- Move the debug trigger from the section header into the strategy
  row's right column, stacked below the select. Users meet the test
  action exactly when they're deciding which strategy to use.
- Switch the trigger to a text-style button and override TDesign's
  default hover/focus/active surfaces so the button reads as an inline
  link (text colour shift only, no filled background block).
- Rename the trigger to "测试分块效果" / "Preview chunking" so it
  describes what will be inspected rather than the input source.
- Drop the reference to the fallback strategy inside the placeholder.
  "不填则按长度切分" / "splits by length if left empty" preserves the
  original information about empty-value behaviour without looking
  like a selected option.
- Remove the now-unused 80px right padding the section header reserved
  to keep the old inline trigger clear of the modal close button.
2026-05-07 11:08:29 +08:00