Files
PlantAI-rag-new/docs/EXTENSION_CONTRACT.md
adminandClaude Fable 5 d12071a4d7 feat(extension): 上传支持 zip/tar/目录三形态+结构自适应分类
- 前端零打包:归档文件(zip/tar/tar.gz/tgz)原样上传服务端解压;
  目录拖入/选择器走 webkitRelativePath 多文件直传(filename=相对路径),
  隐藏文件/__pycache__ 过滤 + 公共根剥离(参考 PlantAI-dev 主路径)
- 后端 _read_archive 魔数分派(zip/tar.gz/tar)+保留嵌套路径;
  code_files 多文件字段;结构自适应分类(目录前缀→命令解析→扩展名,
  未知归代码,纯数据 422 可读,纯脚本合法);store 嵌套落盘
- 存量 bug 修复:FormData 字段名 file→code_zip;golden File→JSON+test_file;
  http size hint 兼容 code_zip 与多文件求和
- 测试:后端 334/334(新增 10 个变体用例),前端 122/373 全绿

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-15 10:34:52 +08:00

6.8 KiB

扩展分析契约文档(Dev-A/B/C 与测试 agent 对齐基线)

生成 2026-09-12,方案见 docs/DEPLOY_SKILL.md 同源的扩展分析方案。三个开发分支与本契约对齐,测试 agent 按本契约+计划文档验收。

1. 扩展资产目录布局(服务端存储)

{BIOFLOW_DATA}/extensions/{ext_id}/
├── extension.json          # 唯一事实源(schema 见 §2)
├── raw_code/               # 上传 zip 解压的原始代码(含 run.sh 等)
├── raw_test_data/          # 上传的测试数据(可选)
├── converted_code/         # AI 转换后写入的代码(与 raw_code 相同或改写版)
├── validation/             # 试运行/金标/修复循环中间产物
│   ├── trial_{n}.log
│   ├── trial_{n}.outputs/
│   └── golden_report.json
└── runs/{run_id}/          # 每次正式运行
    ├── inputs/             # 运行输入(路径登记或复制的文件)
    ├── outputs/            # 运行输出(输出契约校验对象)
    ├── run.log
    └── run_result.json     # {run_id, ext_id, exit_code, started_at, finished_at, outputs: [...], error}

2. extension.json schema(唯一事实源)

{
  "schema_version": "extension_stage_v1",
  "ext_id": "ext_xxxxxxxx",
  "display_name": "测序质量统计",
  "status": "draft|building|built|trial_running|trial_passed|trial_failed|validating|validated|repairing|confirming|published|build_failed",
  "command_template": "python {code_dir}/quality_stats.py --fastq {input_file} --out {output_dir}",
  "original_command": "python quality_stats.py --fastq input.fastq --out results/",
  "runtime_image": "bioflow-gf",
  "requirements": { "pip": [], "apt": [] },
  "parameters": [ { "name": "fastq", "type": "file", "required": true, "description": "..." } ],
  "input_roles": { "input_file": "fastq" },
  "nl_triggers": ["质量统计", "fastq 统计"],
  "analysis_type": "table_filter",
  "golden": { "test_input": "sample.fastq", "expected_outputs": ["..."] } | null,
  "repair_count": 0,
  "created_at": "...", "updated_at": "..."
}

占位符白名单(spec_v2 移植):{code_dir} {input_dir} {input_file} {input_hmm} {input_fasta} {input_query_fasta} {input_reference_fasta} {input_pep_fasta} {input_cds_fasta} {input_id_file} {output_dir} {work_dir} + {param_<name>}。硬约束:{output_dir} 必含;白名单外占位符拒绝。

3. docker 执行契约(Dev-B 负责实现)

宿主挂载入口 bioflow_kernel/cli/run_extension.py,命令形态:

docker run --rm --user <uid> \
  -v <ext_dir>:/job/ext:ro \
  -v <input_dir>:/job/input \
  -v <output_dir>:/job/output \
  -v <宿主 bioflow_kernel/cli>:/opt/bioflow-entry:ro \
  --cpus <白名单> --memory <白名单> \
  <image>:dev python -B /opt/bioflow-entry/run_extension.py \
  --ext-dir /job/ext --input-dir /job/input --output-dir /job/output [--param name=value ...]

run_extension.py 职责:读 /job/ext/extension.json → 渲染 command_template(code_dir=/job/ext/converted_code)→ subprocess 执行 → 日志/退出码返回 → 输出契约校验(输出目录非空,否则退出码 3)。8 个 base 镜像与自动生成镜像零改动。

4. 事件帧契约(chat/stream 扩展分支下发,Dev-C 消费)

帧 = {event, data},事件集:

event data 关键字段 触发
extension_upload {session_ext_id} 创建意图命中 → 上传引导卡
extension_created {ext_id, display_name, status:"draft"} 上传完成
extension_build {ext_id, command_template, requirements, runtime_image, nl_triggers, analysis_type, parameters, status} AI 转换完成 → 转换卡
extension_trial {ext_id, status:"running"|"done"|"failed", log_tail, exit_code, error} 试运行状态/结果
extension_repair {ext_id, repair_count, suggestion, status} 修复循环
extension_validate {ext_id, golden: {...}|null, form_defaults} 金标/确认卡
extension_published {ext_id, display_name, nl_triggers} 发布完成
extension_candidates {candidates: [{ext_id, display_name, purpose}]} 多命中候选卡
extension_confirm {ext_id, params_schema, extracted_params, files_required} 运行前参数确认卡
extension_run_started {run_id, ext_id} 运行开始
extension_run_log {run_id, log} 运行日志追加
extension_run_done {run_id, outputs} 运行完成
extension_run_failed {run_id, exit_code, error, log_tail} 运行失败

5. 意图两层判定(Dev-A 负责,intent.py 扩展)

  • A 层创建:动作词{创建,建,新建,上传,自定义,写,弄,做一个} × 目标词{扩展,拓展分析,分析模板,分析脚本,分析工具},同句命中即进创建流程。
  • B 层运行:已发布扩展打分 = display_name 模糊 + nl_triggers 关键词 + analysis_type;动作词{帮我跑,用,做一下,分析一下}加分。仅 published 可被触发。
  • 歧义消解:目标词命中但无动作词 → 有 B 层命中走运行;无命中回「没有匹配的已发布扩展,是否创建?」引导卡。
  • 漏判安全:无命中且非创建 → 回落正常生信阶段规划,现网零影响。

6. 端点清单(Dev-A 实现,Dev-C 调用)

POST   /api/bioflow/extensions                      (multipart: code_zip 归档[zip/tar/tar.gz,服务端魔数解压] 或 code_files 多文件[目录直传,filename=相对路径] + display_name + command + runtime_image? + golden?[JSON 字符串] + test_file?[金标数据文件])
                                                    上传内容结构自适应分类:raw_code|code|scripts → 代码;raw_test_data|test_data|data → 数据;
                                                    散落文件按运行命令解析入口 + 扩展名模式分类,未知扩展名归代码;纯数据包 422,纯脚本包合法
GET    /api/bioflow/extensions                      (列表,published 优先)
GET    /api/bioflow/extensions/{id}
DELETE /api/bioflow/extensions/{id}
POST   /api/bioflow/extensions/{id}/build           (AI 转换)
POST   /api/bioflow/extensions/{id}/trial-run       (test_inputs 文件)
POST   /api/bioflow/extensions/{id}/repair          (LLM 修复,上限 20 轮可配)
POST   /api/bioflow/extensions/{id}/publish
POST   /api/bioflow/extensions/{id}/run             (params + files → run_id)
GET    /api/bioflow/extensions/{id}/runs
GET    /api/bioflow/extensions/{id}/runs/{run_id}/events   (SSE,首帧快照)

7. 约束(全部 agent)

  • 代码仅限 175 仓库 /home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new(worktree 副本)。
  • 不 push、不部署 176、不动生产部署树;dev 栈不得重启生产服务。
  • 依赖安装:服务端零新增依赖(纯 stdlib+现有 httpx/pydantic/fastapi);镜像内依赖走自动镜像生成(Dev-B)。
  • 现有 bioflow 路径零改动:kernel.py/runner.py/planner.py/catalog.py/stage_image_map.json 一律不碰(扩展是并行链路)。