mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-14 04:15:06 +08:00
🤞 Sync 2026-09-06 22:50:31
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@ AGENTFLOW_HASH_aarch64:=6d733ebc49b095bf8670a1b655a13bb8ad98c90ced19701b67d5cdd4
|
||||
|
||||
PKG_NAME:=agentflow
|
||||
PKG_VERSION:=0.3.0
|
||||
PKG_RELEASE:=7
|
||||
PKG_RELEASE:=8
|
||||
|
||||
AGENTFLOW_URL_FILE:=agentflow-linux-$(AGENTFLOW_ARCH)
|
||||
AGENTFLOW_DOWNLOAD:=$(AGENTFLOW_URL_FILE)-$(AGENTFLOW_HASH_$(ARCH))
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
# AgentFlow 共享 Runtime HOME 实施里程碑
|
||||
|
||||
## 目标架构
|
||||
|
||||
AgentFlow 的应用数据和设备级开发运行时分离:
|
||||
|
||||
- AgentFlow 数据目录:`<quickstart.conf_dir>/AgentFlow`
|
||||
- 共享 Runtime HOME:`<quickstart.conf_dir>/Runtime/home`
|
||||
|
||||
共享 Runtime HOME 由 `mise` 包提供公共 helper 初始化,AgentFlow 和后续运行时感知应用复用同一套 `HOME`、XDG、`MISE_*` 和 `PATH`。
|
||||
|
||||
## Milestone 1:公共 Runtime HOME 合约
|
||||
|
||||
目标:
|
||||
|
||||
- `mise` 包安装 `/etc/config/mise`。
|
||||
- `mise` 包安装 `/lib/functions/istore_runtime.sh`。
|
||||
- helper 自动从 `quickstart.main.conf_dir` 推导 `<conf_dir>/Runtime/home`。
|
||||
- helper 支持 `ISTORE_RUNTIME_CONF_DIR` 兜底,便于应用从自身 Configs 目录派生 Runtime。
|
||||
- helper 统一导出 `HOME`、`XDG_DATA_HOME`、`XDG_CACHE_HOME`、`XDG_CONFIG_HOME`、`XDG_STATE_HOME`、`MISE_DATA_DIR`、`MISE_CACHE_DIR`、`MISE_CONFIG_DIR`、`MISE_STATE_DIR` 和 `PATH`。
|
||||
|
||||
验收:
|
||||
|
||||
- 新安装 `mise` 后,存在 `/etc/config/mise` 和 `/lib/functions/istore_runtime.sh`。
|
||||
- 已配置 quickstart 时,初始化路径为 `<quickstart.conf_dir>/Runtime/home`。
|
||||
- 未配置 quickstart 但应用提供 `ISTORE_RUNTIME_CONF_DIR` 时,初始化路径为 `$ISTORE_RUNTIME_CONF_DIR/Runtime/home`。
|
||||
|
||||
## Milestone 2:AgentFlow 接入共享 Runtime HOME
|
||||
|
||||
目标:
|
||||
|
||||
- AgentFlow 不再使用 `$data_dir/global` 作为 `HOME` 或 mise shim 根。
|
||||
- AgentFlow 启动时调用 `istore_runtime_export_env`。
|
||||
- `AGENT_FLOW_DATA` 继续固定在 AgentFlow 数据目录下的 `data` 子目录。
|
||||
- AgentFlow 服务进程及其子进程继承共享 Runtime HOME。
|
||||
|
||||
验收:
|
||||
|
||||
- `/etc/init.d/agentflow start` 后,AgentFlow 进程环境中 `HOME=<conf_dir>/Runtime/home`。
|
||||
- `MISE_DATA_DIR=$HOME/.local/share/mise`。
|
||||
- `PATH` 以 `$MISE_DATA_DIR/shims:$HOME/.local/bin` 开头。
|
||||
- AgentFlow 数据库仍写入 `<conf_dir>/AgentFlow/data/db/db.sqlite`。
|
||||
|
||||
## Milestone 3:LuCI 可见性
|
||||
|
||||
目标:
|
||||
|
||||
- AgentFlow LuCI 页面继续配置 AgentFlow 数据目录。
|
||||
- 页面展示推导出的共享 Runtime HOME。
|
||||
- 如果 `mise.runtime_dir` 被显式设置,页面展示其对应的 `home`。
|
||||
|
||||
验收:
|
||||
|
||||
- quickstart `conf_dir=/mnt/vio3-1/Configs` 时,页面显示 `/mnt/vio3-1/Configs/Runtime/home`。
|
||||
- AgentFlow 数据目录仍显示 `/mnt/vio3-1/Configs/AgentFlow`。
|
||||
|
||||
## Milestone 4:迁移与兼容
|
||||
|
||||
目标:
|
||||
|
||||
- 新安装默认使用共享 Runtime HOME。
|
||||
- 老安装中已有 `$data_dir/global/.local/share/mise` 时,不自动移动大目录。
|
||||
- 后续提供显式迁移命令或 LuCI 操作。
|
||||
|
||||
验收:
|
||||
|
||||
- 升级不会删除或搬移旧 runtime 数据。
|
||||
- 用户确认迁移后,旧 mise data 可迁移到 `<conf_dir>/Runtime/home/.local/share/mise`。
|
||||
- 迁移失败不会影响 AgentFlow 私有数据。
|
||||
|
||||
## Milestone 5:AgentFlow 后端项目环境集成
|
||||
|
||||
目标:
|
||||
|
||||
- OpenWrt 层面完成共享 HOME 后,再在 AgentFlow 后端引入项目环境 wrapper。
|
||||
- coding agent 进程使用 `mise exec -- <agent> ...` 应用项目 `mise.toml`。
|
||||
- 运行期设置 `MISE_EXEC_AUTO_INSTALL=0`,缺失工具只在准备阶段安装。
|
||||
|
||||
验收:
|
||||
|
||||
- 单 repo 项目中,agent 看到项目声明的 Node/Python/Go 版本。
|
||||
- 没有隐式运行期下载。
|
||||
- Codex/Claude/Kimi 等 agent 凭据继续来自共享 Runtime HOME。
|
||||
- 取消任务时 wrapper 和 agent 子进程都能退出。
|
||||
@@ -10,22 +10,6 @@ get_config() {
|
||||
config_get port "$1" port "9000"
|
||||
}
|
||||
|
||||
load_runtime_env() {
|
||||
local conf_dir
|
||||
|
||||
[ -n "$data_dir" ] || return 1
|
||||
conf_dir="$(dirname "$data_dir")"
|
||||
export ISTORE_RUNTIME_CONF_DIR="$conf_dir"
|
||||
|
||||
if [ -r /lib/functions/istore_runtime.sh ]; then
|
||||
. /lib/functions/istore_runtime.sh
|
||||
istore_runtime_export_env
|
||||
return $?
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load agentflow
|
||||
config_foreach get_config agentflow
|
||||
@@ -35,11 +19,16 @@ start_service() {
|
||||
logger -t agentflow "missing executable: /usr/sbin/agentflow"
|
||||
return 1
|
||||
}
|
||||
mkdir -p "$data_dir" "$data_dir/data" || return 1
|
||||
if ! load_runtime_env; then
|
||||
logger -t agentflow "shared runtime home is not configured"
|
||||
[ -r /lib/functions/mise.sh ] || {
|
||||
logger -t agentflow "missing mise environment helper"
|
||||
return 1
|
||||
}
|
||||
. /lib/functions/mise.sh
|
||||
if ! istore_runtime_env; then
|
||||
logger -t agentflow "failed to initialize mise environment"
|
||||
return 1
|
||||
fi
|
||||
mkdir -p "$data_dir" "$data_dir/data" || return 1
|
||||
|
||||
logger -t agentflow "starting AgentFlow on $host:$port"
|
||||
procd_open_instance
|
||||
@@ -49,14 +38,6 @@ start_service() {
|
||||
"AGENT_FLOW_HOST=$host" \
|
||||
"AGENT_FLOW_PORT=$port" \
|
||||
"HOME=$HOME" \
|
||||
"XDG_DATA_HOME=$XDG_DATA_HOME" \
|
||||
"XDG_CACHE_HOME=$XDG_CACHE_HOME" \
|
||||
"XDG_CONFIG_HOME=$XDG_CONFIG_HOME" \
|
||||
"XDG_STATE_HOME=$XDG_STATE_HOME" \
|
||||
"MISE_DATA_DIR=$MISE_DATA_DIR" \
|
||||
"MISE_CACHE_DIR=$MISE_CACHE_DIR" \
|
||||
"MISE_CONFIG_DIR=$MISE_CONFIG_DIR" \
|
||||
"MISE_STATE_DIR=$MISE_STATE_DIR" \
|
||||
"PATH=$PATH"
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
THIS_FILE = Path(__file__).resolve()
|
||||
|
||||
|
||||
def read(relative):
|
||||
relative_path = Path(relative)
|
||||
package = relative_path.parts[0]
|
||||
app = package[9:] if package.startswith("luci-app-") else package
|
||||
remainder = Path(*relative_path.parts[1:])
|
||||
|
||||
candidates = [
|
||||
THIS_FILE.parents[index] / relative_path
|
||||
for index in range(2, min(len(THIS_FILE.parents), 6))
|
||||
]
|
||||
candidates.append(THIS_FILE.parents[3] / app / package / remainder)
|
||||
|
||||
for candidate in candidates:
|
||||
if candidate.exists():
|
||||
return candidate.read_text()
|
||||
|
||||
searched = "\n".join(str(candidate) for candidate in candidates)
|
||||
raise FileNotFoundError(f"{relative} not found; searched:\n{searched}")
|
||||
|
||||
|
||||
class MiseRuntimeContractTest(unittest.TestCase):
|
||||
def test_mise_package_installs_shared_runtime_contract(self):
|
||||
makefile = read("mise/Makefile")
|
||||
config = read("mise/files/mise.config")
|
||||
defaults = read("mise/files/mise.uci-default")
|
||||
helper = read("mise/files/istore_runtime.sh")
|
||||
|
||||
self.assertIn("/etc/config/mise", makefile)
|
||||
self.assertIn("/lib/functions/istore_runtime.sh", makefile)
|
||||
self.assertIn("$(INSTALL_BIN) ./files/mise.uci-default", makefile)
|
||||
self.assertIn("[ -f /etc/uci-defaults/mise ]", makefile)
|
||||
|
||||
self.assertIn("config mise 'main'", config)
|
||||
self.assertIn("option runtime_dir ''", config)
|
||||
self.assertIn("option auto_discover '1'", config)
|
||||
|
||||
self.assertIn(". /lib/functions/istore_runtime.sh", defaults)
|
||||
self.assertIn("istore_runtime_init", defaults)
|
||||
|
||||
self.assertIn("config_get conf_dir main conf_dir", helper)
|
||||
self.assertIn('"$conf_dir" "$ISTORE_RUNTIME_DEFAULT_SUBDIR"', helper)
|
||||
self.assertIn("ISTORE_RUNTIME_HOME_SUBDIR=\"home\"", helper)
|
||||
self.assertIn("ISTORE_RUNTIME_CONF_DIR", helper)
|
||||
self.assertIn('export HOME="$runtime_home"', helper)
|
||||
self.assertIn('export XDG_DATA_HOME="$HOME/.local/share"', helper)
|
||||
self.assertIn('export MISE_DATA_DIR="$XDG_DATA_HOME/mise"', helper)
|
||||
self.assertIn('export PATH="$MISE_DATA_DIR/shims:$HOME/.local/bin:$PATH"', helper)
|
||||
|
||||
def test_agentflow_consumes_shared_runtime_home(self):
|
||||
init = read("agentflow/files/agentflow.init")
|
||||
cbi = read("luci-app-agentflow/luasrc/model/cbi/agentflow.lua")
|
||||
model = read("luci-app-agentflow/luasrc/model/agentflow.lua")
|
||||
translations = read("luci-app-agentflow/po/zh-cn/agentflow.po")
|
||||
|
||||
self.assertIn(". /lib/functions/istore_runtime.sh", init)
|
||||
self.assertIn("istore_runtime_export_env", init)
|
||||
self.assertIn('AGENT_FLOW_DATA=$data_dir/data', init)
|
||||
self.assertIn('HOME=$HOME', init)
|
||||
self.assertIn('MISE_DATA_DIR=$MISE_DATA_DIR', init)
|
||||
self.assertNotIn("$data_dir/global", init)
|
||||
self.assertNotIn(".local/share/mise/shims:$PATH", init)
|
||||
|
||||
self.assertIn('translate("Shared runtime home")', cbi)
|
||||
self.assertIn("agentflow_model.runtime_home", cbi)
|
||||
self.assertIn('return runtime_dir .. "/home"', model)
|
||||
self.assertIn('return conf_dir .. "/Runtime"', model)
|
||||
|
||||
self.assertIn('msgid "Shared runtime home"', translations)
|
||||
self.assertIn('msgstr "共享运行时 HOME"', translations)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user