Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 47 additions & 39 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ RUSTC_VERSION := $(shell rustc --version 2>/dev/null || echo "unknown")

WEB_ADMIN_DIR := web-admin
WEB_CONSOLE_DIR := web-console
NPM ?= $(or $(shell command -v npm 2>/dev/null),$(shell PATH=/opt/homebrew/bin:$$PATH command -v npm 2>/dev/null))
NPM_BIN_DIR := $(patsubst %/,%,$(dir $(NPM)))

CLIPPY_DENY_WARNINGS ?= 0

Expand Down Expand Up @@ -129,14 +131,14 @@ build-release: web-admin-build web-console-build
# Run tests / 运行测试
test:
@echo -e "$(BLUE)🧪 Running tests... / 运行测试...$(NC)"
@NOCAPTURE_ARGS=""; \
@TEST_ARGS="-- --test-threads=$${TEST_THREADS:-1}"; \
if [ "$(NOCAPTURE)" = "1" ]; then \
NOCAPTURE_ARGS="-- --nocapture"; \
TEST_ARGS="$$TEST_ARGS --nocapture"; \
fi; \
if [ -n "$(FEATURES)" ]; then \
$(CARGO) test --features $(FEATURES) $$NOCAPTURE_ARGS; \
$(CARGO) test --features $(FEATURES) $$TEST_ARGS; \
else \
$(CARGO) test $$NOCAPTURE_ARGS; \
$(CARGO) test $$TEST_ARGS; \
fi
@$(MAKE) web-admin-test
@$(MAKE) web-console-test
Expand All @@ -145,78 +147,84 @@ test:
.PHONY: web-admin-build web-admin-lint web-admin-test web-console-build web-console-lint web-console-test
web-admin-build:
@echo -e "$(BLUE)🔧 Building Web Admin assets... / 构建Web Admin静态资源...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
if [ -f "assets/admin/index.html" ] && [ -f "assets/admin/main.js" ] && [ -f "assets/admin/main.css" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, using existing assets/admin/* / 未找到npm,使用已有assets/admin/*$(NC)"; \
exit 0; \
else \
echo -e "$(RED)❌ npm not found and assets/admin/* missing. Install npm or run in an environment with Node. / 未找到npm且assets/admin/*不存在,请安装Node/npm$(NC)"; \
exit 1; \
fi; \
fi
@cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm run build
else \
cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" run build; \
fi; }
@echo -e "$(GREEN)✅ Web Admin assets built / Web Admin静态资源构建完成$(NC)"

web-console-build:
@echo -e "$(BLUE)🔧 Building SPEAR Console assets... / 构建SPEAR Console静态资源...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
if [ -f "assets/console/index.html" ] && [ -f "assets/console/main.js" ] && [ -f "assets/console/main.css" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, using existing assets/console/* / 未找到npm,使用已有assets/console/*$(NC)"; \
exit 0; \
else \
echo -e "$(RED)❌ npm not found and assets/console/* missing. Install npm or run in an environment with Node. / 未找到npm且assets/console/*不存在,请安装Node/npm$(NC)"; \
exit 1; \
fi; \
fi
@cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm run build
else \
cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" run build; \
fi; }
@echo -e "$(GREEN)✅ SPEAR Console assets built / SPEAR Console静态资源构建完成$(NC)"

web-console-lint:
@echo -e "$(BLUE)🔍 Linting SPEAR Console... / SPEAR Console代码检查...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, skipping SPEAR Console lint / 未找到npm,跳过SPEAR Console代码检查$(NC)"; \
exit 0; \
fi
@cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm run lint
else \
cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" run lint; \
fi; }
@echo -e "$(GREEN)✅ SPEAR Console lint completed / SPEAR Console代码检查完成$(NC)"

web-console-test:
@echo -e "$(BLUE)🧪 Running SPEAR Console tests... / 运行SPEAR Console测试...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, skipping SPEAR Console tests / 未找到npm,跳过SPEAR Console测试$(NC)"; \
exit 0; \
fi
@cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm test
else \
cd $(WEB_CONSOLE_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" test; \
fi; }
@echo -e "$(GREEN)✅ SPEAR Console tests completed / SPEAR Console测试完成$(NC)"

web-admin-lint:
@echo -e "$(BLUE)🔍 Linting Web Admin... / Web Admin代码检查...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, skipping Web Admin lint / 未找到npm,跳过Web Admin代码检查$(NC)"; \
exit 0; \
fi
@cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm run lint
else \
cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" run lint; \
fi; }
@echo -e "$(GREEN)✅ Web Admin lint completed / Web Admin代码检查完成$(NC)"

web-admin-test:
@echo -e "$(BLUE)🧪 Running Web Admin tests... / 运行Web Admin测试...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@{ if [ -z "$(NPM)" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, skipping Web Admin tests / 未找到npm,跳过Web Admin测试$(NC)"; \
exit 0; \
fi
@cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then npm ci --silent; else npm install --silent; fi) && \
npm test
else \
cd $(WEB_ADMIN_DIR) && \
(if [ -f package-lock.json ]; then PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" ci --silent; else PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent; fi) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" test; \
fi; }
@echo -e "$(GREEN)✅ Web Admin tests completed / Web Admin测试完成$(NC)"

test-mic-device:
Expand All @@ -233,7 +241,7 @@ mac-build-release:
.PHONY: test-ui
test-ui:
@echo -e "$(BLUE)🧪 Running UI tests... / 运行UI测试...$(NC)"
@if ! command -v npm >/dev/null 2>&1; then \
@if [ -z "$(NPM)" ]; then \
echo -e "$(YELLOW)⚠️ npm not found, skipping UI tests / 未找到npm,跳过UI测试$(NC)"; \
exit 0; \
fi
Expand Down Expand Up @@ -263,10 +271,10 @@ test-ui:
fi; \
}
@$(MAKE) web-admin-build
@cd ui-tests && \
npm install --silent && \
npm run install:pw --silent || true && \
npm test
@cd $(WEB_ADMIN_DIR) && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" install --silent && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" run install:pw --silent || true && \
PATH="$(NPM_BIN_DIR):$$PATH" "$(NPM)" test
@echo -e "$(GREEN)✅ UI tests completed / UI测试完成$(NC)"

# Run tests with specific feature / 运行特定特性的测试
Expand Down
46 changes: 34 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ This is the recommended cross-platform local setup (no Kubernetes required). It
Use the provided Compose file:

- `deploy/docker/compose.local.yaml`
- The local Compose stack builds SMS with the `rocksdb` feature enabled and persists both admin metadata and event KV under the `sms-data` volume.

Start:

Expand Down Expand Up @@ -170,19 +171,40 @@ SPEARlet can import models from a local Ollama on startup and materialize them a

## Web Admin

Web Admin provides Nodes/Tasks/Files/AI Models pages.

- AI Models provides an aggregated view across nodes, split into Local/Remote.
- Local AI Models supports creating/deleting model deployments on a node.

Local model provisioning (llamacpp):

- `model` is just a display key; actual download uses `params.model_url` when the model file is missing.
- Supported params:
- `model_url`: http/https URL to a `.gguf` file (large files are supported).
- `download_timeout_s`: total download budget in seconds (default: 3600).
Web Admin provides Nodes, Tasks, Files, AI Backends, AI Models, Credentials, MCP, and Execution History pages.

- AI Backends is the control-plane write surface for backend definitions, placements, and credentials.
- AI Models provides a read-only aggregated view across nodes, split into Local and Remote.
- The AI Backends page now exposes separate create flows:
- `Create Remote Backend`
- `Create Local Backend`
- Placement is created during backend creation:
- remote backends default to `All Nodes`
- local backends default to `Single Node`
- Backend detail pages expose:
- placements
- per-node status
- read-model views

Local model provisioning (`llamacpp`):

- `model` is the routing / display key; the node-local runtime uses metadata-backed runtime parameters.
- The Web Admin local dialog surfaces the most common `llamacpp` fields directly and persists them into backend metadata.
- Common fields:
- `model_url`: http/https URL to a `.gguf` file.
- `model_path`: absolute path, or relative to `spearlet.local_models_dir`.
- `skip_download=1`: fail if the model file is missing (no download).
- `skip_download=1`: fail if the model file is missing instead of downloading.
- `download_timeout_s`: total download budget in seconds (default: 3600).
- `threads`: forwarded to `llama-server --threads`.
- `ctx_size`: forwarded to `llama-server --ctx-size`.
- Advanced metadata keys still supported by runtime:
- `server_mode`
- `server_cmd`
- `server_cmd_args`
- `ready_probe`
- `start_timeout_s`

Local `vllm` remains a scaffolded / external-endpoint-oriented path rather than a fully managed local process mode.

Docs:

Expand Down
46 changes: 34 additions & 12 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ English README: [README.md](./README.md)
使用仓库自带 Compose 文件:

- `deploy/docker/compose.local.yaml`
- 本地 Compose 栈会用 `rocksdb` feature 构建 SMS,并把 admin metadata 与 event KV 一起持久化到 `sms-data` volume。

启动:

Expand Down Expand Up @@ -170,19 +171,40 @@ SPEARlet 支持在启动时从本机 Ollama 导入模型并生成对应的 AI ba

## Web Admin

Web Admin 提供 Nodes/Tasks/Files/AI Models 等页面。

- AI Models 提供跨节点聚合视图,并区分 Local/Remote
- Local AI Models 支持在节点上创建/删除 model deployment

本地模型拉取(llamacpp):

- `model` 只是展示用 key;当本地模型文件不存在时,实际下载取决于 `params.model_url`。
- 支持参数:
- `model_url`:指向 `.gguf` 的 http/https URL(支持大文件)。
- `download_timeout_s`:总下载超时预算(秒,默认 3600)。
Web Admin 提供 Nodes、Tasks、Files、AI Backends、AI Models、Credentials、MCP 和 Execution History 等页面。

- AI Backends 是 backend 定义、placement 与 credentials 的控制面写入口
- AI Models 提供跨节点只读聚合视图,并区分 Local / Remote
- AI Backends 页面现在提供两条创建入口:
- `Create Remote Backend`
- `Create Local Backend`
- backend 创建时会一并配置 placement:
- remote 默认 `All Nodes`
- local 默认 `Single Node`
- backend 详情页可查看:
- placements
- 按节点的 runtime status
- read model views

本地模型拉起(`llamacpp`):

- `model` 是路由 / 展示用 key;节点侧运行时使用 metadata 中的本地运行参数。
- Web Admin 的 local 创建对话框已经把最常用的 `llamacpp` 字段提成显式输入,并在保存时自动写回 backend metadata。
- 常用字段:
- `model_url`:指向 `.gguf` 的 http/https URL。
- `model_path`:绝对路径,或相对于 `spearlet.local_models_dir` 的相对路径。
- `skip_download=1`:模型文件不存在时直接失败(不下载)。
- `skip_download=1`:模型文件不存在时直接失败,不执行下载。
- `download_timeout_s`:总下载超时预算(秒,默认 3600)。
- `threads`:映射到 `llama-server --threads`。
- `ctx_size`:映射到 `llama-server --ctx-size`。
- 运行时仍支持的高级 metadata 字段:
- `server_mode`
- `server_cmd`
- `server_cmd_args`
- `ready_probe`
- `start_timeout_s`

本地 `vllm` 当前仍以脚手架 / external endpoint 场景为主,并非完整托管的本地进程模式。

文档:

Expand Down
2 changes: 1 addition & 1 deletion assets/admin/main.css

Large diffs are not rendered by default.

81 changes: 43 additions & 38 deletions assets/admin/main.js

Large diffs are not rendered by default.

Loading
Loading