本文档描述一个典型的 Skill 执行请求在系统内部的流转过程。
串行多 skill 工作流可以在后续 POST /v1/jobs 请求中提交 runtime_options.workspace.mode="reuse" 和前序成功请求的 request_id。后续请求保留独立 logical run_id,但复用前序请求的物理 workspace。Runner-owned 文件写入 run record 暴露的 resultJsonPath 与 inputManifestPath,调用方不应拼接 result/result.json。
客户端可以通过 runtime_options.env 为单次 run 注入局部环境变量。API 创建请求时会先校验 env,再将 raw value 写入 data/run_secrets/<request_id>.env.json,普通 request record 与 input manifest 只保存 redacted 投影。执行 attempt 准备阶段从 vault 重新加载 raw env,作为内部 __runtime_env 传给 adapter;adapter 只把它叠加到当前 subprocess env,不修改全局 os.environ。
客户端可以通过 runtime_options.preamble_prompt 为单次 run 注入受治理的前置上下文。API 创建请求时会校验并规范化该文本,将 raw value 写入 data/run_secrets/<request_id>.preamble.json,普通 request record 与 input manifest 只保存包含 sha256 和 length 的 redacted descriptor。
执行 attempt 准备阶段只会在首次初始 attempt 恢复 raw preamble,并作为内部 __preamble_prompt 交给 common prompt builder。该内容被包裹在固定边界中,插入到 skill invoke line 之后、skill body prompt 之前;retry、interactive reply、auth resume 与 output repair 不会重复注入。
- Client -> API: 发送
POST /v1/jobs创建请求。- Payload: 包含
skill_id和parameterJSON (仅配置值)。
- Payload: 包含
- WorkspaceManager:
- 创建
data/requests/<request_id>/目录。 - 返回
request_id。 - 在临时 skill 或需要上传的请求中,此时可能尚未绑定
run_id。客户端可以立即读取GET /v1/jobs/{request_id},响应为queued且observability_ready=false;/events/history与/chat/history返回空历史,实时 SSE 只返回 pre-observable keepalive。
- 创建
- Client -> API: (可选) 发送
POST /v1/jobs/<request_id>/upload上传文件。- Payload: Zip 文件。
- WorkspaceManager:
- 解压 Zip 到
data/requests/<request_id>/uploads/。 - 生成
input_manifest.json并计算 cache key。 - 缓存仅在
execution_mode=auto且no_cache!=true时启用;interactive不读不写缓存。 - cache key 统一包含 skill id、engine、规范化
skill_package_hash、参数、engine options、上传文件清单哈希、inline input 哈希和 preamble hash。 runtime_options.env不进入 cache key;若 env 会影响输出,调用方需设置no_cache=true。runtime_options.preamble_prompt的规范化内容 hash 进入 cache key;相同输入但不同 preamble 会 cache miss。- 已安装 skill 与临时上传 skill 使用同一套
skill_package_hash口径;临时上传包会缓存未 patch 的规范化 snapshot,默认 30 天滑动 TTL。 - 命中缓存则将缓存的 run 绑定到
request_id;未命中则创建data/runs/<run_id>/。
- 解压 Zip 到
- Client -> API: 上传完成即触发执行(服务端自动触发)。
- JobOrchestrator:
get_skill(skill_id): 获取技能清单。- Engine Gate:
engine必须包含在skill.engines中(由 WorkspaceManager 兜底拦截)。
- Schema Splitting:
- 识别
runner.json中的input(文件) 和parameter(数值) Schema。
- 识别
- Validation:
- 验证传入的
parameterJSON 是否符合parameterSchema。 - 检查
uploads/目录下的文件是否符合inputSchema 的要求 (存在性检查)。
- 验证传入的
Selected Adapter (Gemini/Codex/IFlow/OpenCode) 接管控制权:
- 环境准备:
- 将技能的
assets/和SKILL.md复制/安装到运行目录.<engine>/skills/下(如.gemini/.codex/.qwen/.opencode),确保执行环境隔离。 - 若 request 声明了
runtime_options.env,从 secret vault 加载 raw env;vault 缺失时 run 失败并返回RUNTIME_ENV_SECRET_MISSING。
- 将技能的
- 输入解析 (Input Resolution):
- 遍历
inputSchema 的所有键。 - 声明式 file path 解析: 若请求体
input.<key>为 file 字段提供了uploads/相对路径,则优先按该路径解析。 - 兼容回退: 若请求体未显式提供 file 路径,再回退到旧的 strict key-matching(检查
uploads/<key>是否存在)。 - 若最终未命中: 对 required file 字段抛出缺文件错误。
- 遍历
- 上下文构建 (Context Building):
input_ctx: 包含解析后的文件绝对路径。param_ctx: 包含纯数值参数。
- Prompt 生成 (Adapter Dependent):
- Gemini: 加载 Jinja2 模板,注入上下文,渲染为
prompt.txt。 - Codex: 融合
engine_default -> skill default -> runtime -> enforced,再构造 CLI 参数。 - Gemini / Qwen / OpenCode: 在运行目录写入项目级配置,统一遵循
engine_default -> skill default -> runtime -> enforced合成顺序。 - OpenCode 特例: 额外按执行模式写入
permission.question(auto=deny,interactive=allow)。
- Gemini: 加载 Jinja2 模板,注入上下文,渲染为
- Command Construction:
- Gemini:
gemini --yolo <prompt> - Codex:
codex exec --full-auto --skip-git-repo-check --json -p skill-runner <prompt>(不支持 landlock 时回退--yolo) - OpenCode:
opencode run --format json --model <provider/model> <prompt> - 设置工作目录为
data/runs/<uuid>/。 - 如果存在 run-local env,dependency probe、uv wrapper 与最终 adapter subprocess 使用同一份叠加后的 env。
注意: 以上命令行示例为简化展示。实际 CLI 参数由各引擎的
adapter_profile.json中command_defaults驱动,并由引擎CommandBuilder动态构建。 - Gemini:
- Run Folder Trust 生命周期(Codex/Gemini):
- 在真正调用 CLI 前,服务会将本次
run_dir写入全局 trust 配置。- Codex:
~/.codex/config.toml->projects."<run_dir>".trust_level = "trusted" - Gemini:
~/.gemini/trustedFolders.json->"<run_dir>": "TRUST_FOLDER"
- Codex:
- CLI 执行结束后(无论成功/失败),在
finally路径删除该run_dirtrust 记录。 - trust 回收失败只记录 warning,不会覆盖本次 run 的最终状态。
- 在真正调用 CLI 前,服务会将本次
- Subprocess:
- 启动异步子进程。
- 实时流式读取
stdout和stderr并写入logs/目录。
- Completion:
- 等待进程结束。
- 解析最终输出 (JSON)。
- 更新 Run 状态为
succeeded/failed。 - 生成 bundle(debug/非 debug)。
- 定时清理任务会在清理历史 run 的同时,扫描活动 run 列表并执行 stale trust 清理。
- 仅清理
runs根目录下、且不在活动集合(queued/running)中的 Codex/Gemini trust 条目。 - 定时清理也会移除超过滑动 TTL 的临时 skill 包缓存 snapshot;TTL 内再次使用同一规范化包 hash 会刷新过期时间。