{"_id":"@airalogy/airalogy-engine","_rev":"5-7f15551a37185862a3833f616e6ec8cd","name":"@airalogy/airalogy-engine","dist-tags":{"latest":"0.0.5"},"versions":{"0.0.1":{"name":"@airalogy/airalogy-engine","version":"0.0.1","keywords":["airalogy","protocol","sandbox"],"author":{"name":"Airalogy Team"},"license":"Apache-2.0","_id":"@airalogy/airalogy-engine@0.0.1","maintainers":[{"name":"yangzijie","email":"yangzijie@westlake.edu.cn"}],"dist":{"shasum":"e50751c69647998a2b55f5cc91ca2ff8d17bfec7","tarball":"https://registry.npmjs.org/@airalogy/airalogy-engine/-/airalogy-engine-0.0.1.tgz","fileCount":7,"integrity":"sha512-AF7Rk7MZ1DXUqp3sRx6XzW4jM1cls+2BbMLZx5pE5Z1gDNjZTY5cG2dtFzAPXCVPeHgs5RBRSJndN1XvW1oySg==","signatures":[{"sig":"MEYCIQDOtHyTEkFTnbXMO79JFTAhkcJ6LMBKzgPDrCCf2YvBGwIhAKL5Y7h9yG2u08MHUavjrhtPlLlIjQbgVmQxRkUc3ulr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44325},"main":"dist/index.js","type":"module","_from":"file:airalogy-airalogy-engine-0.0.1.tgz","types":"dist/index.d.ts","scripts":{"lint":"oxlint --ignore-path=.gitignore","test":"vitest run --pool=threads --maxWorkers=1 --no-file-parallelism","build":"pnpm run copy-executor && tsc","lint:fix":"oxlint --fix --ignore-path=.gitignore","type-check":"tsc --noEmit","copy-executor":"cp ../python/src/airalogy_engine/protocol_executor.py ./protocol_executor.py"},"_npmUser":{"name":"yangzijie","email":"yangzijie@westlake.edu.cn"},"_resolved":"/private/var/folders/wd/4mh5q2yn5rsd3mnz9pkk5lr40000gn/T/e43b2234399591126130588613f9326f/airalogy-airalogy-engine-0.0.1.tgz","_integrity":"sha512-AF7Rk7MZ1DXUqp3sRx6XzW4jM1cls+2BbMLZx5pE5Z1gDNjZTY5cG2dtFzAPXCVPeHgs5RBRSJndN1XvW1oySg==","_npmVersion":"10.8.2","description":"Airalogy protocol execute sandbox","directories":{},"_nodeVersion":"20.19.6","dependencies":{"@boxlite-ai/boxlite":"0.8.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","oxfmt":"^0.43.0","oxlint":"^1.58.0","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","oxlint-tsgolint":"^0.19.0"},"_npmOperationalInternal":{"tmp":"tmp/airalogy-engine_0.0.1_1778743633081_0.6268604115933978","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@airalogy/airalogy-engine","version":"0.0.2","keywords":["airalogy","protocol","sandbox"],"author":{"name":"Airalogy Team"},"license":"Apache-2.0","_id":"@airalogy/airalogy-engine@0.0.2","maintainers":[{"name":"yangzijie","email":"yangzijie@westlake.edu.cn"}],"homepage":"https://airalogy.github.io/airalogy/airalogy-engine/","bugs":{"url":"https://github.com/airalogy/airalogy/issues"},"dist":{"shasum":"564eb9a1efef8d19996f8ce91372076e0d13d92e","tarball":"https://registry.npmjs.org/@airalogy/airalogy-engine/-/airalogy-engine-0.0.2.tgz","fileCount":9,"integrity":"sha512-ly4IOA9LKb8BgBtX/NDj9Odhs0DpnmLb2JvmrYSeoM26VCl3RN5NYZWGbvxtu2MH7op6c5ZFZPvfHXg/JdXHOw==","signatures":[{"sig":"MEUCIH2O4PrN44D663Mid6hhLPsifbbiRd7BzEMRxFu0rtRRAiEAiHhxSc9yrO6BFlcPGfchsgfxhFgTK+qTHtAW4/vf128=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airalogy%2fairalogy-engine@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":76522},"main":"dist/index.js","type":"module","_from":"file:airalogy-airalogy-engine-0.0.2.tgz","types":"dist/index.d.ts","scripts":{"lint":"oxlint --ignore-path=.gitignore","test":"vitest run --config vitest.config.ts --pool=threads --maxWorkers=1 --no-file-parallelism","build":"pnpm run copy-executor && tsc","lint:fix":"oxlint --fix --ignore-path=.gitignore","type-check":"tsc --noEmit","copy-executor":"cp ../../pypi/airalogy-engine/src/airalogy_engine/protocol_executor.py ./protocol_executor.py"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:49a680d1-64c3-43fd-943c-5a434f04a06b"}},"_resolved":"/tmp/91f391749e75b849543995897ec0fcba/airalogy-airalogy-engine-0.0.2.tgz","_integrity":"sha512-ly4IOA9LKb8BgBtX/NDj9Odhs0DpnmLb2JvmrYSeoM26VCl3RN5NYZWGbvxtu2MH7op6c5ZFZPvfHXg/JdXHOw==","repository":{"url":"git+https://github.com/airalogy/airalogy.git","type":"git","directory":"packages/npm/airalogy-engine"},"_npmVersion":"11.13.0","description":"Airalogy protocol execute sandbox","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@boxlite-ai/boxlite":"0.8.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","oxfmt":"^0.43.0","oxlint":"^1.58.0","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","oxlint-tsgolint":"^0.19.0"},"_npmOperationalInternal":{"tmp":"tmp/airalogy-engine_0.0.2_1780064998304_0.055547976154946","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@airalogy/airalogy-engine","version":"0.0.3","keywords":["airalogy","protocol","sandbox"],"author":{"name":"Airalogy Team"},"license":"Apache-2.0","_id":"@airalogy/airalogy-engine@0.0.3","maintainers":[{"name":"yangzijie","email":"yangzijie@westlake.edu.cn"}],"homepage":"https://airalogy.github.io/airalogy/airalogy-engine/","bugs":{"url":"https://github.com/airalogy/airalogy/issues"},"dist":{"shasum":"8e904b43ed8419b68b317201c330dca6a9cf577e","tarball":"https://registry.npmjs.org/@airalogy/airalogy-engine/-/airalogy-engine-0.0.3.tgz","fileCount":10,"integrity":"sha512-JfT0T+HScVUoqItQ2pZC+cEIVWE1uppuR/FI/5RRJ99Go+3Kf8rnZRHkITa6stn8VZudR7AXZi3n17A6a4Td+w==","signatures":[{"sig":"MEQCIFgGLHxyYRZLcK5s4vsFRIJHbattoW7uP/375qm8u2vlAiAAza+mhkCERvRiYQo7brk20ylYr1cOUNLFJm/mAGBV7A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airalogy%2fairalogy-engine@0.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":183036},"main":"dist/index.js","type":"module","_from":"file:airalogy-airalogy-engine-0.0.3.tgz","types":"dist/index.d.ts","scripts":{"lint":"oxlint --ignore-path=.gitignore","test":"vitest run --config vitest.config.ts --pool=threads --maxWorkers=1 --no-file-parallelism","build":"pnpm run copy-executor && tsc","lint:fix":"oxlint --fix --ignore-path=.gitignore","type-check":"tsc --noEmit","copy-executor":"cp ../../pypi/airalogy-engine/src/airalogy_engine/protocol_executor.py ./protocol_executor.py && cp ../../pypi/airalogy-engine/src/airalogy_engine/workflow_executor.py ./workflow_executor.py"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:49a680d1-64c3-43fd-943c-5a434f04a06b"}},"_resolved":"/tmp/d17d83296ec3f1c4cf5046609a2d444a/airalogy-airalogy-engine-0.0.3.tgz","_integrity":"sha512-JfT0T+HScVUoqItQ2pZC+cEIVWE1uppuR/FI/5RRJ99Go+3Kf8rnZRHkITa6stn8VZudR7AXZi3n17A6a4Td+w==","repository":{"url":"git+https://github.com/airalogy/airalogy.git","type":"git","directory":"packages/npm/airalogy-engine"},"_npmVersion":"11.13.0","description":"Airalogy protocol execute sandbox","directories":{},"_nodeVersion":"24.17.0","dependencies":{"yaml":"^2.4.2","@boxlite-ai/boxlite":"0.8.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","oxfmt":"^0.43.0","oxlint":"^1.58.0","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","oxlint-tsgolint":"^0.19.0"},"_npmOperationalInternal":{"tmp":"tmp/airalogy-engine_0.0.3_1782911103221_0.6767039268276147","host":"s3://npm-registry-packages-npm-production"}},"0.0.4":{"name":"@airalogy/airalogy-engine","version":"0.0.4","keywords":["airalogy","protocol","sandbox"],"author":{"name":"Airalogy Team"},"license":"Apache-2.0","_id":"@airalogy/airalogy-engine@0.0.4","maintainers":[{"name":"yangzijie","email":"yangzijie2026@gmail.com"}],"homepage":"https://airalogy.github.io/airalogy/airalogy-engine/","bugs":{"url":"https://github.com/airalogy/airalogy/issues"},"dist":{"shasum":"6592fb88b8ae10b6eb109864ac1700c33bf03f31","tarball":"https://registry.npmjs.org/@airalogy/airalogy-engine/-/airalogy-engine-0.0.4.tgz","fileCount":10,"integrity":"sha512-sHYO6kMVI1oNGpGfESZFQljIF5/seU7uOIgdsnrQ4BvDhg8e3viOCyaJv1+Jjv9GTckHBqnq8Vd7+gNKR00SwA==","signatures":[{"sig":"MEUCIQDUIYHSA3it8XeJBT0zX4B8tdYTd4NAEJCKKQZOS/AH2QIgXxKta86W5+BtazAbQ1Jx0NA4M68lnRjydNVHPeo579k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airalogy%2fairalogy-engine@0.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":187050},"main":"dist/index.js","type":"module","_from":"file:airalogy-airalogy-engine-0.0.4.tgz","types":"dist/index.d.ts","scripts":{"lint":"oxlint --ignore-path=.gitignore","test":"vitest run --config vitest.config.ts --pool=threads --maxWorkers=1 --no-file-parallelism","build":"pnpm run copy-executor && tsc","lint:fix":"oxlint --fix --ignore-path=.gitignore","type-check":"tsc --noEmit","copy-executor":"cp ../../pypi/airalogy-engine/src/airalogy_engine/protocol_executor.py ./protocol_executor.py && cp ../../pypi/airalogy-engine/src/airalogy_engine/workflow_executor.py ./workflow_executor.py"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:49a680d1-64c3-43fd-943c-5a434f04a06b"}},"_resolved":"/tmp/c9f231fcb35ead4a84d915b332e58055/airalogy-airalogy-engine-0.0.4.tgz","_integrity":"sha512-sHYO6kMVI1oNGpGfESZFQljIF5/seU7uOIgdsnrQ4BvDhg8e3viOCyaJv1+Jjv9GTckHBqnq8Vd7+gNKR00SwA==","repository":{"url":"git+https://github.com/airalogy/airalogy.git","type":"git","directory":"packages/npm/airalogy-engine"},"_npmVersion":"11.16.0","description":"Airalogy protocol execute sandbox","directories":{},"_nodeVersion":"24.18.0","dependencies":{"yaml":"^2.4.2","@boxlite-ai/boxlite":"0.8.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","oxfmt":"^0.43.0","oxlint":"^1.58.0","vitest":"^4.1.2","typescript":"^6.0.2","@types/node":"^25.5.0","oxlint-tsgolint":"^0.19.0"},"_npmOperationalInternal":{"tmp":"tmp/airalogy-engine_0.0.4_1784797941269_0.4983244709622956","host":"s3://npm-registry-packages-npm-production"}},"0.0.5":{"name":"@airalogy/airalogy-engine","version":"0.0.5","description":"Airalogy protocol execute sandbox","type":"module","repository":{"type":"git","url":"git+https://github.com/airalogy/airalogy.git","directory":"packages/npm/airalogy-engine"},"bugs":{"url":"https://github.com/airalogy/airalogy/issues"},"homepage":"https://airalogy.github.io/airalogy/airalogy-engine/","main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"keywords":["airalogy","protocol","sandbox"],"author":{"name":"Airalogy Team"},"license":"Apache-2.0","devDependencies":{"@types/node":"^25.5.0","oxfmt":"^0.43.0","oxlint":"^1.58.0","oxlint-tsgolint":"^0.19.0","tsx":"^4.21.0","typescript":"^6.0.2","vitest":"^4.1.2"},"dependencies":{"@boxlite-ai/boxlite":"0.8.2","yaml":"^2.4.2"},"scripts":{"build":"pnpm run copy-executor && tsc","lint":"oxlint --ignore-path=.gitignore","lint:fix":"oxlint --fix --ignore-path=.gitignore","type-check":"tsc --noEmit","copy-executor":"cp ../../pypi/airalogy-engine/src/airalogy_engine/protocol_executor.py ./protocol_executor.py && cp ../../pypi/airalogy-engine/src/airalogy_engine/workflow_executor.py ./workflow_executor.py","test":"vitest run --config vitest.config.ts --pool=threads --maxWorkers=1 --no-file-parallelism"},"_id":"@airalogy/airalogy-engine@0.0.5","_integrity":"sha512-PHmmFd2TDPSxQZcvCBOYnVnzz8cGlC/r1VFN1T8tcIA0i4R+D+e93BHX09t65EHKYl5zVXNdKnZeLIWXeNKIow==","_resolved":"/tmp/cd106a5ab1f3c69a9bcd4e482c880ab4/airalogy-airalogy-engine-0.0.5.tgz","_from":"file:airalogy-airalogy-engine-0.0.5.tgz","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-PHmmFd2TDPSxQZcvCBOYnVnzz8cGlC/r1VFN1T8tcIA0i4R+D+e93BHX09t65EHKYl5zVXNdKnZeLIWXeNKIow==","shasum":"8499fc1abd98c21b73571ded3062430a949fd9c2","tarball":"https://registry.npmjs.org/@airalogy/airalogy-engine/-/airalogy-engine-0.0.5.tgz","fileCount":10,"unpackedSize":187178,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airalogy%2fairalogy-engine@0.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDZQAnbnvo3rkNAILuutoHvoCKzLUvkRyggpJcPpLQbuQIgeI8PMlDsIP39mcVQvOjVOmLUqGBp2Kbra9K5Q6OFnG8="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:49a680d1-64c3-43fd-943c-5a434f04a06b"}},"directories":{},"maintainers":[{"name":"yangzijie","email":"yangzijie2026@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/airalogy-engine_0.0.5_1786705148873_0.05803722079186424"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-14T07:27:12.915Z","modified":"2026-08-14T10:59:09.930Z","0.0.1":"2026-05-14T07:27:13.216Z","0.0.2":"2026-05-29T14:29:58.477Z","0.0.3":"2026-07-01T13:05:03.356Z","0.0.4":"2026-07-23T09:12:21.403Z","0.0.5":"2026-08-14T10:59:09.014Z"},"bugs":{"url":"https://github.com/airalogy/airalogy/issues"},"author":{"name":"Airalogy Team"},"license":"Apache-2.0","homepage":"https://airalogy.github.io/airalogy/airalogy-engine/","keywords":["airalogy","protocol","sandbox"],"repository":{"type":"git","url":"git+https://github.com/airalogy/airalogy.git","directory":"packages/npm/airalogy-engine"},"description":"Airalogy protocol execute sandbox","maintainers":[{"name":"yangzijie","email":"yangzijie2026@gmail.com"}],"readme":"# airalogy-engine (Node.js)\n\n[![npm version](https://img.shields.io/npm/v/%40airalogy%2Fairalogy-engine?label=npm)](https://www.npmjs.com/package/@airalogy/airalogy-engine)\n\n英文 README：[README.md](README.md)\n\nAiralogy 协议执行 sandbox 的 Node.js/TypeScript 包。它在安全的 [BoxLite](https://github.com/boxlite-ai/boxlite) sandbox 中运行协议包的 `parse`、`assign` 和 `validate` 操作，也可以执行 AIMD Workflow 中跨 Protocol Record 的 transition assignment。\n\n## 设计逻辑\n\nAiralogy Engine 把协议运行时拆成四层：Docker/BuildKit 负责构建 sandbox 环境，OCI image layout 把这个环境保存成标准、可迁移的 artifact，BoxLite 挂载这个 artifact 并隔离执行协议代码，Engine API 则向宿主应用暴露稳定的 `image`、`rootfsPath` 和 file bridge 抽象。\n\n这种设计避免依赖宿主机 Python 环境，也避免在本地 rootfs 构建完成后仍要求正常协议执行必须访问 Docker daemon。它还让运行边界保持清晰：未来无论是 CI 构建、托管服务，还是替换底层 sandbox runtime，都可以复用同一个 OCI artifact 和 Engine 层 API，而不需要改协议包或 recorder 集成。\n\n## 安装\n\n```bash\npnpm add @airalogy/airalogy-engine\n```\n\n## Sandbox 镜像\n\nEngine 会在 BoxLite sandbox 中运行协议代码。可以使用远程 Docker 镜像，也可以使用本地 OCI rootfs 目录。\n\n### 远程镜像\n\n```typescript\nconst result = await parseProtocol(protocolPath, undefined, {\n  image: \"ghcr.io/airalogy/airalogy-engine:0.16.0\",\n});\n```\n\n### 本地 OCI Rootfs（推荐）\n\n在 monorepo 中，可以把 sandbox 镜像构建并导出到本地，以获得更快、可离线的执行：\n\n```bash\npnpm build:engine-rootfs\n```\n\n构建本地 rootfs 需要 Docker daemon 处于运行状态。在 macOS 上，请从“应用程序”启动 Docker Desktop，或运行 `open -a Docker`，然后等待 `docker info` 成功后再执行 `pnpm build:engine-rootfs` 或 `pnpm build:engine-rootfs:force`。如果使用 Colima、Rancher Desktop 或其他 Docker 兼容运行时，请先启动对应运行时，并确保 Docker context 指向它。\n\n构建脚本需要导出 OCI layout，因此会自动创建并使用 `docker-container` driver 的 Buildx builder。Docker 默认的 `docker` driver 不能导出 `type=oci`。如果需要使用不同的 builder 名称，可以传入 `--builder <name>`，或设置 `AIRALOGY_ENGINE_BUILDX_BUILDER`。\n\n#### 什么是 OCI rootfs？\n\nOCI 是 Open Container Initiative 的缩写。这里的 \"OCI rootfs\" 指 OCI image layout 目录，也就是 Open Container Initiative 定义的容器镜像本地目录格式；它不是传统的 Linux 根文件系统解包目录，也不是 Docker 专有格式。有效目录应包含 `oci-layout`、`index.json` 和 `blobs/sha256/...`；BoxLite 会把这个镜像布局挂载为 sandbox 文件系统。如果目录存在但没有 `oci-layout`，说明构建不完整，请运行 `pnpm build:engine-rootfs:force` 重新构建。\n\n然后传入 `rootfsPath`：\n\n```typescript\nconst result = await parseProtocol(protocolPath, undefined, {\n  rootfsPath: \"packages/runtime/airalogy-engine-image/airalogy-engine-image\",\n});\n```\n\n> 如果没有提供 `image` 或 `rootfsPath`，engine 会回退到官方的版本化多架构镜像 `ghcr.io/airalogy/airalogy-engine:0.16.0`。\n\n## 使用\n\n```typescript\nimport { parseProtocol, assignVariable, runWorkflow, validateVariables } from \"@airalogy/airalogy-engine\";\n\nconst protocolPath = \"/path/to/your/protocol\";\nconst options = { rootfsPath: \"/path/to/airalogy-engine-image\" }; // 或 { image: \"...\" }\n\nconst parseResult = await parseProtocol(protocolPath, { API_KEY: \"xxx\" }, options);\nconsole.log(parseResult.data?.meta_data);\nconsole.log(parseResult.data?.json_schema);\n\nconst assignResult = await assignVariable(\n  protocolPath,\n  \"duration\",\n  { seconds: 3600 },\n  { API_KEY: \"xxx\" },\n  options,\n);\nconsole.log(assignResult.data);\n\nconst validateResult = await validateVariables(\n  protocolPath,\n  { seconds: 60, duration: \"PT1M\" },\n  { API_KEY: \"xxx\" },\n  options,\n);\nconsole.log(validateResult.data);\n\nconst workflowResult = await runWorkflow(\n  \"/path/to/workflow.aimd\",\n  {\n    measurement: { data: { var: { raw_data: [1, 2, 3] } } },\n    literature_review: { data: { var: { summary: \"prior context\" } } },\n  },\n  options,\n);\nconsole.log(workflowResult.data?.workflow_data?.path_data.steps);\nconsole.log(workflowResult.data?.records); // 当前 Record 快照。\n```\n\n## Workflow Runtime\n\n`runWorkflow` 和 `runWorkflowTransition` 会执行 `workflow.aimd` 中 fenced `workflow` block 定义的 transition。运行时会解析 `transition.inputs`，在 BoxLite sandbox 中调用 Workflow 级 Python assigner，把返回值暴露为 `${transition_id.outputs.key}`，再按 `transition.assign` 写入目标 Protocol 的 Record draft。Workflow 运行的主产物是 `workflow_data.path_data.steps` 这条 Path step 时间线；`records` 是本次运行派生出的当前 Record 快照。它不会持久化 Record，也不会创建 Record version；调用方应把返回的 Record draft 保存到自己的平台或数据库层。\n\nWorkflow 引用保留 `${...}`，是为了区分“引用”和“常量字符串”。例如 `var.summary: ${prepare_analysis_inputs.outputs.summary}` 表示复制 transition 输出，而 `var.summary: prepare_analysis_inputs.outputs.summary` 表示写入这个普通字符串。\n\n对于可信的本地 demo 或测试，可以传入 `assignerRuntime: \"local\"`，让 Workflow 级 Python assigner 在宿主机 Python 进程中运行，而不是进入 BoxLite。对不可信 workflow 包和生产服务，仍应保留默认的 `assignerRuntime: \"sandbox\"`。\n\n## API\n\n### `parseProtocol(protocolPath, envVars?, options?)`\n\n解析协议并返回 schema、metadata 和字段信息。\n\n### `assignVariable(protocolPath, varName, dependentData, envVars?, options?)`\n\n调用协议中的 assigner 函数为变量赋值。\n\n### `validateVariables(protocolPath, vars, envVars?, options?)`\n\n根据协议模型校验变量值。\n\n### `runWorkflow(workflowPath, records, envVars?, options?)`\n\n按声明顺序执行选中的 Workflow transitions。`workflowPath` 可以是 `workflow.aimd` 文件，也可以是包含 `workflow.aimd` 的目录。返回的 data 包含 `workflow_data.path_data.steps`、`records`、`transition_outputs`、`executed_transitions`、`skipped_transitions`、`attempts` 和 `node_iterations`。\n\n### `runWorkflowTransition(workflowPath, transitionId, records, envVars?, options?)`\n\n执行单个 Workflow transition，并返回更新后的 Record drafts 与 transition metadata。\n\n### `parseWorkflowContent(content)` 和 `isAimdWorkflowReference(value)`\n\n解析单个 Workflow YAML payload，并判断一个值是否是 `${node.section.field}` 形式的 Workflow 引用表达式。\n\n所有函数都返回 `Promise<ProtocolResult>`：\n\n```typescript\ninterface ProtocolResult {\n  success: boolean;\n  message?: string;\n  data?: Record<string, unknown>;\n  output?: string;\n  files?: SandboxFileBridgeOutput[];\n}\n```\n\n### Sandbox Options\n\n所有函数都接受 `SandboxOptions` 对象：\n\n| 参数 | 类型 | 默认值 | 说明 |\n|---|---|---|---|\n| `image` | `string` | `\"ghcr.io/airalogy/airalogy-engine:0.16.0\"` | 远程 Docker 镜像名 |\n| `rootfsPath` | `string` | - | 本地 OCI rootfs 目录路径，会覆盖 `image` |\n| `timeout` | `number` | `300` | 执行超时时间，单位秒 |\n| `memoryMib` | `number` | `512` | 内存限制，单位 MiB |\n| `cpus` | `number` | `1` | CPU 限制 |\n| `debug` | `boolean` | `false` | 启用 sandbox 内 executor 调试日志 |\n| `logFile` | `string` | `\"protocol_debug.log\"` | 追加 sandbox 调试日志的宿主机文件 |\n\n### Workflow Options\n\n`runWorkflow` 接受所有 sandbox options，并额外支持 `workflowId`、`transitionIds`、`transitionOutputs`、`nodeIterations`、`maxPasses` 和 `assignerRuntime`。`runWorkflowTransition` 接受所有 sandbox options，并额外支持 `workflowId`、`transitionOutputs`、`nodeIterations` 和 `assignerRuntime`。\n\n## 开发\n\n```bash\ncd packages/npm/airalogy-engine\n\npnpm install\npnpm run build\npnpm run type-check\npnpm run lint\npnpm test\n```\n\n### 测试\n\n测试使用 [vitest](https://vitest.dev/)，并通过环境变量支持不同 sandbox 模式：\n\n```bash\n# 默认：远程 Docker 镜像模式\npnpm test\n\n# 使用本地 OCI rootfs\nSANDBOX_MODE=rootfs ROOTFS_PATH=../../runtime/airalogy-engine-image/airalogy-engine-image pnpm test\n\n# 使用自定义远程镜像\nSANDBOX_IMAGE=ghcr.io/airalogy/airalogy-engine:0.16.0 pnpm test\n```\n","readmeFilename":"README.zh-CN.md"}