feat(docker): Headless 可选部署的 Dev-Tools 镜像与 Compose 配置 - #410
Open
thirsty5034 wants to merge 16 commits into
Open
Conversation
StackCairn
marked this pull request as draft
August 9, 2026 10:26
Contributor
|
PR governance checks passed. Awaiting human review. |
thirsty5034
marked this pull request as ready for review
August 9, 2026 10:27
5 tasks
Contributor
Author
|
已同步一个构建修复( |
Replace direct AppHandle/State usage in the command layer with a plain AppContext assembly plus a typed event emitter, so the same business commands can run under both the desktop Tauri runtime and a headless server. Desktop-only modules are feature-gated behind the default desktop feature. Tests updated to assert the compat abstraction instead of the raw tauri runtime paths.
A --no-default-features build strips the Tauri desktop runtime and runs
the same command surface over an axum HTTP/WebSocket server: GET /health,
GET /api/status, POST /api/invoke, GET /ws event broadcast, GET /* WebUI
SPA fallback and /proxy/{provider}/ BFF routes. Adds a same-origin
security model (CORS gate, optional Bearer token auth, rate limiting by
real peer IP) and a runtime-fallback mode for browsers without the Tauri
bridge.
Add a tauriBridge module exposing the same invoke interface to the existing GUI code so the WebUI runs unchanged on the headless server (runtime-fallback over fetch/WebSocket). Adds HeadlessFolderPicker and headless-aware file upload. All GUI imports now go through the bridge instead of @tauri-apps/api directly.
scripts/manifest/commands.json is the committed source of truth for the 234 Tauri commands; build_type_map.py derives the Rust type map, gen_adapters.py regenerates commands/adapters.rs and verify_headless.py asserts headless.rs dispatch arms match the manifest both ways. The gen-verify CI job fails on any drift.
Add headless-rust (cargo check/test/build --no-default-features) and gen-verify (generator drift check) jobs. Document the headless security model and the command-registry workflow in the README.
…owser mode agent-gui (headless WebUI) previously re-exported @tauri-apps/api modules (tauriCore/tauriEvent/tauriOpener) which are native-Tauri-only and throw in the browser, breaking all agent-ui fs/memory/proxy/settings paths (workspaces all red, cannot add/activate workspace). Re-export from lib/tauriBridge instead so invoke/listen/openUrl/revealItemInDir fall back to the WebSocket/fetch bridge in headless mode. Verified: tsc + vite build pass; new bundle's fsBackend invoke now imports from tauriBridge chunk (fetch /api/invoke) instead of @tauri-apps/api/core.
The headless WebUI (agent-gui) handled system_pick_folder by simply returning the initial_workdir, so clicking '打开本地文件夹' closed the clone modal with no visible result (no directory picker). Intercept system_pick_folder in lib/tauriBridge for non-Tauri runtimes and show a browser prompt asking for the absolute server path, mirroring the agent-gateway web shim. The headless server still validates the path.
…save) Upstream added the model-failover settings command; the business fn was already merged into commands/config/settings/commands.rs but headless.rs had no dispatch arm and the manifest was stale, so saving model failover settings from the browser UI failed with 'unknown command'. - add dispatch arm in headless.rs (mirrors settings_save_memory) - register settings_save_model_failover in scripts/manifest/commands.json - regenerate commands/adapters.rs (235 adapters) - verify_headless.py: manifest 235 == dispatch 235
…load
The upstream merge dropped the wired-up versions of two headless WebUI
features; the components/endpoints survived but the glue was lost:
1. system_pick_folder fell back to a bare absolute-path text prompt
(HeadlessFolderPicker.tsx existed but was never wired). Route the
headless intercept through openFolderPicker() instead, so the user can
browse the server's filesystem (breadcrumbs + fs_list_dirs listing +
fs_roots quick locations) rather than typing a path by hand. Dynamic
import breaks the static cycle HeadlessFolderPicker -> fsBackend ->
shims/tauriCore -> tauriBridge.
2. 'pick files' in headless mode called system_pick_readable_files, which
errors ('file picker is unavailable in headless mode') because there is
no native dialog. Restore the browser <input type=file> fallback
(pickBrowserFiles) and route headless uploads (pick + drag&drop + paste)
through the multipart endpoint POST /api/files/import via
importReadableFilesViaMultipart (no base64 +33% expansion, no 413 on
larger files). Tauri desktop paths unchanged.
Verified: tsc, biome (changed files), vite build (HeadlessFolderPicker
emitted as its own lazy chunk), verify_headless.py 235==235, 1509 frontend
tests pass.
The proxy baseUrl was hardcoded to a loopback (http://127.0.0.1:17890). When the WebUI is reached through a public domain / reverse proxy (https://liveagent.code.pp00.top), the frontend built cross-origin proxy URLs pointing at 127.0.0.1, which the browser blocked via CORS (no Access-Control-Allow-Origin, plus HTTPS->HTTP mixed content), so model listing showed 'Failed to fetch' on the domain entry while the loopback entry worked. Now /api/invoke reads the browser Origin header and returns it as the proxy baseUrl, so proxy requests stay same-origin on the accessing entrypoint. Falls back to the startup loopback baseUrl for desktop/curl callers without an Origin.
thirsty5034
force-pushed
the
feat/headless-docker
branch
from
August 13, 2026 03:21
de1c3c6 to
f4f6ed4
Compare
- Route GUI imports through @liveagent/ui after agent-ui extract - Drop residual tauri:: usage from chat_history_set_cwd / HistorySetCwd - Align append_segment with ChatHistoryAppendSegmentInput across manifest, adapters, and headless dispatch
thirsty5034
force-pushed
the
feat/headless-docker
branch
from
August 13, 2026 04:12
f4f6ed4 to
ca5d119
Compare
thirsty5034
force-pushed
the
feat/headless-docker
branch
from
August 13, 2026 04:14
ca5d119 to
fa2a358
Compare
appUpdates now invokes through tauriBridge's dynamic desktop import. Mock the resolved bridge module so deferred install/check assertions stay in sync under the CommonJS test loader.
Single Dockerfile.headless-tools with TARGET_PROFILE=minimal|core|full, multi-arch amd64/arm64, shared base layers. Runtimes are managed by mise (go/node/pnpm/bun/python; full adds Temurin 17 + Maven) and kept lean; missing versions auto-install on first boot against a named volume. Adds the liveagent-headless-tools GH Actions workflow to build and push the three images to GHCR (main push/tag/workflow_dispatch).
docker-compose.headless-{minimal,core,full}.yml and
docker-compose.gateway.yml with data + mise volumes, per-profile
environment, restart policy and network mode; entrypoint.sh wires mise
lazy install with a bounded timeout. README documents the quick-start,
runtime version switching via MISE_*_VERSION and volume requirements.
thirsty5034
force-pushed
the
feat/headless-docker
branch
from
August 13, 2026 04:22
fa2a358 to
4f2f93e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 issue
Resolves #380(Headless 运行时主体见 #409,本 PR 在其之上增加可选部署层)
概述
为 Headless 运行时提供可选的部署层:基于
mise构建分层 Dev-Tools 镜像(minimal/core/full),并提供 headless 与 gateway 的 docker-compose 配置。本 PR 叠加在运行时 PR(#409)之上,增量仅为 Docker/Compose 工具链(11 个文件)。改动范围
Dockerfile.headless-tools、docker/、.github/workflows/liveagent-headless-tools.ymlDockerfile.headless-tools— 分层构建(minimal → core → full),apt/npm 镜像加速(mirrors.tuna.tsinghua.edu.cn、npmmirror),便于国内网络快速构建docker/docker-compose.headless-{minimal,core,full}.yml— headless 服务器配置docker/docker-compose.gateway.yml— gateway 部署配置docker/mise.{core,full}.toml— 锁定工具链版本.github/workflows/liveagent-headless-tools.yml— 在 main 分支 push/tag 时构建并推送镜像到ghcr.nju.edu.cn(支持手动触发)主要亮点
liveagent-full+liveagent-minimal),会话数据完好截图 / 预览
基于构建镜像运行的 Headless WebUI(运行时见 #409):
验证情况
ghcr.nju.edu.cn/thirsty5034/liveagent-*(手动触发,feat-headless-pr-g与main标签均存在)docker compose up启动 full 镜像,WebUI 可访问,既有会话数据保留提交前检查