Commit Graph
28 Commits
Author SHA1 Message Date
Soulter 8831d95025 feat(dashboard): scoped path-token auth for plugin views and complete the views rename (#10415)
* refactor(dashboard): complete the plugin pages to views rename

Finish the remaining Pages -> Views rename on the dashboard:

- Fix the plugin card "Open View" button crash by pointing
  openPluginWebui at the renamed PluginView route
- Rename PluginPagePage.vue to PluginViewPage.vue and update its
  internals (loadPluginView, pluginViewTitle, .plugin-view-* classes)
- Rename openPluginWebui -> openPluginView and the open-webui emit to
  open-view; pluginPageTitle/Description -> pluginViewTitle/Description;
  isPluginPageRoute -> isPluginViewRoute
- Rename i18n keys (pluginWebui -> pluginView, openWebui -> openView,
  pluginPageType -> pluginViewType, messages) across en/zh/ja/ru locales

The postMessage bridge channel name (astrbot-plugin-page) is kept
unchanged because it is part of the wire protocol shared with
plugin_page_bridge.js.

* feat(dashboard): authenticate plugin view assets with scoped path tokens

Serve plugin view assets from
/api/v1/plugins/{id}/views/{page}/_t/{token}/... so the scoped token
travels in the URL path. Relative URLs inside the view then inherit the
token through normal path resolution, which removes the need for
server-side HTML/CSS/JS URL rewriting on this route.

- Add the _t routes with a require_plugin_view_token dependency
  (v1 paths bypass the dashboard auth middleware)
- Extend the plugin page asset token to a session-length TTL (7 days,
  aligned with the dashboard session) with a page_session purpose claim,
  still scoped to a single plugin and page
- Serialize the view entry content_path as the _t URL, keeping the
  asset_token query for plugins that parse location.search
- Keep the legacy /api/plugin/page/content/...?asset_token= form working
  during the transition
- Rename the OpenAPI tag Plugin Pages -> Plugin Views, document the new
  route, regenerate the frontend API client, and update the zh/en
  plugin-pages docs

* refactor(dashboard): remove the legacy plugin page content route and URL rewriting

The path-token view route makes the compatibility surface unnecessary:

- Drop /api/plugin/page/content/... (query asset_token form)
- Drop the redundant authenticated asset routes /plugins/page/assets,
  /plugins/view/assets, and /plugins/{id}/(pages|views)/{page}/assets/...
  which had no callers outside the generated client
- Remove the HTML/CSS/JS URL rewriting helpers; view assets are always
  served raw and only HTML gets bridge SDK injection plus theme handling
- Slim PluginPageAuth down to the bridge SDK endpoint, the only
  non-v1 path still authenticating scoped query tokens
- serialize_plugin_page no longer falls back to the legacy content path
- Update the plugin-pages docs (zh/en) and the OpenAPI spec, and
  regenerate the frontend API client

* refactor(dashboard): drop legacy plugin page API aliases

Remove the page-named plugin view API aliases now that the views rename
is complete and legacy compatibility is intentionally dropped:

- DELETE /api/v1/plugins/page(s) and /plugins/{plugin_id}/pages{,/{page_name}}
  aliases; /plugins/view(s) and /plugins/{plugin_id}/views{,/{page_name}}
  are the only entry config routes
- Remove the unused /api/v1/plugins/page-bridge-sdk.js route; the live
  bridge SDK stays at /api/plugin/page/bridge-sdk.js
- Dashboard calls the view-named endpoints; regenerate the API client
  and the OpenAPI scopes docs

* refactor(dashboard): keep plugin page APIs as deprecated view aliases

Restore the page-named plugin view routes removed in the previous commit
and keep them for a transition period, with view as the canonical API:

- /plugins/page(s) and /plugins/{plugin_id}/pages{,/{page_name}} serve as
  aliases of the corresponding /views routes (same handlers)
- The OpenAPI spec marks the page operations deprecated and points new
  clients at the view routes; the v1 page-bridge-sdk.js route is restored
- The dashboard keeps calling the view endpoints by default

* refactor(dashboard): rename the plugin view path parameter to view_name

The view entry and path-token asset routes now use {view_name} instead of
{page_name} in the OpenAPI-visible path, and the service layer renames its
internal page_name variables to match. Wire-compatible surfaces stay
unchanged: the page_name JWT claim, the pageName JSON field, query
parameters, and the deprecated /pages aliases. Error messages and the
plugin view docs (zh/en) complete the Page to View rename.
2026-10-06 18:18:22 +08:00
Soulter 4b049d1e57 feat(dashboard): regroup sidebar into labeled sections and rename plugin Pages to Views (#10307)
* feat(dashboard): regroup the sidebar into labeled System and Extensions sections

- Add static group headers (System / Extensions) to the sidebar, in the
  style of AI Studio's labeled sections
- System: welcome, platforms, providers, extensions, config profiles,
  data & logs, custom rules
- Extensions: knowledge base, cron, subagent orchestration, personas;
  plugin pages are flattened into this section and the collapsible
  plugin-pages group is removed
- Dissolve the collapsible More Features group; headers hide in rail mode
- Skip the legacy sidebar customization when building the menu (the
  feature is slated for removal)
- Update zh/en docs for the new locations

* feat(dashboard): place personas before knowledge base in the extensions group

* feat(dashboard): make the extensions sidebar group collapsible

Add a chevron toggle to the extensions group header; collapsing hides
the group's items and the state persists in localStorage. Rail mode is
unaffected and always shows every icon.

* feat(dashboard): pin extension sidebar items to the top of their group

Extension group items show a pin button on hover; pinned items move to
the top of the extensions group (hidden together with the group when
collapsed) and the pinned set is persisted in localStorage.

* feat(dashboard): keep the unpin icon always visible on pinned items

Pinned items now show a PinOff icon in the primary color without
requiring hover; unpinned items still reveal the Pin icon on hover.

* feat(dashboard): show a hover card with plugin details on plugin page items

Hovering a plugin-provided page in the extensions group reveals a card
with the page name, plugin ID, and author. The data comes from the
existing plugin list API (no backend change); static items and rail
mode are unaffected.

* fix(dashboard): add author and version to the PluginEntry type

* feat(dashboard): refine the plugin hover card

- Show the card immediately on hover (no open delay) and drop the
  expand animation
- Plugin row shows an icon plus 'display_name (id)' with the id muted,
  or just the id when the plugin has no display name
- Author row gets its own icon

* feat(dashboard): add a type row to the plugin hover card

Defaults to '插件可视化视图' (localized in all four locales).

* feat: rename plugin Pages to Views and group plugin views by plugin

Rename (Views preferred, Pages kept as a compatible alias everywhere):
- StarMetadata.pages -> views; metadata.yaml accepts views: (pages: alias)
- Plugin view directory views/ preferred, pages/ still accepted
- v1 API gains /plugins/view(s) alias routes alongside /plugins/page(s)
- Bridge global window.AstrBotPluginView with AstrBotPluginPage as alias
- Plugin i18n keys views.<name>.* preferred, pages.<name>.* alias
- Frontend route /plugin-view/... with /plugin-page/... redirecting
- OpenAPI spec + regenerated client; docs use Views (zh: 插件可视化视图)

Sidebar (extensions group):
- Default mode shows the view name for plugin views
- New group-by-plugin toggle on the extensions header (grid icon, off by
  default, persisted in localStorage): plugin views are grouped per plugin
  under the extensions group, each group listing all of the plugin's views
- Hover card on plugin view items shows page name, plugin display name
  (with id), author, and type; white card style reused for the toggle
  tooltip
- Pinning works for nested views too, lifting them to the group top
2026-10-01 16:26:56 +08:00
Wei Chengqian 2f7675140d feat(dashboard): paginate sidebar chat sessions (#10279) 2026-09-29 20:27:00 +08:00
Ruochen Pan f99c76ec10 fix(dashboard): bound upload memory and add resumable chunked uploads (#10123)
* refactor(dashboard): consolidate upload saves into streaming helper

Five copies of the same upload-save logic existed: three file wrappers
(UploadFileAdapter, RequestUploadFile, PluginUploadFile) plus one
_save_upload() in each of BackupService and SkillsService. The backup
variant fell back to a full-body read() for raw FastAPI UploadFile,
buffering entire uploads in memory.

Introduce save_upload_stream() as the single streaming implementation
(1 MiB blocks, optional max_bytes with in-loop abort and partial-file
cleanup). The wrappers keep their public signatures and delegate to it;
skills/chat/config save paths call save() directly with max_bytes,
replacing their post-save size checks.

* fix(dashboard): bound backup upload size and harden chunked flow

Backup routes passed raw FastAPI UploadFile into the service layer,
hitting the full-body read() fallback: a single authenticated request
with an oversized chunk or whole-file upload could OOM-kill the
process (verified with a 512 MiB memory-limited container, exit 137).

- Wrap uploads in UploadFileAdapter so all saves stream to disk
- Enforce CHUNK_SIZE (1 MiB) per chunk and 128 MiB for whole-file
  uploads, aborting mid-stream with partial-file cleanup
- Cap chunked backup totals at 8 GiB and point larger backups at
  manual restore via the data directory
- Verify the merged backup size against the declared total

* fix(dashboard): enforce MAX_CONTENT_LENGTH with per-route overrides

The 128 MiB MAX_CONTENT_LENGTH value was written into the compat-layer
config dict but nothing read it, so the FastAPI/hypercorn path had no
request body limit at all.

Add a middleware that rejects oversized bodies with 413 before auth or
body parsing, using MAX_CONTENT_LENGTH as the default with per-route
overrides for legitimate large uploads (attachments 512 MiB, plugin
config files 500 MiB, knowledge bases 512 MiB) and a tight 2 MiB cap
on the backup chunk endpoint. Requests without a Content-Length header
pass through and remain bounded by per-endpoint max_bytes at save time.

* refactor(dashboard): extract generic chunked upload session service

Pull the chunk session machinery out of BackupService into a reusable
ChunkedUploadService owning session lifecycle, chunk storage, streaming
assembly and expiry cleanup, in preparation for webchat attachment
chunked uploads.

Sessions are now bound to an owner (the authenticated username) and a
purpose; chunk/complete/abort calls from another owner fail with the
same "not found or expired" error as unknown sessions, so upload IDs
cannot be probed or consumed cross-user. BackupService keeps business
concerns (zip validation, size caps, manifest marking) and delegates
the rest; API shapes and frontend flows are unchanged.

* feat(dashboard): add resumable upload status endpoint

Expose per-session progress (received chunk indexes, totals, expiry)
so clients can resume an interrupted chunked upload by sending only
the missing chunks instead of starting over.

Abuse considerations baked in: the lookup inherits owner binding and
answers "not found or expired" for both unknown sessions and sessions
owned by someone else (no probing), the response carries no filename
(minimal disclosure), and the query is strictly read-only — it never
touches last_activity, so polling it cannot anchor a session and its
on-disk chunks alive past expiry.

* fix(dashboard): bound file signature memory with chunked hashing

getFileSignature() read the entire file into browser memory via
arrayBuffer() before computing SHA-256, spiking renderer memory by the
full attachment size (up to the 512 MiB upload cap).

The signature is only used for in-session staging dedup and never
leaves the browser, so it does not need to be the canonical whole-file
SHA-256. Hash 8 MiB blocks individually and digest the concatenated
block digests instead; the prefix changes to sha256m: to mark the
algorithm change (old signatures vanish with the page session, so no
compatibility concern).

* feat(dashboard): resumable chunked upload UI for backup import

Extract the chunk scheduling logic from BackupDialog into a reusable
useChunkedUpload composable (5-way concurrency, per-chunk silent
retries, progress accounting) and add resume support on top of the
new upload status endpoint: a failed upload now offers a "Resume
Upload" action that queries received chunk indexes and sends only the
missing ones. Expired sessions transparently re-initialize and start
over; a failed complete() drops the poisoned session by design.

Wires the new /backups/upload/status endpoint through the OpenAPI
spec and regenerated client, and adds the resumeUpload label to all
four locales.

* feat(dashboard): chunked upload endpoints for webchat attachments

Mirror the backup chunked-upload flow for chat attachments so large
files (>128 MiB request-body default, up to the 512 MiB attachment
cap) can be uploaded in slices: POST /api/v1/files/upload/{init,
chunk,complete,abort,status}, owner-bound sessions, and a per-route
body limit on the chunk endpoint.

ChatService reuses the generic ChunkedUploadService with a new meta
passthrough carrying the client content_type through the session;
completion merges outside the chunk dir and feeds the result through
save_uploaded_file() unchanged via a move-based LocalUploadFile
adapter, keeping MIME sniffing, type classification and attachment
insertion in exactly one place.

Also repairs two pre-existing test stubs that predated the
max_bytes-aware save() contract and were already failing on this
branch.

* feat(dashboard): chunked upload with resume for webchat attachments

Route staged files >= 32 MiB through the new chunked upload endpoints
via useChunkedUpload; smaller files keep the single POST path so paste
and quick picks stay low-latency. The content_type travels through the
init payload so server-side attachment classification is unchanged.

A failed chunked upload is kept as an error chip in the input area
with a retry action that resumes from the last received chunk (and
transparently restarts when the session expired) plus a discard action
that aborts the session. Failed entries hold their uploader in a
shallowRef so Vue's deep ref unwrapping cannot strip the composable's
internal refs, and their signatures stay reserved to block duplicate
staging while a failed entry exists.

* docs: regenerate openapi artifacts for file upload endpoints

* fix(dashboard): harden chunk save and request body limits

Address review findings on the upload-hardening branch:

- save_chunk() now writes to a uniquely named temp file, verifies the
  save() byte count against the expected chunk length, and publishes
  via atomic rename. A failed or concurrent same-index retry can no
  longer truncate and delete an already-received chunk (previously
  left received_chunks claiming data that assemble() then failed to
  find), and short writes are rejected instead of published.
- Requests with multipart bodies but no Content-Length are rejected
  with 411: form parsing spools large bodies to disk before any
  per-file size check can run. This is a documented stopgap — other
  lengthless bodies still pass and are bounded only at save time;
  closing that fully requires counting bytes as they arrive.
- Whole-file upload overrides gain 1 MiB of multipart framing slack
  so a file exactly at the size cap is no longer rejected with 413.

The body-limit decision is extracted into a pure function for direct
unit tests; the assemble-time size recheck is now covered by an
out-of-band corruption test since chunk-level verification rejects
short writes earlier.

* fix(dashboard): drain upload pool and pin session on resume

A failed chunk made runPool() reject immediately while the remaining
in-flight requests kept writing; a resume could then race them on the
same chunk, stale retries read the mutable uploadId (potentially
writing into a re-initialized session), and late completions kept
counting progress (150% after resume).

The pool now stops scheduling on first failure but drains issued
requests via allSettled before surfacing the error, each request pins
the uploadId captured at run start, and a run-generation counter
(bumped on start/resume/cancel) blocks stale completions from the
progress accounting.

* fix(dashboard): close 411 bypass and temp-file residue on publish

Address the second round of review findings:

- The 411 media-type check used a raw startswith(), but the form
  parser strips surrounding whitespace, so a leading-space
  Content-Type was let through without a Content-Length while
  Starlette still parsed the body as multipart. Detection now uses
  the same parse_options_header the parser uses.
- A failing os.replace() during chunk publish left the uniquely
  named temp file behind; it is now covered by the same cleanup
  discipline as the save path.

Backup direct-upload routes deliberately get no framing slack: they
are legacy paths with no remaining callers, and the pre-existing
exact-limit 413 edge is answered by chunked upload.

* fix(dashboard): abort sessions created after a cancel

Cancelling while initUpload was still in flight cleared local state
before an upload id existed; when the delayed init returned, the run
flipped from idle to error and the freshly created server session was
never aborted. handleFailure now lets cancel win over any late
resolution and aborts the session id captured at that point.

* fix(dashboard): check cancel flag after completeUpload resolves

Cancelling while completeUpload was in flight let the late success
response flip the uploader from idle to done and hand the result to
the caller, which proceeded to the precheck. completeSession() now
re-checks the cancel flag after the response arrives and routes the
late success through the cancelled path instead.

* fix(dashboard): gate the 411 rule to body-capable methods

The 411 stopgap rejected GET /api/v1/logs/live: the SSE log client
sends a bogus "Content-Type: multipart/form-data" header on a GET
(copy-paste relic), and a GET with no Content-Length matched the
multipart-without-length rule. Body-less methods never trigger form
parsing, so no disk-spool risk exists for them — the 411 now applies
only to POST/PUT/PATCH. The junk header on the SSE client is removed
as well; the other two SSE consumers never had it.

* feat(dashboard): show in-progress chips for chunked attachments

Chunked uploads gave no feedback while in flight: the staged chip
only appeared after completion, leaving multi-minute uploads silent.
Track in-flight uploads alongside the failed ones and render progress
chips (filename, percent, thin progress bar) with a cancel action in
the input area; on success the chip hands off to the staged
attachment, on failure to the resumable error chip.

* fix(dashboard): type active upload chips upfront and align progress bar

The in-progress chip used a generic cloud icon even though the file
type is known locally before the upload starts; it now derives
icon/color/label from the filename via attachmentPresentation, same
as the staged chip. The progress bar's left edge is aligned with the
filename text instead of the card padding.

* fix(dashboard): keep active-chip progress bar inside the card

v-progress-linear ships width:100%, which wins over the right offset
in absolute positioning; the bar ran 52px past the card's right edge
and was clipped by overflow:hidden. Give it width:auto so the left/
right offsets determine the width.

* fix(dashboard): rework active-chip progress track and cancel button

Positioning a Vuetify component root directly proved fragile — the
progress bar drifted to the card's top edge. Wrap it in a plain track
div that owns the absolute positioning and let the component fill it.
Replace the corner tonal badge cancel with an inline text-variant
icon button after the percent label, and drop the padding reserved
for the badge.

* fix(dashboard): enforce session expiry and atomic save semantics

Address the third review round (sourcery-ai findings):

- get_session() now actually enforces the idle expiry it advertises
  in its "not found or expired" error; expired sessions stay
  abortable for cleanup, and backup upload_init starts the janitor
  just like chat's does, so chunk dirs cannot linger indefinitely.
- cleanup_session() only unregisters a session after rmtree()
  succeeds, letting the janitor retry on transient filesystem errors
  instead of permanently leaking the chunk directory.
- save_upload_stream() writes to a uniquely named temp sibling and
  atomically renames on success, so a failed or cancelled overwrite
  can no longer delete a pre-existing destination (e.g. re-uploading
  over an existing attachment), and all callers inherit the behavior.

The write()-return-value finding is a non-issue: BufferedWriter
writes fully or raises, and the chunk path already verifies byte
counts.

* fix(dashboard): guard failed-upload retry against double clicks

retryFailedUpload() ran resume() without any in-flight marker, so a
second click started a concurrent resume on the same session; the
loser hit "not found or expired" and left a failed chip next to the
successfully staged attachment. The entry now moves to activeUploads
while resuming, which blocks the second click and shows live
progress, and returns to failedUploads only if the resume errors.
2026-09-18 17:55:30 +08:00
SoulterandRuochenPan 06261c532a feat: add role-based Local computer permissions (#9472)
* feat: sandbox local member execution on Linux

* feat: add macOS Seatbelt local sandbox

* feat: Implement race-resistant file access for local tools

- Added `open_file_in_allowed_roots` function in `local_file_security.py` to securely open files within specified directories, preventing path traversal attacks.
- Updated file reading functions in `file_read_utils.py` to accept file descriptors, allowing for safer file operations.
- Enhanced `FileReadTool`, `FileWriteTool`, and `FileEditTool` to utilize the new secure file access method.
- Added tests to ensure restricted access works correctly, including scenarios with symlinked directories and ancestor swaps.
- Improved error handling for file operations to provide clearer feedback on permission issues.

* feat: add role-based Local computer permissions

* fix: clarify Windows Local permission behavior

* style: use neutral permission matrix border

* fix: clarify Local runtime permission labels

* fix: localize computer runtime options

* fix: tighten default Local permission policy

* fix: allow macOS sandboxed shell forks

* refactor: extract platform process sandboxes

* refactor: expose cross-platform sandbox limits

* refactor: unify sandbox process lifecycle

* refactor: seal local sandbox abstractions

* test: align local sandbox tests with Windows support

* fix: improve local permission settings layout

* fix: initialize workspace for restricted file writes

* feat: expose runtime and sandbox dependency information

* feat: add disabled local access and platform-aware permission controls

* feat: display runtime information in local permission controls

* fix: validate local permission support before saving config

* fix: use supported local permission defaults on Windows

* fix: restrict local file sending and align Windows permission tests

* chore: remove redundant local permission hint

* fix: restore local sandbox DNS and approved file access

* ci: enable bubblewrap user namespaces on Ubuntu runners

* fix: report local sandbox startup failures

* fix: use a portable sandbox startup probe

* fix: preserve read-only Python virtualenv access in local sandboxes

* fix: revoke local shell sessions when permissions change

* fix: block shared-path attacks on local runtime file exchange

Sandboxed processes can write to shared temp roots, so a named session
log there could be replaced with a symlink to a host file that host-side
reads and appends would follow. Keep managed shell output on an anonymous
temporary file handle instead of a named path.

Also stop _resolve_path_from_sandbox from consulting a booter under the
local runtime: workspace and local-file checks already enforce caller
permissions, and the fallback branch probed the host shell without them.
Reject such paths with FileNotFoundError instead.

* fix: revoke local shell sessions when admin access is removed

* fix: skip missing default roots in local grep

* test: check sandbox file readability across platforms

* test: wait for watchdog retry without fixed sleeps

* test: synchronize watchdog log rotation assertions

---------

Co-authored-by: RuochenPan <badbatch0x01@gmail.com>
2026-09-15 15:48:01 +08:00
Wei Chengqian fae2c120ef feat(chatui): paginate chat history (#9667)
* feat(dashboard): add chat history pagination and reasoning blocks (#9652)

* refactor(dashboard): remove reasoning char count and loading text

* feat(dashboard): load earlier messages on scroll up

* refactor(dashboard): remove reasoning retry label

* refactor(dashboard): remove thread panel pagination and lazy reasoning

Restore the thread panel to pre-#9652 behavior: full history without
pagination and inline reasoning content. Reverts the out-of-scope thread
additions while keeping main-session pagination and reasoning lazy-loading.

* chore: retrigger smoke test

* fix(dashboard): pause automatic history loading after failure

* feat(dashboard): show progress while loading earlier messages

* fix(dashboard): show reasoning loading errors and retry action

* style(dashboard): align chat loading errors with chat UI

* style(dashboard): make chat loading errors more compact

* refactor(chat): retain complete message content in history pages

* refactor(dashboard): expand reasoning directly from history pages

* refactor(api): remove lazy chat message retrieval endpoint
2026-09-12 13:56:22 +08:00
Soulter 6fb50cae91 feat(webchat): enable reasoning display by default (#10020)
* feat(webchat): enable reasoning display by default

* fix(webchat): sync reasoning flag expectations and API docs
2026-09-10 10:36:24 +08:00
Soulter 69030851d4 feat: consolidate data dashboard and redesign conversations (#9846)
* feat: consolidate data dashboard

* feat: redesign conversation workspace

* docs: sync conversation OpenAPI artifacts

* docs: update data workspace navigation

* feat: group conversations by session

* fix: optimize mobile conversation workspace

* feat: refine log workspace

* fix: honor console auto-scroll setting

* feat: refine trace workspace
2026-08-27 18:53:02 +08:00
Soulter cfe6424742 fix: harden API key scope boundaries (#9503) 2026-08-02 13:19:38 +08:00
Soulter 21f41c2398 refactor: simplify updater architecture (#9493) 2026-08-01 18:05:06 +08:00
Soulter 73ecc394de feat: add ChatUI workspace file browser (#9432)
* feat: add ChatUI workspace file browser

* fix: harden workspace path validation

* fix: validate workspace download boundary

* fix: resolve workspace files from directory entries
2026-07-28 23:53:47 +08:00
868c3f137e fix: improve conversation list performance and prevent stale updates (#9226)
* fix: 优化对话列表加载与请求竞态

- 对话列表改为摘要查询,避免读取和传输完整聊天历史,同时保持详情、导出及插件默认行为兼容
- 统一筛选、排除和稳定分页逻辑,补充 SQLite 索引并保留全文搜索能力
- 使用组件级请求编号和取消控制阻止迟到响应覆盖最新状态,修复删除、筛选防抖与分页竞态
- 增加摘要查询、索引、API 响应和参数清洗回归测试

* fix: 保持摘要历史为合法 JSON

- 摘要查询未加载历史时返回空 JSON 数组字符串
- 增加管理器摘要结果可解析性的回归测试

* fix: 避免重复显示列表错误

- 仅在保留旧列表数据时显示顶部错误横幅
- 空列表失败时继续使用表格内错误与重试状态

* fix: preserve conversation list compatibility

* refactor: align conversation history option naming

---------

Co-authored-by: C₂₂H₂₅NO₆ <Sisyphbaous-DT-Project@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-07-28 16:44:28 +08:00
Ruochen Pan 10e5ca6958 Feat: Allow adjust plugin log levels (#9342)
* feat(logging): add isolated plugin loggers

* feat(dashboard): configure plugin log levels

* fix(logging): support legacy plugin loggers

* fix(dashboard): sync plugin log level response

* perf(logging): avoid rescanning plugin handlers

* fix(logging): persist plugin levels atomically

* test(logging): use valid logger level mocks
2026-07-24 10:03:55 +08:00
Soulter e47e5af9c4 feat: implement HTML GenUI component and register custom markdown tags (#8712)
* feat: implement HTML GenUI component and register custom markdown tags

* fix: expand bot message content width

* feat: add per-request ChatUI flags

* feat: refine ChatUI HTML GenUI prompt for clarity and token efficiency
2026-07-18 18:06:26 +08:00
Soulter 6070da9ae2 fix: resume ChatUI streams after refresh (#9259)
* fix: resume ChatUI streams after refresh

* fix: hide chat run service errors

* fix: harden resumed chat streams
2026-07-13 23:05:03 +08:00
Weilong Liao b43cc6dee0 feat: improve ChatUI attachment display (#9134) 2026-07-04 17:56:33 +08:00
lxfight ea9e3421d9 fix: align knowledge base CRUD API contract with kb_name, canonical payload fields, and matching OpenAPI types (#9000)
Warning: Potential breaking changes in /kb related openapi.

* fix(kb): align CRUD API contract end-to-end

Unify knowledge base create/update/list with kb_name, canonical_payload,
optional list pagination with total, and matching OpenAPI plus dashboard types.

* fix: restore _model_dict references, add KnowledgeBaseCreateRequest, fix OpenAPI allOf validation

- Replace 3 remaining _model_dict() calls with payload.model_dump(exclude_none=True)
- Add KnowledgeBaseCreateRequest schema with required kb_name + embedding_provider_id
- Remove additionalProperties: false from OpenAPI allOf sub-schema to avoid validation failures
- Use Pydantic Field(alias="name") + populate_by_name=True for legacy name migration
- Delegate _canonical_kb_payload to KnowledgeBaseRequest to eliminate duplicated logic
- Add getattr default None for update_kb to prevent AttributeError
- Add validation error tests: missing kb_name, missing embedding_provider_id

* fix: address knowledge base contract follow-ups

* fix: preserve knowledge base create error shape
2026-07-03 22:18:56 +08:00
Weilong Liao e7d5be632f feat: add ChatUI project workspaces (#9066)
* feat: add ChatUI project workspaces

* feat: refine chatui layout

* feat: enhance chat input and project view styles for attachment handling

* feat: adjust chat sidebar brand logo positioning

* feat: enhance project dialog with error handling and loading state
2026-07-03 21:54:20 +08:00
lxfight 758e43273d fix: paginate knowledge base dashboard lists (#9055)
* fix: paginate knowledge base dashboard lists

* fix: preserve knowledge document search pagination
2026-06-28 14:00:45 +08:00
Weilong Liao 3d4c4ed01b fix: validate plugin install sources (#9061) 2026-06-28 13:45:59 +08:00
Weilong Liao 0ef790d289 fix: track plugin install source for updates (#9037)
* fix: track plugin install source for updates

* feat: refine plugin source management flow

* test: align plugin update expectation
2026-06-27 15:02:04 +08:00
Weilong Liao 421d718041 feat: show public version details on login (#8986)
* feat: show public version details on login

* fix: address login version review feedback
2026-06-24 21:46:29 +08:00
Weilong Liao 967ed01cf7 fix: add data scope to api keys (#8985) 2026-06-24 16:37:46 +08:00
Weilong Liao 49b86320cb docs: clarify OpenAPI chat username identity (#8880) 2026-06-18 23:17:50 +08:00
Weilong Liao 264e7eaaa3 fix: restore OpenAPI file uploads
Expose /api/v1/file in OpenAPI, enable file-scoped API keys, and regenerate docs/client artifacts.
2026-06-18 12:37:38 +08:00
Weilong Liao 5566bd621c feat: reorganize settings system configuration (#8777)
* feat: reorganize settings system configuration

* fix: float system config restart notice

* fix: blur system config restart notice

* fix: tint restart notice blur background

* fix: allow totp setup without body

* fix: filter public openapi docs

* fix: handle settings autosave cleanup

* chore: ui
2026-06-16 11:03:42 +08:00
Weilong Liao 0d8e8682db refactor(core): migrate backend backbone from Quart to FastAPI and introduce more OpenAPI (#8688)
* refactor: migrate to fastapi

* structure refactor

* fix: pyright fix

* refactor: improve error handling and public messages in plugin services

* feat(api): refactor API client integration and enhance request handling

- Updated API client configuration to use a dedicated HTTP client.
- Introduced utility functions for generating options, queries, and form data for API requests.
- Refactored multiple API methods to utilize the new utility functions for improved consistency and readability.
- Renamed types for clarity and updated import statements accordingly.

feat(docs): add script to update OpenAPI JSON from YAML spec

- Created a Python script to convert OpenAPI YAML specification to JSON format.
- The script supports customizable input and output paths.
- Ensured the script handles directory creation for output paths and validates the YAML structure.

* fix

* feat(auth): implement rate limiting for v1 login endpoint and enhance request handling

* Refactor dashboard API routers to use legacy_router for backward compatibility

- Changed all instances of dashboard_router to legacy_router across multiple API modules including platform, plugins, providers, sessions, skills, stats, subagents, t2i, tools, updates, and asgi_runtime.
- Updated route definitions to ensure existing endpoints remain functional under the new router structure.
- Introduced support for Quart request context in asgi_runtime to enhance compatibility with existing Quart-based plugins.
- Added a test case to validate the functionality of the new Quart request context handling in plugin extensions.

* chore: remove cli test

* fix: update dashboard tests for fastapi migration

* chore: satisfy ruff checks

* fix: update openapi api key scopes

* fix: sync config scope chip selection

* fix: restore quart dependency

* docs: clarify quart plugin api compatibility

* docs: update openapi scope documentation

* fix: use singular skill openapi scope

* fix: hide update service exception details

* fix: address fastapi review comments

* fix: address dashboard review findings

* docs: revert unrelated package deployment changes

* docs: update agent api generation guidance

* feat: add plugin page web api helpers

* docs: add plugin page bridge demo

* fix: type plugin upload files

* fix: stabilize plugin page uploads

* fix: type plugin web request proxy

* docs: remove plugin page docs example

* fix: authenticate plugin page SSE bridge
2026-06-14 15:03:26 +08:00
zenfun 963122b916 chore: update gitignore, Makefile, skills route, and test scaffolding 2026-02-16 02:38:01 +08:00