diff --git a/README.md b/README.md index 64eec4ce..1e221a3b 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,9 @@ make down WITH_BROWSER=1 WITH_OTEL=1 When `GOCLAW_*_API_KEY` environment variables are set, the gateway auto-onboards without interactive prompts — detects provider, runs migrations, and seeds default data. -> For detailed configuration and Docker image tags, see the [Deployment Guide](https://docs.goclaw.sh/#deploy-docker-compose). +> `ghcr.io/nextlevelbuilder/goclaw:latest` is the minimal runtime image and does **not** include Python or Node.js by default. If you need those runtimes preinstalled, use the `python`, `node`, or `full` image variant, run `./scripts/setup-docker.sh --variant `, or rebuild locally with `ENABLE_PYTHON=true`, `ENABLE_NODE=true`, or `ENABLE_FULL_SKILLS=true`. + +> For build variants (OTel, Tailscale, Redis), Docker image tags, and compose overlays, see the [Deployment Guide](https://docs.goclaw.sh/#deploy-docker-compose). ## Multi-Agent Orchestration diff --git a/docs/14-skills-runtime.md b/docs/14-skills-runtime.md index a398513a..5c386f2e 100644 --- a/docs/14-skills-runtime.md +++ b/docs/14-skills-runtime.md @@ -1,6 +1,6 @@ # 14 - Skills Runtime Environment -How skills access Python, Node.js, and system tools inside the Docker container. Covers pre-installed packages, runtime installation, and security constraints. +How skills access Python, Node.js, and system tools inside the Docker container. Covers image variants, pre-installed packages, runtime installation, and security constraints. --- @@ -14,10 +14,10 @@ How skills access Python, Node.js, and system tools inside the Docker container. │ │ Pre-installed │ │ Writable Runtime Dir │ │ │ │ (image layer) │ │ /app/data/.runtime/ │ │ │ │ │ │ │ │ -│ │ python3, node │ │ pip/ ← PIP_TARGET │ │ -│ │ gh, pandoc │ │ pip-cache/ ← PIP_CACHE │ │ -│ │ pypdf, openpyxl │ │ npm-global/ ← NPM_PREFIX │ │ -│ │ pandas, etc. │ │ │ │ +│ │ latest/alpine │ │ pip/ ← PIP_TARGET │ │ +│ │ no py/node │ │ pip-cache/ ← PIP_CACHE │ │ +│ │ python/node/full│ │ npm-global/ ← NPM_PREFIX │ │ +│ │ add runtimes │ │ │ │ │ └─────────────────┘ └──────────────────────────────┘ │ │ │ │ Volumes (read-write): │ @@ -33,9 +33,20 @@ How skills access Python, Node.js, and system tools inside the Docker container. ## 2. Pre-installed Packages (Option A) -Installed at build time in the Dockerfile when `ENABLE_PYTHON=true`. +Pre-installed runtimes depend on the Docker image variant you deploy. The Packages page and `/v1/packages/runtimes` report what exists inside the active GoClaw container, not what exists on the host machine. -### Python Packages +### Runtime Variant Matrix + +| Variant | Published tag | Build args | Pre-installed runtimes | +|---------|---------------|------------|------------------------| +| Minimal | `latest` | `ENABLE_PYTHON=false`, `ENABLE_NODE=false`, `ENABLE_FULL_SKILLS=false` | No Python or Node.js runtimes | +| Python | `python` | `ENABLE_PYTHON=true` | `python3`, `py3-pip`, `edge-tts` | +| Node | `node` | `ENABLE_NODE=true` | `nodejs`, `npm` | +| Full | `full` | `ENABLE_FULL_SKILLS=true` | `python3`, `py3-pip`, `nodejs`, `npm`, `pandoc`, `github-cli`, bundled skill deps | + +### Full Variant Extras + +#### Python Packages | Package | Version | Used By | |---------|---------|---------| @@ -45,22 +56,13 @@ Installed at build time in the Dockerfile when `ENABLE_PYTHON=true`. | `python-pptx` | latest | pptx skill | | `markitdown` | latest | pptx skill (content extraction) | -### Node.js Packages (global) +#### Node.js Packages (global) | Package | Used By | |---------|---------| | `docx` | docx skill (document creation) | | `pptxgenjs` | pptx skill (presentation creation) | -### System Tools - -| Tool | Purpose | -|------|---------| -| `python3` + `py3-pip` | Python runtime + package manager | -| `nodejs` + `npm` | Node.js runtime + package manager | -| `pandoc` | Document format conversion | -| `github-cli` (`gh`) | GitHub API operations | - --- ## 3. Runtime Package Installation (Option B) @@ -90,11 +92,11 @@ PATH=/app/data/.runtime/npm-global/bin:/app/data/.runtime/pip/bin:$PATH ### Agent Guidance -The system prompt includes this section so agents know what's available: +The system prompt and UI should treat runtime availability as variant-dependent: ``` -Pre-installed: python3, node, gh, pypdf, openpyxl, pandas, python-pptx, -markitdown, docx (npm), pptxgenjs (npm), pandoc. +Minimal `latest`: Python/Node may be missing in the container. +`python`, `node`, and `full` variants pre-install different runtimes. To install additional packages: pip3 install or npm install -g ``` @@ -179,10 +181,10 @@ When a user uploads a skill with the same name via the UI, the managed version t To add a new package to the Docker image: -1. **Python**: Add to the `pip3 install` line in `Dockerfile` -2. **Node.js**: Add to the `npm install -g` line in `Dockerfile` +1. **Python**: Add to the `pip3 install` line in `Dockerfile` (usually `full`, sometimes `python`) +2. **Node.js**: Add to the `npm install -g` line in `Dockerfile` (usually `full`, sometimes `node`) 3. **System tool**: Add to the `apk add` line in `Dockerfile` -4. **System prompt**: Update the pre-installed list in `systemprompt.go` (`buildToolSection`) +4. **Docs/UI guidance**: Update runtime variant docs and any UI copy that describes pre-installed tools 5. **Rebuild**: `docker compose ... up -d --build` For packages only needed by specific skills, prefer runtime installation (Option B) to keep the image lean. diff --git a/docs/18-http-api.md b/docs/18-http-api.md index f327d48a..8ff2c27e 100644 --- a/docs/18-http-api.md +++ b/docs/18-http-api.md @@ -506,7 +506,7 @@ CLI authentication credentials for secure command execution. Requires **admin ro ## 17. Runtime & Packages Management -Manage system (apk), Python (pip), and Node (npm) package installation in the runtime container. Requires authentication. When `GOCLAW_GATEWAY_TOKEN` is empty (dev/single-user mode), all users get admin role and can manage packages. +Manage system (apk), Python (pip), and Node (npm) package installation in the GoClaw runtime container. These endpoints do not inspect host-level runtimes. Requires authentication. When `GOCLAW_GATEWAY_TOKEN` is empty (dev/single-user mode), all users get admin role and can manage packages. ### List Installed Packages @@ -591,17 +591,25 @@ Same format as install. System packages are removed from persist file and contai GET /v1/packages/runtimes ``` -Check if Python and Node runtimes are available in the container. +Check which prerequisite runtimes are available inside the active GoClaw runtime container. Host-installed runtimes and shell-profile-managed binaries (for example `nvm`) are not included in this result. **Response:** ```json { - "python": true, - "node": true + "runtimes": [ + {"name": "python3", "available": false}, + {"name": "pip3", "available": false}, + {"name": "node", "available": false}, + {"name": "npm", "available": false}, + {"name": "pkg-helper", "available": true, "version": "socket"} + ], + "ready": false } ``` +The published `ghcr.io/nextlevelbuilder/goclaw:latest` image is the minimal variant, so missing Python or Node runtimes can be expected there. + --- ## 18. Traces & Costs diff --git a/internal/tools/message.go b/internal/tools/message.go index 26bf0758..6241d610 100644 --- a/internal/tools/message.go +++ b/internal/tools/message.go @@ -338,9 +338,12 @@ func isGroupContext(ctx context.Context) bool { } // resolveMediaPath extracts and validates a file path from a "MEDIA:path" string. -// Uses the same workspace-aware path resolution as other filesystem tools: -// - When restrict_to_workspace is true: allows workspace dir + /tmp/ -// - When restrict_to_workspace is false: allows any valid path +// Uses the same workspace-aware path resolution as other filesystem tools. +// Multi-tenant isolation forces MEDIA: paths through restricted resolution +// first, with one explicit fallback for generated media artifacts under /tmp/. +// In practice MEDIA: paths may resolve to: +// - files inside the agent workspace +// - absolute paths under /tmp/ for generated media artifacts // // Relative paths are resolved against the agent's workspace. func (t *MessageTool) resolveMediaPath(ctx context.Context, s string) (string, bool) { diff --git a/scripts/setup-docker.sh b/scripts/setup-docker.sh index 20de9ef9..27704c93 100644 --- a/scripts/setup-docker.sh +++ b/scripts/setup-docker.sh @@ -52,10 +52,10 @@ done if [ -z "$VARIANT" ]; then echo "Select GoClaw Docker variant:" echo "" - echo " 1) alpine — Base image (~50 MB), no runtimes" - echo " 2) node — + Node.js (for JS/TS skills)" - echo " 3) python — + Python (for Python skills)" - echo " 4) full — + Node.js + Python + all skill deps" + echo " 1) alpine — Base image (~50 MB), no runtimes (published as :latest)" + echo " 2) node — + Node.js (published as :node)" + echo " 3) python — + Python (published as :python)" + echo " 4) full — + Node.js + Python + all skill deps (published as :full)" echo "" read -rp "Choice [1-4, default=1]: " choice case "${choice:-1}" in diff --git a/ui/web/src/i18n/locales/en/packages.json b/ui/web/src/i18n/locales/en/packages.json index f29d2bdf..7a7b37e3 100644 --- a/ui/web/src/i18n/locales/en/packages.json +++ b/ui/web/src/i18n/locales/en/packages.json @@ -1,10 +1,14 @@ { "title": "Runtime & Packages", - "description": "Manage system runtimes and installed packages", + "description": "Manage runtimes and installed packages inside the active GoClaw runtime container", "runtimes": { "title": "Runtimes", + "scopeTitle": "Container-scoped runtime status", + "scopeDesc": "These checks run inside the active GoClaw runtime container. Host-installed runtimes, shell profile changes, and nvm-managed binaries are not used here.", + "minimalImageHint": "The published latest image is minimal, so missing Python or Node runtimes can be expected there. Use the python, node, or full image variant, rebuild with ENABLE_PYTHON=true / ENABLE_NODE=true / ENABLE_FULL_SKILLS=true, or install runtimes manually in this container.", "available": "Available", - "missing": "Missing" + "missing": "Missing", + "missingInContainer": "Missing in container" }, "system": { "title": "System Packages", diff --git a/ui/web/src/i18n/locales/en/skills.json b/ui/web/src/i18n/locales/en/skills.json index 93c62ece..b4670f28 100644 --- a/ui/web/src/i18n/locales/en/skills.json +++ b/ui/web/src/i18n/locales/en/skills.json @@ -99,8 +99,9 @@ "statusActive": "Active", "statusArchived": "Missing deps", "runtimeMissing": "Runtime Prerequisites Missing", - "runtimeMissingDesc": "Core skills require Python and/or Node.js runtimes. Rebuild with ENABLE_PYTHON=true, ENABLE_NODE=true, or ENABLE_FULL_SKILLS=true, or install manually.", - "runtimeRequired": "Install runtimes first" + "runtimeMissingDesc": "Core skills require Python and/or Node.js runtimes inside the GoClaw runtime container. Host-installed runtimes are not used here. If you are using the published latest image, missing runtimes can be expected there.", + "runtimeMissingAction": "Open Packages to verify or install runtimes in this container.", + "runtimeRequired": "Install container runtimes first" }, "detail": { "title": "Skill Detail", @@ -119,4 +120,4 @@ "rescanNoChanges": "All skills up to date", "rescanFailed": "Failed to rescan dependencies" } -} \ No newline at end of file +} diff --git a/ui/web/src/i18n/locales/vi/packages.json b/ui/web/src/i18n/locales/vi/packages.json index 56fff9d9..f231638a 100644 --- a/ui/web/src/i18n/locales/vi/packages.json +++ b/ui/web/src/i18n/locales/vi/packages.json @@ -1,10 +1,14 @@ { "title": "Runtime & Gói phần mềm", - "description": "Quản lý runtime hệ thống và các gói đã cài đặt", + "description": "Quản lý runtime và các gói đã cài đặt bên trong container GoClaw đang hoạt động", "runtimes": { "title": "Runtimes", + "scopeTitle": "Trạng thái runtime theo container", + "scopeDesc": "Các kiểm tra này chạy bên trong container runtime GoClaw hiện tại. Runtime cài trên máy host, thay đổi shell profile và binary do nvm quản lý sẽ không được dùng ở đây.", + "minimalImageHint": "Image latest được phát hành là bản tối giản, nên việc thiếu Python hoặc Node ở đó có thể là bình thường. Hãy dùng biến thể image python, node hoặc full, build lại với ENABLE_PYTHON=true / ENABLE_NODE=true / ENABLE_FULL_SKILLS=true, hoặc cài runtime trực tiếp trong container này.", "available": "Sẵn sàng", - "missing": "Chưa cài" + "missing": "Chưa cài", + "missingInContainer": "Thiếu trong container" }, "system": { "title": "Gói hệ thống", diff --git a/ui/web/src/i18n/locales/vi/skills.json b/ui/web/src/i18n/locales/vi/skills.json index 9b8897ea..550fd145 100644 --- a/ui/web/src/i18n/locales/vi/skills.json +++ b/ui/web/src/i18n/locales/vi/skills.json @@ -99,8 +99,9 @@ "statusActive": "Active", "statusArchived": "Missing deps", "runtimeMissing": "Runtime Prerequisites Missing", - "runtimeMissingDesc": "Core skills require Python and/or Node.js runtimes. Rebuild with ENABLE_PYTHON=true, ENABLE_NODE=true, or ENABLE_FULL_SKILLS=true, or install manually.", - "runtimeRequired": "Install runtimes first" + "runtimeMissingDesc": "Các core skill cần runtime Python và/hoặc Node.js bên trong container runtime GoClaw. Runtime cài trên máy host sẽ không được dùng ở đây. Nếu bạn đang dùng image latest đã phát hành thì việc thiếu runtime có thể là bình thường.", + "runtimeMissingAction": "Mở trang Packages để kiểm tra hoặc cài runtime trong container này.", + "runtimeRequired": "Hãy cài runtime trong container trước" }, "detail": { "title": "Chi tiết skill", @@ -119,4 +120,4 @@ "rescanNoChanges": "Tất cả skill đã cập nhật", "rescanFailed": "Không thể quét lại dependencies" } -} \ No newline at end of file +} diff --git a/ui/web/src/i18n/locales/zh/packages.json b/ui/web/src/i18n/locales/zh/packages.json index 35fa4c46..fbb5722c 100644 --- a/ui/web/src/i18n/locales/zh/packages.json +++ b/ui/web/src/i18n/locales/zh/packages.json @@ -1,10 +1,14 @@ { "title": "运行时与软件包", - "description": "管理系统运行时和已安装的软件包", + "description": "管理当前 GoClaw 运行时容器内的运行时和已安装软件包", "runtimes": { "title": "运行时", + "scopeTitle": "容器范围内的运行时状态", + "scopeDesc": "这些检查在当前活动的 GoClaw 运行时容器内执行。宿主机已安装的运行时、shell profile 变更以及由 nvm 管理的二进制文件都不会在这里被使用。", + "minimalImageHint": "已发布的 latest 镜像是最小化变体,因此缺少 Python 或 Node 运行时在该镜像中可能是正常现象。请改用 python、node 或 full 镜像变体,或使用 ENABLE_PYTHON=true / ENABLE_NODE=true / ENABLE_FULL_SKILLS=true 重新构建,或者直接在此容器中手动安装运行时。", "available": "可用", - "missing": "缺失" + "missing": "缺失", + "missingInContainer": "容器内缺失" }, "system": { "title": "系统软件包", diff --git a/ui/web/src/i18n/locales/zh/skills.json b/ui/web/src/i18n/locales/zh/skills.json index 55e7ec92..00f056f7 100644 --- a/ui/web/src/i18n/locales/zh/skills.json +++ b/ui/web/src/i18n/locales/zh/skills.json @@ -99,8 +99,9 @@ "statusActive": "Active", "statusArchived": "Missing deps", "runtimeMissing": "Runtime Prerequisites Missing", - "runtimeMissingDesc": "Core skills require Python and/or Node.js runtimes. Rebuild with ENABLE_PYTHON=true, ENABLE_NODE=true, or ENABLE_FULL_SKILLS=true, or install manually.", - "runtimeRequired": "Install runtimes first" + "runtimeMissingDesc": "核心技能需要在 GoClaw 运行时容器内提供 Python 和/或 Node.js 运行时。宿主机上的运行时不会在这里被使用。如果你使用的是已发布的 latest 镜像,那么缺少这些运行时可能是正常现象。", + "runtimeMissingAction": "打开 Packages 页面,在此容器中检查或安装运行时。", + "runtimeRequired": "请先安装容器内运行时" }, "detail": { "title": "Skill详情", @@ -119,4 +120,4 @@ "rescanNoChanges": "所有技能已是最新", "rescanFailed": "重新扫描依赖失败" } -} \ No newline at end of file +} diff --git a/ui/web/src/pages/packages/packages-page.tsx b/ui/web/src/pages/packages/packages-page.tsx index b33f4524..f88283e4 100644 --- a/ui/web/src/pages/packages/packages-page.tsx +++ b/ui/web/src/pages/packages/packages-page.tsx @@ -1,8 +1,9 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; -import { RefreshCw, Loader2, Trash2, Download, CheckCircle2, XCircle } from "lucide-react"; +import { RefreshCw, Loader2, Trash2, Download, CheckCircle2, XCircle, AlertTriangle } from "lucide-react"; import { PageHeader } from "@/components/shared/page-header"; import { ConfirmDialog } from "@/components/shared/confirm-dialog"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; import { usePackages, type PackageInfo } from "./hooks/use-packages"; import { usePackageRuntimes } from "./hooks/use-package-runtimes"; @@ -13,6 +14,7 @@ export function PackagesPage() { const { t } = useTranslation("packages"); const { packages, loading, refresh, installPackage, uninstallPackage } = usePackages(); const { runtimes, loading: runtimesLoading, refresh: refreshRuntimes } = usePackageRuntimes(); + const hasMissingRuntimes = (runtimes?.runtimes?.some((rt) => !rt.available)) ?? false; return (
@@ -33,8 +35,18 @@ export function PackagesPage() { /> {/* Runtimes Section */} -
+

{t("runtimes.title")}

+ + + + {t("runtimes.scopeTitle")} + + +

{t("runtimes.scopeDesc")}

+ {hasMissingRuntimes &&

{t("runtimes.minimalImageHint")}

} +
+
{runtimes?.runtimes?.map((rt) => (
{rt.version}

)} {!rt.available && ( -

{t("runtimes.missing")}

+

{t("runtimes.missingInContainer")}

)}
))} diff --git a/ui/web/src/pages/skills/missing-deps-panel.tsx b/ui/web/src/pages/skills/missing-deps-panel.tsx index c657d751..83a17bd9 100644 --- a/ui/web/src/pages/skills/missing-deps-panel.tsx +++ b/ui/web/src/pages/skills/missing-deps-panel.tsx @@ -1,7 +1,9 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { Link } from "react-router"; import { Button } from "@/components/ui/button"; import { Download, Loader2, AlertTriangle, CheckCircle2, XCircle } from "lucide-react"; +import { ROUTES } from "@/lib/constants"; import type { RuntimeStatus } from "./hooks/use-runtimes"; interface MissingDepsPanelProps { @@ -81,6 +83,12 @@ export function MissingDepsPanel({ missing, onInstallItem, runtimes }: MissingDe

{t("deps.runtimeMissingDesc")}

+ + {t("deps.runtimeMissingAction")} +
{missingRuntimes.map((r) => (