TTokenySpace
返回 Skills 列表

skill-to-http-flash

把单个 Skill 编译成独立 HTTP REST API 微服务(v2.0 subprocess 直执行)。当用户说「skill 暴露成 HTTP 接口」「flash 一个 skill」「skill 起 API 服务」「skill 输入输出结构化」「standalone 跑 skill」 「skill-to-http-flash」时使用。JSON → Python 入口 → 统一 envelop

#中文
0

安装到 Tokeny(自动)

下载 ZIP
安装"skill-to-http-flash"技能
技能信息:
- 名称: skill-to-http-flash
- 标识: skill-to-http-flash
- 描述: 把单个 Skill 编译成独立 HTTP REST API 微服务(v2.0 subprocess 直执行)。当用户说「skill 暴露成 HTTP 接口」「flash 一个 skill」「skill 起 API 服务」「skill 输入输出结构化」「standalone 跑 skill」 「skill-to-http-flash」时使用。JSON → Python 入口 → 统一 envelop
- 版本: 1.0.0
下载地址:
https://www.tokeny.space/api/skills/skill-to-http-flash/download
继续

复制上方内容到 Tokeny 客户端并在会话中发送即可自动安装;也可直接 下载 ZIP并拖动到技能窗口安装。

SKILL.md

skill-to-http-flash v2.0

依赖:Python 3.10+;pip install fastapi uvicorn cryptography pydantic jsonschema;可选 openssl(HTTPS)。

定位:subprocess 直执行 + standalone。"把 Skill 脚本变成稳定 REST API"的微服务工厂。

POST /run  →  subprocess.run(["python3", "scripts/main.py", "--foo", "x", ...])
            →  envelope { success / exit_code / elapsed_ms / data | output / stderr / truncated }

不依赖 Gateway,运行期不调 LLM,不走 sessions_spawn。秒级冷启,100% 复现,零 LLM 漂移。

ℹ️ 关于 LLM运行期(/run 执行 skill)完全不碰 LLM,100% subprocess 确定性。 仅在 create / recreate 生成期,会可选用 LLM 从 SKILL.md 自动提取入参 schema—— 未配置 LLM(默认)时走启发式 fallback(空 schema + additionalProperties: true), 生成后可手动编辑 params.json。即:跑起来零 LLM,生成时 LLM 只是锦上添花


v1 → v2 重大变更速览

维度v1.xv2.0
执行方式sessions_spawn 调 OpenClaw agent + LLMsubprocess 直调 skill 的 Python 入口
依赖 Gateway✅ 必须❌ 不需要
入参自由 message 字段(LLM 解读)JSON Schema 校验 + 长 flag CLI 映射
出参自由文本统一 envelope,自适应 JSON 解析(A)或文本(B)
截断无明确阈值同步 512 KB 截断 + 异步不截断
skill-to-http 依赖静默自动安装完全移除,自带 _cert.py
standalone部分支持一等公民设计目标--skill-dir/--data-dir + env 覆盖)
默认超时120s60s(同步)

v2.0 不兼容 v1 老 project。已有的 v1 project 必须 flash.py remove 后重新 create。详见 references/migration-from-v1.md


前置条件

  • Python 3.10+
  • Skill 的入口必须是 .py 文件(v2.0 不支持 shell entry,因为 shell 难校验参数)
  • 推荐 skill 的入口用 argparse 长 flag(自动映射 {"foo": "x"}--foo x

不再需要:OpenClaw Gateway / 运行期 LLM。(生成期可选 LLM 提参,未配置走 fallback,见上方说明。)


SKILL.md frontmatter 约定(推荐)

让被 flash 的 skill 在 frontmatter 显式声明入口:

---
name: my-skill
version: 1.0.0
description: ...
flash:
  entry: scripts/main.py        # 相对 skill 目录
  interpreter: python3          # 可选,默认 python3
---

找不到 flash.entry,flash 按以下顺序扫 7 个候选位置(首个命中为准):

  1. scripts/<skill-name>.py
  2. scripts/cli.py
  3. scripts/main.py
  4. scripts/run.py
  5. <skill-name>.py(skill 根目录)
  6. main.py(skill 根目录)
  7. cli.py(skill 根目录)

都找不到 → 直接报错并打印 frontmatter patch 建议,引导用户加 flash.entry

⚠️ 找到 .sh 入口也会报错 — v2.0 只支持 .py。包一层 subprocess.run(["bash", ...]) 的 Python launcher 即可。


快速开始(OpenClaw 环境)

cd ~/.openclaw/workspace/skills/skill-to-http-flash/scripts

# 1. 创建 flash 项目
python3 flash.py create --skill <skill-name>
#   → 解析入口、提参数 schema、交互确认端口/超时/TLS
#   → 生成到 <workspace>/.skill-to-http-flash/services/<skill-name>-api/

# 2. 启动
cd <workspace>/.skill-to-http-flash/services/<skill-name>-api
pip install -r requirements.txt
python3 server.py start

# 3. 调用
curl -X POST http://127.0.0.1:7780/run \
  -H 'content-type: application/json' \
  -d '{"foo": "bar"}'

Standalone 用法(非 OpenClaw 环境)

任何能跑 Python 的机器都能用,完全不依赖 ~/.openclaw。它本质是"把带 argparse 的 Python 脚本编译成 REST API",与具体 agent runtime 无关——不 import 任何 agent SDK,不调 Gateway / LLM / sessions_spawn。

多 agent 开箱即用:默认自动探测以下 skill 目录(首个命中为准),OpenClaw / Claude Code / Cursor 用户无需手设 env:

~/.openclaw/workspace/skills/   # OpenClaw
~/.claude/skills/               # Claude Code
~/.cursor/skills/               # Cursor
~/.config/skills/               # 通用 XDG
./skills/                       # 项目本地
/app/skills/                    # 容器挂载

自定义目录(其它 runtime 或非标准布局):

# 方式 A:环境变量
export FLASH_SKILL_DIR=/your/path/to/skills
export FLASH_DATA_DIR=/your/path/to/flash-data
python3 flash.py create --skill my-skill

# 方式 B:CLI flag(每条命令带上)
python3 flash.py \
  --skill-dir /your/path/to/skills \
  --data-dir /your/path/to/flash-data \
  create --skill my-skill

生成的 server.py 完全自包含,可 scp 到任何机器裸跑(只需 pip install -r requirements.txt),与本 skill / 任何 agent runtime 解耦。

完整 standalone 指南:references/standalone-usage.md


入参映射规则(JSON → CLI 长 flag)

请求 JSON转成 argv
{"foo": "x"}--foo x
{"foo_bar": 10}--foo-bar 10(下划线 → 横杠)
{"verbose": true}--verbose(flag style)
{"verbose": false}(不传,约定脚本默认就是 false)
{"verbose": null}(不传)
{"tags": ["a","b"]}--tags a --tags b(重复 flag)
{"meta": {"k":"v"}}--meta '{"k":"v"}'(嵌套对象序列化为 JSON 字符串)

安全:字段名走白名单 [a-z][a-z0-9_]*(防 --foo;rm -rf /),argv 走 list 不拼 shell。


响应 envelope

{
  "success": true | false,        // exit_code == 0
  "exit_code": 0 | n,              // subprocess 返回码
  "elapsed_ms": 240,
  "data": <object|array|primitive> | null,  // stdout 是合法 JSON 时(模式 A)
  "output": "<string>" | null,              // stdout 不是 JSON 时(模式 B)
  "stderr": "<string>" | null,              // 仅 success=false 时透出
  "stderr_truncated": true,                  // 仅 stderr 被截断时(success=false 路径)
  "truncated": true,                         // 仅同步 + stdout >512KB 时
  "hint": "Output exceeded 512KB. Use POST /run/async + GET /jobs/<id> for full output."  // 仅 truncated=true 时
}

dataoutput 互斥——任意时刻只有一个有值。

自适应 JSON 解析

  • stdout 是合法 JSON → 走 data 字段(模式 A,客户端可结构化访问)
  • 否则 → 走 output 字段(模式 B,原始文本)
  • 脚本零改动:原来啥样还啥样

错误类型

错误码HTTP触发场景
validation_failed400JSON Schema / 字段名白名单校验失败
entry_not_found500入口文件不存在或不是 .py
spawn_failed500subprocess 启动失败(interpreter not in PATH 等)
timeout408超过 timeout_seconds
rate_limited429/run/async 并发 >20
internal_error500未预期异常(兜底)
exit_code != 0200业务执行失败(脚本"运行了但失败"),envelope.success=false + stderr 透出

设计原则:业务失败用 envelope 表达,HTTP 状态码只表达框架问题


路由

MethodPath说明
GET/HTML 引导页
GET/healthprobe entry 文件 + interpreter 在 PATH
GET/schema入参 JSON Schema + entry / interpreter
GET/docsFastAPI Swagger UI
POST/run同步执行,默认 60s 超时,512KB 截断
POST/run/async异步执行,立即返回 job_id,不截断
GET/jobs/{id}轮询异步任务(内存 + JSONL fallback)

异步任务(不截断 + 持久化)

# 提交
JOB=$(curl -s -X POST http://127.0.0.1:7780/run/async \
  -H 'content-type: application/json' -d '{"big_query": true}')
JOB_ID=$(echo "$JOB" | jq -r .job_id)

# 轮询
curl http://127.0.0.1:7780/jobs/$JOB_ID
# {"job_id":"...","status":"completed","result":{...完整 envelope...}}
  • 不截断:异步任务保留完整 stdout(>512KB 也不切)
  • 内存(快查,1h TTL)+ JSONL 持久化(重启不丢)
  • 并发上限 20{"status": "failed", "error_type": "rate_limited"} 429
  • logrotate:JSONL 单文件 >10MB 切到 .1 ~ .7,保留 7 份
  • 导出 SQLitepython3 flash.py jobs-export-sqlite --skill <name>

CLI 命令清单

# 创建项目(首次/新 skill)
python3 flash.py create --skill <name> [--output <dir>]

# 列出所有项目
python3 flash.py list

# 删除(默认保留生成的代码,加 --delete-files 一并删)
python3 flash.py remove --skill <name> [--delete-files]

# Skill 升级后重新生成(保留端口/超时/TLS 配置,只刷 server.py 和 params.json)
python3 flash.py recreate --skill <name> [--yes] [--diff]

# 证书管理(HTTPS 模式)
python3 flash.py cert --skill <name> --cert-action info | renew | import \
    [--cert-src <crt> --key-src <key>]

# 异步 job 历史导出 SQLite
python3 flash.py jobs-export-sqlite --skill <name>

# 生成 systemd unit(宿主机自启)
python3 flash.py systemd --skill <name> [--user] [--output <path>] [--restart-sec 5]

# Standalone:所有命令都支持 --skill-dir / --data-dir 全局 flag
python3 flash.py --skill-dir /path/to/skills --data-dir /path/to/data create --skill <name>

持久化目录(K8s Pod 容器友好)

数据默认位置环境变量覆盖
flash 项目数据(projects.json / jobs.jsonl / PID)<workspace>/.skill-to-http-flash/FLASH_DATA_DIROPENCLAW_FLASH_DATA_DIR
证书 / API Key<workspace>/.http/OPENCLAW_HTTP_ROOT
Skill 搜索路径~/.openclaw/workspace/skills/~/.claude/skills/~/.cursor/skills/~/.config/skills/./skills//app/skills/FLASH_SKILL_DIR

兜底(非 OpenClaw 环境):~/.skill-to-http-flash/~/.http/

⚠️ K8s Pod:~/ 下非 workspace 目录可能不挂 PVC,重启丢密钥/证书/历史。默认存 workspace 内能规避(PVC 一定持久化)。


TLS / HTTPS

默认 HTTP(零门槛跑通)。create 时可选启用 HTTPS(自签 SAN 证书)。

# create 时启用
python3 flash.py create --skill foo
# Enable HTTPS? [y/N]: y

# 已有 project 切换
python3 flash.py recreate --skill foo --tls-enabled
python3 flash.py recreate --skill foo --no-tls

# 运行时临时切换(不重生代码)
FLASH_TLS_ENABLED=1 python3 server.py start

# 导入公司颁发的正式证书
python3 flash.py cert --skill foo --cert-action import \
    --cert-src server.crt --key-src server.key

证书路径:<HTTP_ROOT>/certs/flash-<skill>/server.{crt,key},自动 SAN 嗅探本机 IP,有效期 365 天。


鉴权

可选 API Key(X-API-Key header,与 skill-to-http / agent-easy-http 对齐):

# 启用方式
FLASH_API_KEY=mysecret python3 server.py start          # env
echo -n "mysecret" > <HTTP_ROOT>/secrets/api-keys/flash-<skill>.key  # 文件(0600)

# 调用
curl -H 'X-API-Key: mysecret' http://...:7780/run -d '{...}'

未设置不做认证(仅适合内网受信测试)。公网部署请走前置反代 + 公认证书。


CORS

默认 Access-Control-Allow-Origin: *(无 credentials)。收紧:

FLASH_CORS_ALLOW_ORIGINS="https://your-tool.com,https://other.com" python3 server.py start

生成的项目结构

output/<skill-name>-api/
├── server.py           # 独立 FastAPI 服务(~1150 行)
├── params.json         # 入参 schema
├── requirements.txt    # fastapi / uvicorn / cryptography / pydantic / jsonschema
├── start.sh            # 后台启动
├── stop.sh             # 停止
├── restart.sh          # 重启
└── README.md           # 接口文档

server.py 完全自包含(内嵌 cert / job store / argv builder / envelope),可 scp 到任何机器跑。


与 skill-to-http 的关系(更新)

维度skill-to-httpskill-to-http-flash v2.0
服务模型多 Skill 统一网关单 Skill 独立 subprocess 微服务
Schema运行时动态(LLM 生成)生成时固化(JSON Schema 校验)
执行引擎sessions_spawn + LLMsubprocess.run() 直调
启动延迟30s+ (LLM 链路)<2s
复现性LLM 漂移100% 确定性
依赖Gateway + LLM无外部依赖

flash v2.0 不再依赖 skill-to-http(v1.x 自动安装逻辑已删除)。


参考文档

  • references/migration-from-v1.md — v1 用户如何 recreate
  • references/standalone-usage.md — 非 OpenClaw 环境完整使用指南

适用场景

  • HTML 工具站通过 fetch 调 skill 拿结构化数据
  • CI/CD pipeline 步骤里 curl skill 当成"可复用脚本服务"
  • 跨服务调用:服务 A 想调服务 B 的某个 skill
  • 本地脚本快速变 REST API:argparse 写好后立即变 HTTP 接口

不适用场景(v2.0 第一版边界)

  • ❌ 入口是 shell .sh(包一层 Python launcher)
  • ❌ 需要 LLM 自然语言"理解后取数"(用 skill-to-http 或 agent-easy-http)
  • ❌ stdout 包含人交互式 UI(如 TUI)
  • ❌ 需要长连接 / SSE / WebSocket

Changelog

v2.0.3

  • 文档:README 改为 runtime-中立表述,OpenClaw / Claude Code / Cursor / standalone 平等对待(此前 Install 表偏 OpenClaw)

v2.0.2

  • 多 agent 兼容:skill 目录探测新增 Claude Code (~/.claude/skills) / Cursor (~/.cursor/skills) / 通用 XDG (~/.config/skills) / 项目本地 (./skills) 兜底,非 OpenClaw runtime 开箱即用无需手设 env
  • 文档一致性修复:明确「运行期零 LLM、生成期可选 LLM 提参(未配置走 fallback)」,消除「不调 LLM」与 create 期 schema 提取仍调 LLM 的表述冲突
  • 优雅退出修复:生成的 server.py lifespan 退出不再 os._exit(0)(原会绕过 atexit/finally/日志 flush,可能截断 JSONL 落盘),改为让 uvicorn 自然走完关闭流程
  • 安全加固:API Key 校验改用 hmac.compare_digest 恒定时间比较(防 timing attack);401 响应不再回显 header 名
  • 健壮性flash.py list 的 stale 判断异常捕获从冗余的 (OSError, Exception) 收敛为 (OSError, ValueError, JSONDecodeError)
  • 新增可配置项:异步并发上限支持 FLASH_MAX_ASYNC env 覆盖(默认 20)

v2.0.1

  • PVC 持久化路径、TLS/鉴权/CORS、异步 job store、SQLite 导出等(详见正文)

评论

加载中…