From fbfc3e30fb9aa1c58218266bbe5ded938caef472 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:40:31 +0800 Subject: [PATCH] update unilabos_formulation & batch-submit-exp --- .../skills/batch-submit-experiment/SKILL.md | 54 +++++++++++++------ .../scripts/gen_notebook_params.py | 1 + .cursor/skills/create-device-skill/SKILL.md | 41 +++++++++++++- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/.cursor/skills/batch-submit-experiment/SKILL.md b/.cursor/skills/batch-submit-experiment/SKILL.md index 76e1ab1c..de6fed5e 100644 --- a/.cursor/skills/batch-submit-experiment/SKILL.md +++ b/.cursor/skills/batch-submit-experiment/SKILL.md @@ -1,6 +1,6 @@ --- name: batch-submit-experiment -description: Batch submit experiments (notebooks) to Uni-Lab platform — list workflows, generate node_params from registry schemas, submit multiple rounds. Use when the user wants to submit experiments, create notebooks, batch run workflows, or mentions 提交实验/批量实验/notebook/实验轮次. +description: Batch submit experiments (notebooks) to Uni-Lab platform — list workflows, generate node_params from registry schemas, submit multiple rounds, check notebook status. Use when the user wants to submit experiments, create notebooks, batch run workflows, check experiment status, or mentions 提交实验/批量实验/notebook/实验轮次/实验状态. --- # 批量提交实验指南 @@ -59,7 +59,7 @@ AUTH="Authorization: Lab <上面命令输出的 token>" ### 4. workflow_uuid(目标工作流) -用户需要提供要提交的 workflow UUID。如果用户不确定,通过 API #2 列出可用 workflow 供选择。 +用户需要提供要提交的 workflow UUID。如果用户不确定,通过 API #3 列出可用 workflow 供选择。 **四项全部就绪后才可开始。** @@ -68,8 +68,9 @@ AUTH="Authorization: Lab <上面命令输出的 token>" 在整个对话过程中,agent 需要记住以下状态,避免重复询问用户: - `lab_uuid` — 实验室 UUID(首次通过 API #1 自动获取,**不需要问用户**) +- `project_uuid` — 项目 UUID(通过 API #2 列出项目列表,**让用户选择**) - `workflow_uuid` — 工作流 UUID(用户提供或从列表选择) -- `workflow_nodes` — workflow 中各 action 节点的 uuid、设备 ID、动作名(从 API #3 获取) +- `workflow_nodes` — workflow 中各 action 节点的 uuid、设备 ID、动作名(从 API #4 获取) ## 请求约定 @@ -97,7 +98,17 @@ curl -s -X GET "$BASE/api/v1/edge/lab/info" -H "$AUTH" 记住 `data.uuid` 为 `lab_uuid`。 -### 2. 列出可用 workflow +### 2. 列出实验室项目(让用户选择项目) + +```bash +curl -s -X GET "$BASE/api/v1/lab/project/list?lab_uuid=$lab_uuid" -H "$AUTH" +``` + +返回项目列表,展示给用户选择。列出每个项目的 `uuid` 和 `name`。 + +用户**必须**选择一个项目,记住 `project_uuid`,后续创建 notebook 时需要提供。 + +### 3. 列出可用 workflow ```bash curl -s -X GET "$BASE/api/v1/lab/workflow/workflows?page=1&page_size=20&lab_uuid=$lab_uuid" -H "$AUTH" @@ -105,7 +116,7 @@ curl -s -X GET "$BASE/api/v1/lab/workflow/workflows?page=1&page_size=20&lab_uuid 返回 workflow 列表,展示给用户选择。列出每个 workflow 的 `uuid` 和 `name`。 -### 3. 获取 workflow 模板详情 +### 4. 获取 workflow 模板详情 ```bash curl -s -X GET "$BASE/api/v1/lab/workflow/template/detail/$workflow_uuid" -H "$AUTH" @@ -119,7 +130,7 @@ curl -s -X GET "$BASE/api/v1/lab/workflow/template/detail/$workflow_uuid" -H "$A > **注意**:此 API 返回格式可能因版本不同而有差异。首次调用时,先打印完整响应分析结构,再提取节点信息。常见的节点字段路径为 `data.nodes[]` 或 `data.workflow_nodes[]`。 -### 4. 提交实验(创建 notebook) +### 5. 提交实验(创建 notebook) ```bash curl -s -X POST "$BASE/api/v1/lab/notebook" \ @@ -132,6 +143,7 @@ curl -s -X POST "$BASE/api/v1/lab/notebook" \ ```json { "lab_uuid": "", + "project_uuid": "", "workflow_uuid": "", "name": "<实验名称>", "node_params": [ @@ -159,6 +171,16 @@ curl -s -X POST "$BASE/api/v1/lab/notebook" \ > **注意**:`sample_uuids` 必须是 **UUID 数组**(`[]uuid.UUID`),不是字符串。无样品时传空数组 `[]`。 +### 6. 查询 notebook 状态 + +提交成功后,使用返回的 notebook UUID 查询执行状态: + +```bash +curl -s -X GET "$BASE/api/v1/lab/notebook/status?uuid=$notebook_uuid" -H "$AUTH" +``` + +提交后应**立即查询一次**状态,确认 notebook 已被正确接收并开始调度。 + --- ## Notebook 请求体详解 @@ -181,7 +203,7 @@ curl -s -X POST "$BASE/api/v1/lab/notebook" \ | 字段 | 类型 | 说明 | |------|------|------| -| `node_uuid` | string | workflow 模板中的节点 UUID(从 API #3 获取) | +| `node_uuid` | string | workflow 模板中的节点 UUID(从 API #4 获取) | | `param` | object | 动作参数(根据本地注册表 schema 填写) | | `sample_params` | array | 样品相关参数(液体名、体积等) | @@ -222,7 +244,7 @@ python scripts/gen_notebook_params.py \ 如果脚本不可用或注册表不存在: -1. 调用 API #3 获取 workflow 详情 +1. 调用 API #4 获取 workflow 详情 2. 找到每个 action 节点的 `node_uuid` 3. 在本地注册表中查找对应设备的 `action_value_mappings`: ``` @@ -275,13 +297,15 @@ Task Progress: - [ ] Step 1: 确认 ak/sk → 生成 AUTH token - [ ] Step 2: 确认 --addr → 设置 BASE URL - [ ] Step 3: GET /edge/lab/info → 获取 lab_uuid -- [ ] Step 4: 确认 workflow_uuid(用户提供或从 GET #2 列表选择) -- [ ] Step 5: GET workflow detail (#3) → 提取各节点 uuid、设备ID、动作名 -- [ ] Step 6: 定位本地注册表 req_device_registry_upload.json -- [ ] Step 7: 运行 gen_notebook_params.py 或手动匹配 → 生成 node_params 模板 -- [ ] Step 8: 引导用户填写每轮的参数(sample_uuids、param、sample_params) -- [ ] Step 9: 构建完整请求体 → POST /lab/notebook 提交 -- [ ] Step 10: 检查返回结果,确认提交成功 +- [ ] Step 4: GET /lab/project/list → 列出项目,让用户选择 → 获取 project_uuid +- [ ] Step 5: 确认 workflow_uuid(用户提供或从 GET #3 列表选择) +- [ ] Step 6: GET workflow detail (#4) → 提取各节点 uuid、设备ID、动作名 +- [ ] Step 7: 定位本地注册表 req_device_registry_upload.json +- [ ] Step 8: 运行 gen_notebook_params.py 或手动匹配 → 生成 node_params 模板 +- [ ] Step 9: 引导用户填写每轮的参数(sample_uuids、param、sample_params) +- [ ] Step 10: 构建完整请求体(含 project_uuid)→ POST /lab/notebook 提交 +- [ ] Step 11: 检查返回结果,记录 notebook UUID +- [ ] Step 12: GET /lab/notebook/status → 查询 notebook 状态,确认已调度 ``` --- diff --git a/.cursor/skills/batch-submit-experiment/scripts/gen_notebook_params.py b/.cursor/skills/batch-submit-experiment/scripts/gen_notebook_params.py index 4b984851..f22b37e8 100644 --- a/.cursor/skills/batch-submit-experiment/scripts/gen_notebook_params.py +++ b/.cursor/skills/batch-submit-experiment/scripts/gen_notebook_params.py @@ -265,6 +265,7 @@ def generate_template(nodes, registry_index, rounds): return { "lab_uuid": "$TODO_LAB_UUID", + "project_uuid": "$TODO_PROJECT_UUID", "workflow_uuid": "$TODO_WORKFLOW_UUID", "name": "$TODO_EXPERIMENT_NAME", "node_params": node_params, diff --git a/.cursor/skills/create-device-skill/SKILL.md b/.cursor/skills/create-device-skill/SKILL.md index 6ce54450..20cd2f33 100644 --- a/.cursor/skills/create-device-skill/SKILL.md +++ b/.cursor/skills/create-device-skill/SKILL.md @@ -158,6 +158,7 @@ python ./scripts/extract_device_actions.py [--registry ] ./ski - `unilabos_devices` → **DeviceSlot**,填入路径字符串如 `"/host_node"`(从资源树筛选 type=device) - `unilabos_nodes` → **NodeSlot**,填入路径字符串如 `"/PRCXI/PRCXI_Deck"`(资源树中任意节点) - `unilabos_class` → **ClassSlot**,填入类名字符串如 `"container"`(从注册表查找) + - `unilabos_formulation` → **FormulationSlot**,填入配方数组 `[{well_name, liquids: [{name, volume}]}]`(well_name 为目标物料的 name) - array 类型字段 → `[{id, name, uuid}, ...]` - 特殊:`create_resource` 的 `res_id`(ResourceSlot)可填不存在的路径 @@ -211,6 +212,7 @@ API 模板结构: - unilabos_devices → DeviceSlot → "/parent/device" 路径字符串 - unilabos_nodes → NodeSlot → "/parent/node" 路径字符串 - unilabos_class → ClassSlot → "class_name" 字符串 +- unilabos_formulation → FormulationSlot → [{well_name, liquids: [{name, volume}]}] 配方数组 - 特例:create_resource 的 res_id 允许填不存在的路径 - 列出本设备所有 Slot 字段、类型及含义 @@ -222,7 +224,7 @@ API 模板结构: 检查文件完整性: - [ ] `SKILL.md` 包含 API endpoint(#1 获取 lab_uuid、#2-#7 工作流/节点/边、#8-#11 运行/查询、#12 资源树、#13 工作流模板详情) -- [ ] `SKILL.md` 包含 Placeholder Slot 填写规则(ResourceSlot / DeviceSlot / NodeSlot / ClassSlot + create_resource 特例)和本设备的 Slot 字段表 +- [ ] `SKILL.md` 包含 Placeholder Slot 填写规则(ResourceSlot / DeviceSlot / NodeSlot / ClassSlot / FormulationSlot + create_resource 特例)和本设备的 Slot 字段表 - [ ] `action-index.md` 列出所有 action 并有描述 - [ ] `actions/` 目录中每个 action 有对应 JSON 文件 - [ ] JSON 文件包含 `type`, `schema`(已提升为 goal 内容), `goal`, `goal_default`, `placeholder_keys` 字段 @@ -268,7 +270,7 @@ API 模板结构: ## Placeholder Slot 类型体系 -`placeholder_keys` / `_unilabos_placeholder_info` 中有 4 种值,对应不同的填写方式: +`placeholder_keys` / `_unilabos_placeholder_info` 中有 5 种值,对应不同的填写方式: | placeholder 值 | Slot 类型 | 填写格式 | 选取范围 | |---------------|-----------|---------|---------| @@ -276,6 +278,7 @@ API 模板结构: | `unilabos_devices` | DeviceSlot | `"/parent/device_name"` | 仅**设备**节点(type=device),路径字符串 | | `unilabos_nodes` | NodeSlot | `"/parent/node_name"` | **设备 + 物料**,即所有节点,路径字符串 | | `unilabos_class` | ClassSlot | `"class_name"` | 注册表中已上报的资源类 name | +| `unilabos_formulation` | FormulationSlot | `[{well_name, liquids: [{name, volume}]}]` | 资源树中物料节点的 **name**,配合液体配方 | ### ResourceSlot(`unilabos_resources`) @@ -322,6 +325,40 @@ API 模板结构: "container" ``` +### FormulationSlot(`unilabos_formulation`) + +描述**液体配方**:向哪些物料容器中加入哪些液体及体积。填写为**对象数组**: + +```json +[ + { + "sample_uuid": "", + "well_name": "YB_PrepBottle_15mL_Carrier_bottle_A1", + "liquids": [ + { "name": "LiPF6", "volume": 0.6 }, + { "name": "DMC", "volume": 1.2 } + ] + } +] +``` + +#### 字段说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `sample_uuid` | string | 样品 UUID,无样品时传空字符串 `""` | +| `well_name` | string | 目标物料容器的 **name**(从资源树中取物料节点的 `name` 字段,如瓶子、孔位名称) | +| `liquids` | array | 要加入的液体列表 | +| `liquids[].name` | string | 液体名称(如试剂名、溶剂名) | +| `liquids[].volume` | number | 液体体积(单位由设备决定,通常为 mL) | + +#### 填写规则 + +- `well_name` 必须是资源树中已存在的物料节点 `name`(不是 `id` 路径),通过 API #12 获取资源树后筛选 +- 每个数组元素代表一个目标容器的配方 +- 一个容器可以加入多种液体(`liquids` 数组多条记录) +- 与 ResourceSlot 的区别:ResourceSlot 填 `{id, name, uuid}` 指向物料本身;FormulationSlot 用 `well_name` 引用物料,并附带液体配方信息 + ### 通过 API #12 获取资源树 ```bash