Files
skill-template/development/SKILL_ACTION_RUNTIME.md
chendelian d911bd28cd
All checks were successful
技能自动化发布 / release (push) Successful in 6s
Release v1.0.127: document executionProfile stream for HTML token streaming
2026-10-25 18:22:25 +08:00

228 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Skill Action Runtime(宿主任务中心契约)
本文是匠厂宿主 **Skill Action / 任务中心** 的技能侧金标准。涉及浏览器 RPA、长耗时任务、数据管理按钮、定时任务、页内流式或 Agent 直接调用时**必读**。
**产品入口(平级关系、何时挂哪个)**先读 [`PRODUCT_SURFACES.md`](PRODUCT_SURFACES.md);本文管 sync/async/stream、任务中心与编排。
**边界:**
| 文档 | 职责 |
|------|------|
| 本文 | sync/async/stream、任务中心、Agent 禁令、单内核编排、队列 pick、同步 vs 导出 |
| [`../references/ACTIONS.md`](../references/ACTIONS.md) | `actions.json` 字段、placements、`bind.tables`、`bind.selectionMode`、`bind.visibleWhen`(行菜单显隐)、**用户可见文案**、inputSchema、跨表 Lookup(含分页勾选 `presentation: paged_table`)、字段条件显隐 `visibleWhen`、本地路径 `file`/`directory` + 可选 **`pathRoot`**、选择摘要「已选择」与映射 **`readOnly` / `revealInForm`**、**按钮中文名 `label` 参考** |
| [`LOGGING.md`](LOGGING.md) | `job_context` / `emit` / `finish` / Run Journal |
| [`DATA_PATHS.md`](DATA_PATHS.md) | 下载/导入等落盘路径 |
宿主实现细节以匠厂 Host API 为准;技能侧只需保证 manifest 与 CLI 契约稳定。
---
## 1. 核心原则
1. **宿主管调度,技能管业务** — 不自行实现任务中心 / Job 轮询 / 后台守护进程。
2. **单业务内核、多入口** — 数据管理、定时任务、Agent、技能详情与直接 CLI 复用同一 domain service;禁止按入口复制业务逻辑。
3. **五职责正交** — `placements` / `bind.tables` / `executionProfile` / `entrypoint` / domain service 各管一事(见 ACTIONS.md)。可选第六轴 **policy**(见 `references/POLICY.md`):未启用 = L0 与今日一致。可选 **`hostEffects` / `steps`**(见 ACTIONS.md):数据管理交互前后的 UI/级联编排;省略 = 不额外改 UI(匠厂宿主 ≥2.8.5)。可选 **`hoverHint`**(见 ACTIONS.md):数据管理工具栏悬停;省略 = 不显示,不回退说明或确认黄条。可选 **表单 `visibleWhen`**(见 ACTIONS.md):Action 参数表单字段条件显隐;省略 = 字段始终平铺;**勿与** **`bind.visibleWhen`**(行菜单)或 Policy L3 混淆;**勿**用其藏映射主键。可选 **`pathRoot`**(见 ACTIONS.md):`file`/`directory` 原生选路对话框起始目录(相对技能数据根;省略默认 `{skill_data}/input`)。可选 **`bind.labelColumn`**(见 ACTIONS.md):选择摘要可读标签列;省略 = 宿主常见列名启发。可选 **`bind.selectionMode`**(见 ACTIONS.md):表勾选如何驱动 Action(`required` / `none` / `optional`);省略 = 宿主按 `$selection.ids` / `batch` 推断;**定时任务等无表勾选入口按无勾选分支**(隐藏 `$selection.ids`,保留 `pickCount`)。可选 **`bind.visibleWhen`**(见 ACTIONS.md「行菜单显隐」):`row` 菜单按当前行列值显隐;省略 = 始终显示。可选 **`revealInForm`**(见 ACTIONS.md):有「已选择」时仍强制显示某 `readOnly` 字段;省略 = 映射只读默认不占 form 参数区(仍提交)。可选 **`cellPresentation`**(见 `references/CELL_PRESENTATION.md`):单元格/整行/整列/区域语义标色;省略 = P0。**用户可见文案**(见 ACTIONS.md「用户可见文案」):弹窗 `description` / 确认黄条 / 参数说明 / 任务失败 `message` 须全中文产品用语;Agent 路由勿塞进弹窗。
4. **长耗时建议 async;页内生成建议 stream** — 开浏览器、RPA、HTTP 大文件下载等建议 `executionProfile: "async"`,进**任务中心**;HTML 内 LLM/长生成要边出边看时用 `"stream"`(静默 Job)。这是对**方法**的选择,**不**限制可以出现在哪些 placement / 入口。
5. **Agent:短 CLI / 长 Action** — 短查询可用共享 Python bash CLI;长任务 / RPA **禁止** `exec` + `process poll`,必须 `run_skill_action`。
6. **进度走 Journal** — `emit` / `video.add_step` → Run Journal(任务中心 / Run Card);`stream` 的增量走 Journal `stream_delta`(经 `stream_channel`),由 HTML `jiangchang.stream` 消费;**不要**靠 stdout 假流式。
7. **显式声明 `executionProfile`** — 心智默认 sync;例外才 `async` 或 `stream`;每个 action **必须**写明三者之一;宿主省略时按 sync,新技能仍禁止赌缺省;禁止模糊别名(`auto` / `background` / `deferred` 等)。
---
## 2. `executionProfile`:sync / async / stream
### 心智(先记住)
1. **默认按 sync 想**:多数 Action(诊断、统计、入队、秒级查询)是短调用,当场返回,**不进**任务中心。
2. **要任务中心进度·取消时标 async**:开浏览器 / RPA / 长下载等,显式 `"executionProfile": "async"`。
3. **要页内 token 流式时标 stream**:数据管理 HTML 问答 / 长文生成,显式 `"stream"`;**不**进任务中心主路径(角标不因 stream 涨)。
4. **匠厂宿主**:`actions.json` 若**省略** `executionProfile`,按 **`sync`** 处理。
5. **新技能仍须显式写出** `sync` / `async` / `stream`(模板 Schema / `POLICY-SKILL-ACTION-002` 硬门禁),禁止赌宿主缺省。
| 值 | 宿主行为 | 超时 | 任务中心 |
|----|----------|------|----------|
| **`sync`**(或省略时的宿主缺省) | 调用方等待 CLI 结束,直接返回结构化结果或结构化错误;**不**创建后台 Job | 默认约 **60s**(`SKILL_ACTION_SYNC_TIMEOUT_MS`) | ❌ 不进 |
| **`async`**(须显式声明) | 后台 spawn Job,立即返回 `jobId`;`emit` / `checkpoint` / `finish`;长任务应支持暂停/停止/取消检查 | Job 本身无默认墙钟上限 | ✅ 进入 |
| **`stream`**(须显式声明) | 建 Job + 页内桥接;技能 `stream_channel` → `stream_delta`;HTML `jiangchang.stream`;终态 `finish` / 结构化 JSON | 宿主对流式会话有墙钟上限(以宿主为准) | ❌ 不进(静默) |
直接执行 CLI:终端等待进程结束。宿主经 Action 调用同一 CLI:再按 `executionProfile` 分流。技能不得自建任务中心。
### 选择建议(不是 placement 硬限制)
| 场景 | 建议 |
|------|------|
| 浏览器 / Playwright / RPA 主路径 | `async` + 建议 `confirmation` |
| 单次可能接近或超过约 60s 的网络/下载/同步 | `async` |
| HTML 页内 LLM / 长生成,要边生成边显示 | `stream`(需宿主 + kit≥1.2.14;见 ACTIONS.md「页面调用」) |
| `health` / `version` / `config-path` / 纯统计 / 秒级查询 | `sync` |
| 任意 placement(含 toolbar) | 允许 sync / async / stream;以 manifest 为准 |
合法:`sync|async|stream` × `toolbar|row|batch|cron|agent|skill-detail`。
### stream 技能侧要点(最小)
1. `actions.json` 目标 Action 写 `"executionProfile": "stream"`(常见 `placements`:`skill-detail` + `agent`)。
2. CLI 中:`from jiangchang_skill_core.activity import stream_channel`,在生成循环里 `ch.delta(text)`;结束仍输出完整结果 JSON(供页面定稿与 Agent)。
3. HTML:`await jiangchang.stream(actionId, params, { onDelta, onEvent })`;缺 API 时提示升级宿主。
4. 将本技能 `platform_kit_min_version` 调到 **≥1.2.14**(模板默认仍可为更低;**用 stream 的技能必须自提**)。
5. 用户可见失败文案用中文;勿把 Job cancelled / Process exited 之类英文直接甩给页面(宿主侧会继续收敛,技能侧先保证自己的 `message`)。
形状参考:[`../assets/examples/stream-ask.action.example.json`](../assets/examples/stream-ask.action.example.json)。
历史说明:旧文档曾错误地把数据管理按钮入口与异步执行方式绑死。该约束**已废止**;模板测试与 Schema **不得**再建立「入口位置决定 sync/async/stream」一类硬耦合。旧版宿主曾「省略 → async」;**当前宿主为「省略 → sync」**。新技能仍须显式声明,不得依赖省略行为。
---
## 3. 多入口如何感知 sync / async / stream
多个入口统一走 `POST /api/skill-actions/run`,可能带 `source.kind`:
| 入口(匠厂侧栏 / 界面) | 常见 `source.kind` | 技能侧 | 开发者怎么测 |
|-------------------------|-------------------|--------|--------------|
| **新建任务**(对话 Agent) | `agent` | `placements` 含 `agent`;`run_skill_action` | 侧栏「新建任务」→ 对话触发 |
| **数据管理 · 顶栏** | `data-management` | `toolbar` + 必填 `bind.tables` | 侧栏「数据管理」→ 表顶栏按钮 |
| **数据管理 · 行级** | `data-management` | `row`(建议 `bind.tables` + `inputMapping`) | 操作列和/或**行右键**(及可选「⋯」)可见并触发(需主键);技能配什么就显示什么 |
| **数据管理 · 批量** | `data-management` | `batch` | 勾选行后点批量按钮 |
| **定时任务** | `cron` | `placements` 含 `cron` | 侧栏「定时任务」→「技能直调」 |
| **任务中心** | (各入口触发的 Job) | `executionProfile: "async"` | 侧栏「任务中心」查看进度 / 取消;**不是** placement;`stream` Job **不**出现在此 |
| **技能详情 / HTML 预览** | `skill-detail` | `placements` 含 `skill-detail`;流式页用 `jiangchang.stream` | 市场详情安装/四 Tab;数据管理打开壳子页;详情直调按钮随宿主上线后**同等自测** |
技能 **不要** 在 Python 里按 `source` / placement 写业务分叉;宿主读 manifest 分流展示与等待策略。
**已声明的入口都要自测**,不要只测对话。操作清单见 [`DEVELOPMENT.md`](DEVELOPMENT.md) §15 第七步。
---
## 4. Action 分类与 placements(示例,不是限制)
下表只表示常见组合示例。**placements 以 manifest 为准;sync/async/stream 不影响展示入口。**
| Action 类型 | 常见 `executionProfile` | 常见 placements | `confirmation` |
|-------------|-------------------------|-----------------|----------------|
| 运行检查 / 版本 / 配置路径 | `sync` | `skill-detail`, `agent` | 无 |
| 库 / 队列统计 | `sync` | `skill-detail`, `agent` | 无 |
| HTML 页内问答 / 长生成 | `stream` | `skill-detail`, `agent` | 通常无 |
| 外源 → 本地库同步 | `sync` 或 `async` | 可含 `toolbar`(须 `bind.tables`)、`cron`、`agent`、`skill-detail` | 可选 |
| 单行 / 批量数据管理动作 | `sync` 或 `async` | `row` / `batch`(建议 `bind.tables`;行内常用 `inputMapping`) | 可选 |
| 数据导入 / 失败重置 | `sync` 或 `async` | `skill-detail`, `agent` | 可选 |
| **单条**副作用 RPA | `async`(建议) | `agent`, `skill-detail` | **建议** |
| **批量顺序** RPA(pick) | `async`(建议) | `toolbar`, `cron`, `agent` | **建议** |
禁忌:
- 高副作用 action 不要默认只挂 `toolbar`(应有 confirmation)。
- 含 `sensitive` 参数的 action 不要挂 `toolbar` / `cron`(除非有明确安全设计)。
- 不要为了「按钮多」暴露所有 CLI 子命令。
- 不要按入口复制多套采集 / 同步 / 处理实现。
---
## 5. 技能内编排范式(单内核 + 多入口)
推荐分层:
```text
scripts/cli/app.py # 参数解析 → 调用 task / service
scripts/service/task_service.py # job_context / emit / checkpoint / finish / 错误转换
scripts/service/<domain>_service.py # 唯一业务内核
scripts/db/*_repository.py # 只负责读写与事务
assets/actions.json # 声明入口、参数、placement、executionProfile、bind
```
长任务 / RPA 常见拆分(勿把 `job_context` 塞进纯业务内核):
```text
execute_single_<biz>(...) # 纯业务:鉴权 + 核心逻辑 + task_log;不含 job_context
cmd_run(...) # 单条:job_context + execute_single + finish
cmd_run_pick(N, ...) # 批量:job_context + for-loop execute_single + emit(progress) + finish
cmd_stats() # 只读 sync:JSON stdout,无 job_context
```
要点:
1. **`job_context` 只包编排层**(`cmd_run` / `cmd_run_pick`),不包 `execute_single_*` / domain service。
2. 批量 **顺序、不并发**;数量由参数 `pickCount` / `--pick N` 传入。
3. pick 循环内:`checkpoint()` + `emit("正在处理 {i}/{total}", progress={...})`。
4. 结束:全成功 `finish(success)`;部分失败 `finish(partial)`;全失败 `finish(failed)`。
5. 同一浏览器 Profile / account lease:**禁止并发**。
6. 兼容旧命令(例如旧 export 需先刷新)必须调用同一 sync / domain 内核,禁止重写采集逻辑。
详见 [`LOGGING.md`](LOGGING.md) §2.5 与 `scripts/service/task_service.py` 示范。可复用契约样例见 `tests/samples/test_action_core_contract.py.sample`、`tests/samples/test_sync_contract.py.sample`。
---
## 6. 队列 + pick(可选,Type B 批量)
有「待处理列表」的技能建议:
| 能力 | 约定 |
|------|------|
| 队列表 | `status`: `pending` → `processing` → `success` / `failed` |
| 入库 | 数据管理 CRUD,或 `import-*`(相对 `{skill_data}/input/`,见 [`DATA_PATHS.md`](DATA_PATHS.md)) |
| 消费 | `run --pick N`,默认仅 `pending` |
| 重试 | `reset` 或数据管理改 `pending`;**failed 不要自动重试** |
| 批次 | 可选 `batch_id`,便于筛选与任务中心对照 |
| Manifest | `*-run-pick`:建议 `async`,`placements` 按需含 `toolbar` / `cron` / `agent`;有 toolbar 则 `bind.tables` 必填 |
批量有两种合理形态(都是**顺序**):
| 形态 | 任务中心条数 | 适用 |
|------|-------------|------|
| 一次 `run-pick` 处理 N 条 | **1** 条 Job | 同类 RPA、同 Profile、定时消费队列 |
| Agent/UI 触发 N 次单条 `run` | **N** 条 Job | 每条独立追踪 / 独立重试 |
默认优先 **一次 pick、一条 Job**。
---
## 7. 业务同步与系统导出
| 能力 | 方向 | 负责方 |
|------|------|--------|
| 同步 / refresh / collect | 外部来源 → 技能本地 SQLite | 技能 domain service |
| 导出当前数据表 | 本地库 → CSV/Excel | **宿主**数据管理统一导出 |
| 特殊业务报告(文件) | 多表合并 / 特殊格式 → `output/` | 仅系统导出不足时提供 `export-*` |
| HTML 页面报告 | 壳子页 `assets/html/pages/*.html`;快照写入 `{skill_data}/html/*.html` | 壳子装完即现;快照由技能生成,重新生成 Action id 固定为 **`render-html`**。页面用 `jiangchang.call` 调已声明命令 |
同步 Action 默认写库、不写导出文件。HTML 报告契约见 [`../references/ACTIONS.md`](../references/ACTIONS.md)「HTML 页面报告」与 [`DATA_PATHS.md`](DATA_PATHS.md)。通用幂等 / 事务 / 空结果保护见 [`../references/SCHEMA.md`](../references/SCHEMA.md)。
---
## 8. Agent / SKILL.md 契约(复制后必改)
业务技能 `SKILL.md` / `references/` 应明确(Agent 主读,勿只写在本文):
1. 短查询:共享 Python(PATH 上的 `python`)跑 CLI;**禁止** `uv run`。
2. 长任务 / RPA / async Action:必须通过宿主 **Skill Action**(`run_skill_action`);**禁止** `exec` + `process poll`。
3. 单条 vs 批量 action id 与参数(如 `url` / `pickCount`)。
4. `executionProfile: async` → 进度看**任务中心** / Skill Run Card;`sync` → 当场结果;`stream` → 页内 `jiangchang.stream`(不进任务中心)。与入口无关。
5. 多入口复用同一业务内核。
模板源仓库的 `SKILL.md` / `references/ACTIONS.md` 含占位段落;scaffold 后按业务改写。
---
## 9. Policy
自动检测索引见 [`POLICY_MATRIX.md`](POLICY_MATRIX.md):
- **POLICY-SKILL-ACTION-001**:Runtime 文档存在;schema 含 `executionProfile`;有 RPA 的业务技能须声明 async agent action。
- **POLICY-SKILL-ACTION-002**:每个 Action 显式声明 `executionProfile`(sync/async/stream)。
- **POLICY-SKILL-ACTION-003**:toolbar Action 必须声明合法 `bind.tables`。
- **POLICY-SKILL-ACTION-004**:placements 与 executionProfile 正交(文档/测试不得写死耦合;Schema 接受 6×3 组合)。
- **POLICY-ARCH-CORE-001** / **POLICY-DATA-SYNC-001**:见矩阵;完整语义多用 sample / code review。
---
## 10. 与宿主 API(参考)
| API | 用途 |
|-----|------|
| `GET /api/skill-actions/{skillSlug}` | 读 manifest |
| `POST /api/skill-actions/run` | 执行 action(sync inline / async job) |
| `GET /api/skill-actions/jobs` | 任务中心列表 |
| `GET /api/skill-actions/jobs/{jobId}` | 单 Job 详情 / 事件 |
Agent 工具(插件):`list_skill_actions` → `get_skill_action` → `run_skill_action`;正常对话**不要**轮询 `get_skill_action_job`(交给 UI / 任务中心)。
表级 `bind.tables` 过滤依赖宿主支持;旧宿主忽略绑定时,toolbar Action 可能在技能全部数据表显示——新技能仍须显式绑定,待宿主升级后完整按表过滤生效。