Ennew Harness Python SDK
适用于 Python 3.9 及以上版本,安装包名为 ennew-harness-sdk,导入名称为 ennew_harness。
从 0.1.1 起,导入名称由 harness 改为 ennew_harness,避免与 Worker 自身的同名包冲突。升级后请同步修改业务脚本中的导入语句;不保留旧名称别名。
python3 -m pip install --upgrade ennew-harness-sdk
本 SDK 依赖 Ennew Harness 运行环境,并非独立运行的公共网关客户端。普通脚本读取上下文或发送前端消息时,运行时必须提供 CODEX_THREAD_ID;MCP 读取上下文或发送前端消息可改为传入请求 ctx。读取上下文还需设置 ENV 或 HARNESS_ENV,并能访问对应业务网关。发送前端消息需要本机 Worker 服务。
读取上下文时,Worker 还需通过环境变量 HARNESS_GATEWAY_CONTEXT_TOKEN 注入对应环境的服务凭据。SDK 将其放入 X-OpenClaw-Mcp-Gateway-Token 请求头;未配置或为空时,在发送请求前报错。不要将真实凭据写入源码、镜像或发布包。
安装到运行业务脚本的 Python 环境后,可直接使用:
from ennew_harness import context, gui
current = context.get_current_context()
gui.send("file_changed", {"file": "report.md"})
上述未传入 ctx 的调用都从运行时的 CODEX_THREAD_ID 获取当前线程身份。gui.send 要求传入非空的 type 和字典 payload,把 type 同时写入 params.type 与 params.message 中的业务 JSON,经 Worker 本机 127.0.0.1:18080/internal/events 发到当前线程的前端连接。只有线程正在执行且前端连接仍在时才能发送;接口返回成功表示消息已写入 WebSocket,不保证前端已处理。
MCP 回调中传入宿主提供的本次请求 ctx,SDK 从 ctx.meta["threadId"] 获取线程身份,不读取或修改 CODEX_THREAD_ID。元数据缺失或线程 ID 不是非空字符串时,在发送请求前报错,不回退环境变量。线程身份不要从模型填写的工具参数中获取。此方式不要求 SDK 安装 MCP 依赖,也不支持在尚无请求上下文的 MCP 启动阶段获取线程身份。
在异步 MCP 回调中,使用以下方式避免同步网关请求阻塞事件循环:
import asyncio
from ennew_harness import context, gui
current = await asyncio.to_thread(context.get_current_context, ctx)
await asyncio.to_thread(gui.send, "file_changed", {"file": "report.md"}, ctx=ctx)
context.get_current_context() 优先读取系统环境变量 ENV 并转为大写;ENV 未设置或为空字符串时,再读取 HARNESS_ENV(保持原有大小写要求)。取到的值必须是 FAT、UAT 或 PROD;非空但无效的 ENV 会直接报错,不会回退。SDK 根据该值选择网关配置,并完整返回网关响应中的 data,包括 authTokens、businessContext 及后续新增字段。返回值可能包含敏感凭据,业务脚本不得记录、展示或转发完整上下文。三套网关 URL 定义在 ennew_harness/context.py,请求不内置 Token。安装 SDK 不会自动授予业务网关访问权限。
源码仓库中可运行上下文示例脚本:python3 fat_context.py。该脚本不随安装包提供。
文件写入后通知(0.1.6 起)
模型生成文本、JSON 时,推荐用标准输入一次同步提交完整内容,不先创建 Agent 临时输入文件。脚本的 read() 等待 EOF,之后才校验、写入和通知。下例为可执行格式示例,真实产物按业务契约填写:
python3 -m ennew_harness.write_notify --file artifacts/report.json --content-file - --json <<'ARTIFACT_EOF'
{"title":"本次报告","ready":true}
ARTIFACT_EOF
用单引号包住 heredoc 标记,避免正文中的 shell 变量和命令被展开;标记不能出现在正文独立行中,结尾独占一行。先准备完整内容再发起一次调用,不后台执行、不交互式分段输入。生成程序管道的 EOF 不代表生成成功,不建议将未检查退出码的生成程序直接管道接入。
执行顺序:读取到 EOF → 输入校验 → 目标同目录临时文件写入、flush/fsync、关闭 → os.replace 原子替换 → 回读比对 → gui.send。默认外层 type=file.changed,消息 JSON 内 type=file_changed,data.files 为项目相对路径数组,与原通知协议一致。gui.py 保持不变;脚本内部通知适配器处理外层与内层 type 不同的情况,通过现有 Worker HTTP 接口发送。默认入口不产生 Agent 输入临时文件;SDK 内部临时文件成功替换后消失,失败时清理。
批量标准输入
python3 -m ennew_harness.write_notify --batch-stdin <<'ARTIFACT_BATCH_EOF'
{"files":[{"file":"artifacts/report.json","content":"{\"ready\":true}","json":true},{"file":"artifacts/report.md","content":"# 本次报告\n"}]}
ARTIFACT_BATCH_EOF
信封只含非空 files 数组,每项 file 是目标路径、content 是完整文本字符串,可选 json=true 校验该文件 JSON。批量信封完整读取 EOF 后,解析和校验全部内容,再写入文件;全部文件回读成功后发送一次去重通知。同路径同内容去重,不同内容拒绝。--json 校验所有项;混合 Markdown 与 JSON 时用逐项 json 标志。--batch-stdin 不与 --file、--content-file、--payload-from-content 或 --cleanup-input 混用。
项目状态通知
python3 -m ennew_harness.write_notify --file project-state.json --content-file - --json --type sop.update --payload-from-content <<'STATE_EOF'
{"revision":1,"currentStep":"step-01","steps":[{"stepId":"step-01","stepName":"需供能力匹配","viewType":"system-page","viewUrl":"/demandSupply","status":"not_started"}]}
STATE_EOF
此处展示一项的格式示例,实际状态按平台步骤配置提供完整列表。通知携带状态 JSON 并附加 type=sop.update,状态文件不增加 type。--payload-from-content 仅支持单文件;自定义消息可用 --payload-file 传入 JSON 对象,与前者互斥。
失败处理与文件模式
退出码 0:文件已保存且 Worker 接受通知,不表示前端已处理;1:输入、写入或回读失败,未发送通知,实际文件可能部分写入,应检查后修复;2:已保存但通知失败;3:保存和通知成功,但临时输入清理失败。
退出码 2 时使用原命令加 --notify-only,并重新提供完全一致的标准输入正文或批量信封,重试一次。该模式只回读对比、不重写文件、不递增 revision;内容改变拒绝通知。退出码 3 仅清理残留,不重新通知。标准输入不落输入临时文件,重试内容须由调用方保留;SDK 不持久化重试正文。
大文件或外部程序输出保留原文件输入模式:
python3 -m ennew_harness.write_notify --file artifacts/report.pdf --content-file drafts/report.tmp.pdf --cleanup-input
只有外部生成程序同步成功退出、文件关闭后才执行。--cleanup-input 通知成功后删除可丢弃的输入文件,失败保留供重试;不删除目标产物、payload-file 或需长期保留的原始材料。重复输入路径去重,输入与任一目标产物相同则预先拒绝。标准输入无需清理。文件模式仍支持重复 --file 与 --content-file 按出现顺序配对,全部输入先读取再写入。
环境与保证范围
目标相对路径基于 --root(默认 cwd);真实绝对路径及符号链接解析后的目标必须在 root 内。消息路径以 / 开头代表相对于项目根目录,不是服务器绝对路径。父目录自动创建。前端文件服务需访问同一存储视图,同目标写入须串行执行。
脚本校验 JSON 语法和读写一致性,不判断业务完整性;EOF 仅代表本次传输结束,不能识别内容本身遗漏或上游异常导致的完整合法短内容。批量写入不提供多文件事务回滚。当前无通知持久化、离线补发或前端处理回执。
运行环境需要更新后的 ennew-harness-sdk、CODEX_THREAD_ID 与本机 Worker。SDK 通知不产生 Codex JSONL 中 send_hidden_message 的调用记录,依赖此记录的后台记忆 Skill 归属需另行适配,不重复发送通知补记录。
Metadata
Release files for ennew-harness-sdk 0.1.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ennew_harness_sdk-0.1.7.tar.gz | 18.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ennew_harness_sdk-0.1.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.9 kB
Release files / ennew_harness_sdk-0.1.7.tar.gz
| Download URL | ennew_harness_sdk-0.1.7.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6a06b1571c7ad650070c71bc38c05cb2d7b09eb1bbafe322eff7b83dce91b40f
|
|
BLAKE2b-256 checksum How to use checksums |
2410d596d82b732a447257f70aac9d187443252f5271af0cbda9be3aa1bf6a2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.12
|
Release files / ennew_harness_sdk-0.1.7-py3-none-any.whl
| Download URL | ennew_harness_sdk-0.1.7-py3-none-any.whl |
|---|---|
| Size | 10.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a2353c635dadfd5b537e718e1030acac13db2bf40851b7a56b22cebd6d828392
|
|
BLAKE2b-256 checksum How to use checksums |
fe2f0984c1eaf99713973af84ddd95636a5663ed1bbd2fbf1873e5f79ca68f3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.12
|
Security for ennew-harness-sdk 0.1.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.