- 前端零打包:归档文件(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>
6.8 KiB
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 一律不碰(扩展是并行链路)。