自动化

插件

给空间加上你自己的动作:用任何语言写的 HTTPS 服务,或者通过 runner 在你自己机器上跑的命令。带签名的任务、按范围读取输入、结果写成附加信息和新文件。

查看 Markdown

插件给 Side Space 加动作:质检、自家的转写服务、在自己显卡上跑的超分辨率……插件的代码从不在 Side Space 服务器上运行。它要么是接收签名任务的 HTTPS 服务,要么是 runner:在你自己机器上主动领任务的命令,不需要公网地址。

空间管理员安装后,它的动作以 x-acme.qc.check 这样的名字出现在内置动作旁边:可以手动运行、放进流水线、被 agent 通过 MCP 调用,也一样按内容缓存(只在本空间内复用,插件升版本后重新处理)。

清单

JSON
{
  "name": "x-acme.qc",
  "title": "Acme QC",
  "version": "1.2.0",
  "endpoint": "https://qc.acme.example/side/jobs",
  "timeout_seconds": 1800,
  "actions": [
    {
      "name": "check",
      "title": "检查掉帧",
      "accepts": ["video/"],
      "writes": ["x-acme.qc"],
      "params_schema": { "type": "object", "properties": { "strict": { "type": "boolean" } } }
    },
    { "name": "report", "title": "生成质检报告", "accepts": ["video/"], "writes": ["x-acme.qc", "files"] }
  ]
}
  • name 以 x- 开头;动作名是 <name>.<action>。
  • accepts 是 MIME 前缀列表(空表示任何文件)。发任务之前,参数会按 params_schema 校验。
  • writes 是动作可能写的所有东西:x-… 命名空间,声明了的话还有 transcript、ai.tags、ai.generation、user 和 files(新文件,会带 derived 附加信息)。结果里写了没声明的内容,整次运行失败,什么都不写。
  • version 是缓存键的一部分:升版本后会重新处理文件。
Shell
sidespace plugin install "Film A" https://qc.acme.example/side/manifest.json   # 打印签名密钥,只显示这一次
sidespace plugin list "Film A"
sidespace run "Film A" /Ep01/a.mov x-acme.qc.check --param strict=true
sidespace plugin enable "Film A" plg_… --off
sidespace plugin rm "Film A" plg_…

HTTPS 插件

服务器向 endpoint POST 一个任务,签名方式和 Webhook 相同(Side-Signature,用安装时给的密钥):

JSON
{
  "type": "run",
  "run_id": "run_…",
  "action": "check",
  "attempt": 1,
  "space_id": "spc_…",
  "node_id": "nod_…",
  "version_id": "ver_…",
  "path": "/Ep01/a.mov",
  "name": "a.mov",
  "mime": "video/quicktime",
  "size": 734003200,
  "params": { "strict": true },
  "sidecars": { "media": { "duration_s": 92.4, "width": 3840, "height": 2160, "fps": 24 } },
  "input": { "url": "https://blocks.side.example.com/files/ver_…?t=…", "expires_at": "…" },
  "callback": { "url": "https://side.example.com/v1/plugin-runs/run_…", "token": "srt_…", "expires_at": "…" }
}

input.url 可以按字节范围读取这个版本的内容,有效期覆盖整个超时时间,所以只读需要的那一段就行。60 秒内回答:

回答含义
200 加结果 {"sidecars": {"x-acme.qc": {…}}, "files": […]}完成
202在后台处理,之后通过回调完成
4xx运行失败,显示你给的原因
5xx 或超时和普通动作一样重试

回答 202 之后,带 Authorization: Bearer <callback.token> 调用回调:

  • POST {callback.url}/progress,带 {"progress": 0.4}
  • POST {callback.url}/upload 拿上传票据,再把文件 POST 到网关的 /stream-upload,得到 manifest
  • POST {callback.url}/complete 交结果,或者 {"error": "…", "retry": true}

超过 timeout_seconds 还没完成,会重新发一次,最多 3 次。

import { PluginRun } from "@sidespace/sdk";
import { verifyWebhookSignature } from "@sidespace/sdk/webhooks";

// 在你的 HTTP 处理函数里,用原始 body:
if (!verifyWebhookSignature(secret, req.headers["side-signature"], rawBody)) return res.writeHead(401).end();
res.writeHead(202).end();

const run = new PluginRun(JSON.parse(rawBody));
await run.progress(0.5);
const manifest = await run.upload(reportBytes);
await run.complete({ sidecars: { "x-acme.qc": { passed: true } }, files: [{ path: "/Ep01/a.qc.pdf", manifest }] });

仓库里的 tests/e2e/fakeplugin.py 是一个只用 Python 标准库的完整参考实现,包括同步回答、回答 202 后回调、上传文件和验签。

Runner:在自己的机器上跑

不想部署 HTTPS 服务,或者要用本机的模型和显卡(whisper.cpp、本地视觉模型、调色工具)时,把清单里的 endpoint 换成 "runtime": "runner",然后在那台机器上运行:

Shell
sidespace plugin install "Film A" ./local-tools.json         # 记下 plg_… 和 whsec_…
sidespace runner --plugin plg_… --secret whsec_… --jobs 2 -- ./qc.sh
  • runner 向服务器长轮询领任务,所以那台机器不需要公网地址,在 NAT 后面、笔记本上都行。它不在线时任务会排队。
  • 每个任务调用一次你的命令。输入文件已经下载好,路径在 SIDE_INPUT;任务 JSON 在 SIDE_JOB(stdin 上也有一份);SIDE_ACTION 和 SIDE_PARAMS 是动作名和参数;新文件写到 SIDE_OUTPUT 目录。
  • 在 stdout 打印结果 JSON,runner 会上传其中列出的文件,再完成这次运行:
JSON
{ "sidecars": { "x-acme.qc": { "passed": true } }, "files": [{ "path": "/Ep01/qc.pdf", "file": "qc.pdf", "mime": "application/pdf" }] }
  • stderr 里的 progress 0.4(或 progress: 40%)会显示为进度,其余输出原样打印。退出码 75 表示稍后重试,其他非零退出码让运行失败,原因取 stderr 的最后几行。
  • timeout_seconds 内没有 runner 来领,任务会重新排队,3 次后失败并提示“没有 runner”。plugin list 会显示 runner 最后一次来领任务的时间。

其他语言自己实现 runner:带 Authorization: Bearer plg_…:whsec_… 调用 POST /v1/plugin-runs/claim?wait=25,拿到的任务和 HTTPS 插件收到的一样,再用任务里的回调汇报。