@h-ai/ai 1.0.0-beta.5 → 1.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ # ACP Agent 镜像
2
+
3
+ ## 用途
4
+
5
+ Codex/dsh 镜像为 `ai.acp` 的 builtin-service 提供原生 stdio 执行环境;Goose 镜像提供自身的原生 HTTP/WS 服务,通过 custom-service 接入。默认非 root 用户 node,不包含引擎 socket;不把 stdio 转成 HTTP/WS。
6
+
7
+ ## 构建与使用
8
+
9
+ ```sh
10
+ pnpm --filter @h-ai/ai agent:build codex-acp
11
+ pnpm --filter @h-ai/ai agent:build deepseek-harness --engine=podman
12
+ pnpm --filter @h-ai/ai agent:build goose
13
+ pnpm --filter @h-ai/ai agent:build codex-acp --engine=docker --java --rust --go
14
+ ```
15
+
16
+ auto 默认先探测可用 Podman,再探测 Docker;显式选择不会降级。镜像标签来自各目录 agent.json。
17
+
18
+ | 镜像 | 必需程序 |
19
+ | ---------------------------------- | ----------------------------------------------------------------------------- |
20
+ | hai-ai/codex-acp:2.5.0 | codex-acp 2.5.0 + 原生 codex 0.165.0 |
21
+ | hai-ai/deepseek-harness:0.2.1-rc.5 | dsh 0.2.1-rc.5,profile=acp |
22
+ | hai-ai/goose:1.57.0 | 官方 Goose 1.57.0 Linux amd64 musl 二进制,校验固定 SHA256,原生 /acp HTTP/WS |
23
+
24
+ 所有镜像含 Git、Node 24、Python 3;可选 Java JDK、Rust/Cargo、Go。Git 缺失属于明确错误,不降级跳过。构建需要 Debian 和 npm 网络访问;版本升级应同步 manifest、Dockerfile、适配器和实际 Agent E2E。
25
+
26
+ Agent 配置指定 builtin-service、adapter、image、modelIds;workspace 指定 volume、name、相同 image 和 engine。workspace 卷挂 `/workspace`,持久状态卷 `<name>-state` 挂 `/state`。Git/worktree 和 Agent 都在同样的容器路径执行,关闭容器不删除两个卷。Git 认证使用 workspace.environmentRefs,由宿主注入环境;不把密钥写进镜像。
27
+
28
+ Podman 不继承其远程服务的代理变量。代理通过 Agent/workspace 的 environmentRefs 显式授予,并使用容器能访问的地址,不能直接使用宿主回环代理。
29
+
30
+ 完整 API 示例见 [ACP 接入指南](../../../cli/templates/skills/hai-ai/acp.md)。
31
+
32
+ ## Goose 原生远程服务
33
+
34
+ Goose 使用 `goose serve --host 0.0.0.0 --port 3284`,在 `/acp` 同时提供 HTTP 和 WebSocket。镜像预启用 Developer 扩展;模型由 Goose 服务端通过 `GOOSE_PROVIDER`、`GOOSE_MODEL` 和供应商密钥变量维护,Hai 的 custom-service 不注入模型配置。OpenRouter 对应 `GOOSE_PROVIDER=openrouter` 和 `OPENROUTER_API_KEY`。服务凭据使用独立的 `GOOSE_SERVER__SECRET_KEY`,客户端用 `headerEnv` 注入 `X-Secret-Key`;不将密钥写在地址中。依据:[固定版本 ACP 文档](https://github.com/aaif-goose/goose/blob/v1.57.0/documentation/docs/gdk/acp/index.md)、[供应商配置](https://github.com/aaif-goose/goose/blob/v1.57.0/documentation/docs/getting-started/providers.md)。
35
+
36
+ 部署方启动容器,将工作区卷挂到 `/workspace`、状态卷挂到 `/state`,再登记 Hai 自定义服务。Hai 只管理 ACP 连接和原生会话;远程服务、卷、Git 与模型的生命周期由部署方管理。镜像当前只提供 linux/amd64;明确检查平台,不在其它架构上误装 x86 二进制。
37
+
38
+ `tests/ai-acp-goose.e2e.test.ts` 对真实 Goose 服务分别验证 HTTP/WS 鉴权、随机文件读写、原生工具调用;仅当握手声明恢复能力时验收恢复,否则验证显式不支持。设置 `HAI_ACP_E2E_GOOSE=1`、`HAI_ACP_E2E_GOOSE_IMAGE=hai-ai/goose:1.57.0` 和 `OPENROUTER_APIKEY` 启用;`HAI_ACP_E2E_GOOSE_MODEL` 可覆盖测试型号,默认沿用 `HAI_ACP_E2E_MODEL`,再回退 qwen/qwen3.7-flash。模型服务会发生真实调用,测试报告与截图沿用 `test-results/acp-openrouter`,不记录凭据。
39
+
40
+ ## 验证
41
+
42
+ AI 包的 `test:e2e` 包含原生 stdio/HTTP/WS、临时 Git remote 和容器卷测试。容器 E2E 用 `HAI_ACP_E2E_IMAGE` 指定已构建的镜像,`HAI_ACP_E2E_ENGINE` 可选 auto/podman/docker。未提供镜像时明确跳过容器测试,不能视为容器通过。`HAI_ACP_E2E_DSH_IMAGE` 开启真实 DeepSeek Harness 验收;native E2E 使用镜像内实际 Codex/dsh 和容器内测试模型 HTTP 服务,检查模型配置、认证、协议请求和返回文本。真实模型推理仍需部署方自己的模型端点,夹具推理不代表真实模型验收。
43
+
44
+ 连接真实 OpenRouter 的四组合(Codex/dsh × embedded/builtin-service)验收使用独立测试,核验实际工具读写与关闭后恢复,并保留脱敏 JSON 与截图。必须显式启用,普通开发与仅存在密钥时均不运行;操作步骤见 [真实模型验收](../../tests/ACP-OPENROUTER.md)。
45
+
46
+ ## 许可证
47
+
48
+ Apache-2.0
@@ -0,0 +1,66 @@
1
+ import { spawn } from 'node:child_process'
2
+ import { readFile } from 'node:fs/promises'
3
+ import process from 'node:process'
4
+ import { fileURLToPath } from 'node:url'
5
+
6
+ async function main() {
7
+ const names = ['codex-acp', 'deepseek-harness', 'goose']
8
+ const [name, ...options] = process.argv.slice(2)
9
+ if (!names.includes(name))
10
+ throw new Error(`Select agent: ${names.join(', ')}`)
11
+ const selected
12
+ = options.find(value => value.startsWith('--engine='))?.slice(9) ?? 'auto'
13
+ if (!['auto', 'podman', 'docker'].includes(selected))
14
+ throw new Error('Invalid container engine')
15
+ for (const option of options) {
16
+ if (!['--java', '--rust', '--go', `--engine=${selected}`].includes(option))
17
+ throw new Error(`Unknown option: ${option}`)
18
+ }
19
+ async function run(command, args) {
20
+ await new Promise((resolve, reject) => {
21
+ const child = spawn(command, args, {
22
+ shell: false,
23
+ windowsHide: true,
24
+ stdio: 'inherit',
25
+ })
26
+ child.on('error', reject)
27
+ child.on('close', code =>
28
+ code === 0 ? resolve() : reject(new Error('Container command failed')))
29
+ })
30
+ }
31
+ let engine
32
+ for (const candidate of selected === 'auto'
33
+ ? ['podman', 'docker']
34
+ : [selected]) {
35
+ try {
36
+ await run(candidate, ['info'])
37
+ engine = candidate
38
+ break
39
+ }
40
+ catch {
41
+ /* 未就绪时尝试下一引擎;明确选择的引擎不会降级。 */
42
+ }
43
+ }
44
+ if (!engine)
45
+ throw new Error('No ready Podman/Docker engine')
46
+ const directory = fileURLToPath(new URL(`./${name}/`, import.meta.url))
47
+ const manifest = JSON.parse(
48
+ await readFile(new URL(`./${name}/agent.json`, import.meta.url), 'utf8'),
49
+ )
50
+ await run(engine, [
51
+ 'build',
52
+ '--build-arg',
53
+ `WITH_JAVA=${options.includes('--java')}`,
54
+ '--build-arg',
55
+ `WITH_RUST=${options.includes('--rust')}`,
56
+ '--build-arg',
57
+ `WITH_GO=${options.includes('--go')}`,
58
+ '-t',
59
+ `${manifest.image}:${manifest.version}`,
60
+ directory,
61
+ ])
62
+ }
63
+ main().catch((error) => {
64
+ process.stderr.write(`${error.message}\n`)
65
+ process.exitCode = 1
66
+ })
@@ -0,0 +1,25 @@
1
+ FROM docker.io/library/node:24.22.1-bookworm-slim
2
+ ARG DEBIAN_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian
3
+ ARG DEBIAN_SECURITY_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian-security
4
+ ARG WITH_JAVA=false
5
+ ARG WITH_RUST=false
6
+ ARG WITH_GO=false
7
+ # 基础运行环境;可选语言在构建时选择,不在任务执行时临时安装。
8
+ # 使用 Node 自带的公开 CA 引导 HTTPS,随后安装系统 CA;不关闭证书校验。
9
+ RUN mkdir -p /etc/ssl/certs && node -e "require('node:fs').writeFileSync('/etc/ssl/certs/ca-certificates.crt', require('node:tls').rootCertificates.join('\\n'))"
10
+ RUN set -eu; packages="git python3 python3-venv python3-pip ca-certificates"; \
11
+ case "$WITH_JAVA" in true) packages="$packages default-jdk-headless";; false) ;; *) exit 2;; esac; \
12
+ case "$WITH_RUST" in true) packages="$packages rustc cargo";; false) ;; *) exit 2;; esac; \
13
+ case "$WITH_GO" in true) packages="$packages golang";; false) ;; *) exit 2;; esac; \
14
+ sed -i -e "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g" -e "s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources; \
15
+ apt-get -o Acquire::Retries=2 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 update; apt-get install -y --no-install-recommends $packages; \
16
+ rm -rf /var/lib/apt/lists/*; git --version; node --version; python3 --version
17
+ # ACP 适配器和原生 Codex CLI 都是镜像的明确组成部分,版本需匹配。
18
+ RUN npm install --global @agentclientprotocol/codex-acp@2.5.0 @openai/codex@0.165.0 \
19
+ && codex --version && codex-acp --version
20
+ RUN mkdir -p /workspace /state && chown node:node /workspace /state
21
+ USER node
22
+ ENV HOME=/state
23
+ WORKDIR /workspace
24
+ ENTRYPOINT ["codex-acp"]
25
+ CMD []
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "codex-acp",
3
+ "package": "@agentclientprotocol/codex-acp",
4
+ "version": "2.5.0",
5
+ "image": "hai-ai/codex-acp",
6
+ "transports": [
7
+ "stdio"
8
+ ],
9
+ "command": "codex-acp",
10
+ "args": [],
11
+ "runtime": {
12
+ "package": "@openai/codex",
13
+ "version": "0.165.0",
14
+ "command": "codex"
15
+ }
16
+ }
@@ -0,0 +1,23 @@
1
+ FROM docker.io/library/node:24.22.1-bookworm-slim
2
+ ARG DEBIAN_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian
3
+ ARG DEBIAN_SECURITY_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian-security
4
+ ARG WITH_JAVA=false
5
+ ARG WITH_RUST=false
6
+ ARG WITH_GO=false
7
+ # 基础运行环境;可选语言在构建时选择,不在任务执行时临时安装。
8
+ # 使用 Node 自带的公开 CA 引导 HTTPS,随后安装系统 CA;不关闭证书校验。
9
+ RUN mkdir -p /etc/ssl/certs && node -e "require('node:fs').writeFileSync('/etc/ssl/certs/ca-certificates.crt', require('node:tls').rootCertificates.join('\\n'))"
10
+ RUN set -eu; packages="git python3 python3-venv python3-pip ca-certificates"; \
11
+ case "$WITH_JAVA" in true) packages="$packages default-jdk-headless";; false) ;; *) exit 2;; esac; \
12
+ case "$WITH_RUST" in true) packages="$packages rustc cargo";; false) ;; *) exit 2;; esac; \
13
+ case "$WITH_GO" in true) packages="$packages golang";; false) ;; *) exit 2;; esac; \
14
+ sed -i -e "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g" -e "s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources; \
15
+ apt-get -o Acquire::Retries=2 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 update; apt-get install -y --no-install-recommends $packages; \
16
+ rm -rf /var/lib/apt/lists/*; git --version; node --version; python3 --version
17
+ RUN npm install --global @deepseek-ai/dsh@0.2.1-rc.5
18
+ RUN mkdir -p /workspace /state && chown node:node /workspace /state
19
+ USER node
20
+ ENV HOME=/state
21
+ WORKDIR /workspace
22
+ ENTRYPOINT ["dsh"]
23
+ CMD ["--profile", "acp"]
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "deepseek-harness",
3
+ "package": "@deepseek-ai/dsh",
4
+ "version": "0.2.1-rc.5",
5
+ "image": "hai-ai/deepseek-harness",
6
+ "transports": [
7
+ "stdio"
8
+ ],
9
+ "command": "dsh",
10
+ "args": [
11
+ "--profile",
12
+ "acp"
13
+ ]
14
+ }
@@ -0,0 +1,34 @@
1
+ FROM docker.io/library/node:24.22.1-bookworm-slim
2
+ ARG DEBIAN_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian
3
+ ARG DEBIAN_SECURITY_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/debian-security
4
+ ARG WITH_JAVA=false
5
+ ARG WITH_RUST=false
6
+ ARG WITH_GO=false
7
+ ARG GOOSE_DOWNLOAD_URL=https://github.com/aaif-goose/goose/releases/download/v1.57.0/goose-x86_64-unknown-linux-musl.tar.gz
8
+ # Git/Node/Python 为基础环境,Goose 使用固定版本及固定 SHA256 的官方 musl 二进制。
9
+ RUN mkdir -p /etc/ssl/certs && node -e "require('node:fs').writeFileSync('/etc/ssl/certs/ca-certificates.crt', require('node:tls').rootCertificates.join('\\n'))"
10
+ RUN set -eu; packages="git python3 python3-venv python3-pip ca-certificates curl musl"; \
11
+ case "$WITH_JAVA" in true) packages="$packages default-jdk-headless";; false) ;; *) exit 2;; esac; \
12
+ case "$WITH_RUST" in true) packages="$packages rustc cargo";; false) ;; *) exit 2;; esac; \
13
+ case "$WITH_GO" in true) packages="$packages golang";; false) ;; *) exit 2;; esac; \
14
+ sed -i -e "s|http://deb.debian.org/debian-security|${DEBIAN_SECURITY_MIRROR}|g" -e "s|http://deb.debian.org/debian|${DEBIAN_MIRROR}|g" /etc/apt/sources.list.d/debian.sources; \
15
+ apt-get -o Acquire::Retries=2 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 update; \
16
+ apt-get install -y --no-install-recommends $packages; rm -rf /var/lib/apt/lists/*; \
17
+ git --version; node --version; python3 --version
18
+ RUN test "$(uname -m)" = x86_64 && \
19
+ curl --fail --location --retry 2 --connect-timeout 30 --max-time 300 \
20
+ "${GOOSE_DOWNLOAD_URL}" \
21
+ --output /tmp/goose.tar.gz && \
22
+ echo '6c3a05e30e1a425dc06a410dbe24b3f3697c9721b1ea2340434ddda6b64267ae /tmp/goose.tar.gz' | sha256sum --check - && \
23
+ mkdir /tmp/goose-install && tar -xf /tmp/goose.tar.gz -C /tmp/goose-install && \
24
+ install -m 0755 /tmp/goose-install/goose /usr/local/bin/goose && \
25
+ rm -rf /tmp/goose.tar.gz /tmp/goose-install && goose --version
26
+ RUN mkdir -p /workspace /state/.config/goose && \
27
+ echo '{"extensions":{"developer":{"bundled":true,"enabled":true,"name":"developer","timeout":300,"type":"builtin"}}}' > /state/.config/goose/config.yaml && \
28
+ chown -R node:node /workspace /state
29
+ USER node
30
+ ENV HOME=/state
31
+ WORKDIR /workspace
32
+ EXPOSE 3284
33
+ ENTRYPOINT ["goose"]
34
+ CMD ["serve", "--host", "0.0.0.0", "--port", "3284"]
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "goose",
3
+ "version": "1.57.0",
4
+ "image": "hai-ai/goose",
5
+ "transports": ["http", "ws"],
6
+ "command": "goose",
7
+ "args": ["serve", "--host", "0.0.0.0", "--port", "3284"],
8
+ "source": "https://github.com/aaif-goose/goose/releases/tag/v1.57.0",
9
+ "artifact": {
10
+ "url": "https://github.com/aaif-goose/goose/releases/download/v1.57.0/goose-x86_64-unknown-linux-musl.tar.gz",
11
+ "sha256": "6c3a05e30e1a425dc06a410dbe24b3f3697c9721b1ea2340434ddda6b64267ae",
12
+ "platform": "linux/amd64"
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/ai",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.5",
4
+ "version": "1.0.0-beta.7",
5
5
  "description": "Hai Framework AI module (LLM, MCP, tools, and clients).",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -23,7 +23,8 @@
23
23
  "browser": "./dist/browser.js",
24
24
  "types": "./dist/index.d.ts",
25
25
  "files": [
26
- "dist"
26
+ "dist",
27
+ "models/agents"
27
28
  ],
28
29
  "publishConfig": {
29
30
  "access": "public"
@@ -41,11 +42,12 @@
41
42
  },
42
43
  "dependencies": {
43
44
  "@a2a-js/sdk": "^0.3.12",
44
- "@h-ai/api-contract": "1.0.0-beta.5",
45
- "@h-ai/core": "1.0.0-beta.5",
46
- "@h-ai/datapipe": "1.0.0-beta.5",
47
- "@h-ai/reldb": "1.0.0-beta.5",
48
- "@h-ai/vecdb": "1.0.0-beta.5",
45
+ "@agentclientprotocol/sdk": "2.2.0",
46
+ "@h-ai/api-contract": "1.0.0-beta.7",
47
+ "@h-ai/core": "1.0.0-beta.7",
48
+ "@h-ai/datapipe": "1.0.0-beta.7",
49
+ "@h-ai/reldb": "1.0.0-beta.7",
50
+ "@h-ai/vecdb": "1.0.0-beta.7",
49
51
  "@modelcontextprotocol/sdk": "^1.32.1",
50
52
  "mem0ai": "^3.3.1",
51
53
  "nanoid": "^6.0.2",
@@ -80,6 +82,8 @@
80
82
  "model:prepare": "node models/build.mjs prepare",
81
83
  "model:build": "node models/build.mjs build",
82
84
  "model:run": "node models/build.mjs run",
83
- "build:clean": "rimraf dist"
85
+ "build:clean": "rimraf dist",
86
+ "agent:build": "node models/agents/build.mjs",
87
+ "test:e2e": "vitest run tests/ai-acp.e2e.test.ts tests/ai-acp-transport.e2e.test.ts tests/ai-acp-container.e2e.test.ts tests/ai-acp-native.e2e.test.ts tests/ai-acp-openrouter.e2e.test.ts tests/ai-acp-goose.e2e.test.ts"
84
88
  }
85
89
  }