brickly-sdk
Brickly Brick Python runtime 官方 SDK。它通过 stdin/stdout 与宿主通信,封装 BPP (Brickly Plugin Protocol),让 Python Brick 可以专注写命令逻辑,而不是手写协议消息。
stdout 会被 SDK 保留给 BPP 协议消息;业务日志请使用 brick.log(...) 写入 stderr。
安装
pip install brickly-sdk==0.3.0
国内环境可以使用 PyPI 镜像:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple brickly-sdk==0.3.0
快速开始
from brickly import BricklyRuntime
brick = BricklyRuntime("com.example.python")
@brick.on_command("hello")
def hello(ctx, input_value):
ctx.progress(0.5, "处理中...")
ctx.chunk("hello\n")
return {"ok": True, "input": input_value}
brick.run()
SDK 会自动处理:
host.hello->runtime.readyruntime.ping->runtime.pongcommand.invoke命令分发command.cancel取消信号、ctx.is_cancelled()和ctx.on_cancel(...)command.progress、command.chunk和command.outputhost.*请求 ID 分配,以及host.result/host.error路由runtime.shutdown-> 可选 shutdown hook ->runtime.bye- 子窗口创建、窗口方法调用、
window.*事件路由 - 事件总线
events.publish(...)/events.on(...) - 跨 Brick 调用
invoke(...)、invoke_root(...)、invoke_stream(...) - 跨 Brick 会话
open_session(...) - 平台能力
platform.screenshot、platform.screen、platform.input、platform.clipboard、platform.system
跨 Brick 的 invoke / invoke_resource / root / session 调用不设置 SDK 本地固定超时,由 Host
调用生命周期和 command.cancel 统一终止,避免大资源或长任务被误判超时。其他底层 Host API
仍保留默认超时,显式 timeout 的调用方式不变。
与 Node SDK 的同步关系
Python SDK 的协议语义与 @syllm/brickly-sdk 保持一致:
- Python 使用
snake_case方法名,例如create_browser_window()、set_full_screen()。 - Node 使用
camelCase方法名,例如createBrowserWindow()、setFullScreen()。 - 两者底层发送的 BPP 消息类型和窗口方法名一致。
- 当前 SDK 包版本为
0.3.0;BPP 协议版本为0.2.0;窗口 DTO 和方法 Literal 由specs/bpp.schema.json生成。 - Python 不提供 Node 的 TypeScript
CommandMap类型生成能力;Python 侧依赖类型标注和中文 docstring 提供 IDE 补全。
命令上下文
命令处理函数会收到 CommandContext:
@brick.on_command("process")
def process(ctx, input_value):
ctx.progress(0.2, "准备中")
if ctx.is_cancelled():
return {"cancelled": True}
ctx.output("debug", {"step": "start"})
ctx.chunk("第一段输出\n")
return {"ok": True}
常用属性和方法:
ctx.request_id:当前请求 IDctx.command_id:当前命令 IDctx.invocation:宿主传入的可信调用来源和依赖 Profile 映射ctx.config:当前 Profile 配置快照ctx.ui:子窗口 APIctx.events:事件总线 APIctx.platform:平台能力 APIctx.system:ctx.platform.system的快捷别名ctx.progress(value, message):上报进度ctx.chunk(chunk, name=None):追加流式输出ctx.output(name, value):设置具名输出ctx.invoke(...):在命令作用域内调用另一个 Brickctx.invoke_resource(...):调用另一个 Brick 并固定返回ResourceHandlectx.invoke_root(...):发起独立 root 调用,并携带当前请求 ID 供宿主审计ctx.invoke_root_resource(...):发起独立资源结果调用ctx.invoke_stream(...):流式调用另一个 Brickctx.open_session(...):打开跨 Brick 会话,后续可用session.invoke(...)/session.invoke_stream(...)
子窗口
from brickly import BricklyRuntime
brick = BricklyRuntime("com.example.window")
@brick.on_command("open")
def open_window(ctx, _input):
win = ctx.ui.create_browser_window("ui/index.html", {"width": 640, "height": 480})
win.on("closed", lambda payload: brick.log("窗口已关闭", payload))
win.set_title("Hello from Python")
win.web_contents.send("app:hello", {"requestId": ctx.request_id, "text": "你好"})
return {"windowId": win.id, "windowKey": win.window_key}
brick.run()
WindowHandle 提供与 Node SDK 对齐的常用窗口方法,例如:
- 几何尺寸:
set_bounds()、get_bounds()、set_position()、set_size() - 内容区域:
set_content_bounds()、get_content_bounds()、set_content_size() - 状态切换:
minimize()、maximize()、restore()、show()、hide()、focus() - 状态查询:
is_visible()、is_focused()、is_minimized()、is_full_screen() - 外观能力:
set_title()、set_opacity()、set_background_color()、set_has_shadow() - webContents:
send()、execute_javascript()、open_dev_tools()、go_back()、set_zoom_factor()、copy()、paste()、undo()
关闭是显式生命周期操作:
result = win.close()
if result["status"] in ("pending", "prevented"):
win.focus() # 句柄仍可用
termination = win.force_close()
# win.destroy() 是 force_close() 的旧便利名,不走反射 destroy。
close() 返回 closed/prevented/pending/not-found。只有 closed/not-found 和 window.closed 终态事件会把句柄标记为 closed、从 Runtime Map 删除并清空 listener。终态 eventId 有界去重,transport 结束时也会释放全部窗口句柄。
跨 Brick 调用
命令处理函数内部使用 ctx.invoke(...):
result = ctx.invoke(
"com.brickly.openai",
"chat",
{"prompt": "hello"},
profile_id="work",
)
如果宿主在 ctx.invocation.dependencyProfiles 中给目标 Brick 指定了 Profile,且调用时没有显式传
profile_id,ctx.invoke(...)、ctx.invoke_root(...)、ctx.invoke_stream(...) 和
ctx.open_session(...) 都会自动沿用该 Profile;显式 profile_id 始终优先。这一点与 Node SDK 行为一致。
命令处理函数外部需要使用显式 root 调用:
result = brick.invoke_root(
"com.brickly.openai",
"chat",
{"prompt": "hello"},
profile_id="work",
)
大载荷与资源
普通 invoke / invoke_root 始终返回直接值,逻辑 JSON 输入和结果上限为 200 MiB;
超限抛出 PAYLOAD_TOO_LARGE,不会静默改成资源类型。预期结果需要流式读取时使用
ctx.invoke_resource(...)、brick.invoke_root_resource(...) 或
session.invoke_resource(...),它们固定返回 ResourceHandle:
resource = ctx.invoke_resource("com.example.report", "export", input_value)
if resource.ref["sizeBytes"] <= 200 * 1024 * 1024:
report = resource.json()
else:
resource.save_to(output_path)
ctx.invoke("com.example.consumer", "analyse", {"source": resource})
Brick 可主动创建资源:
input_resource = brick.resources.create(data, name="input.bin")
str 默认 text/plain; charset=utf-8,bytes 默认 application/octet-stream;只有下游需要
具体类型时才传 mime_type。该 API 要求 resource.register。小内容走一次性快速路径,大内容
自动切换到 Writer,调用方式和返回类型不变。
大内容使用 create_from:
with open("large.bin", "rb") as source:
resource = brick.resources.create_from(source, name="large.bin")
它也接受 Iterable[str | bytes],自动聚合后按最大 1 MiB 的 wire 分块顺序写入 Host,finish 后返回
ResourceHandle。finish 前资源不可读取;发布后下游独立读取,不会向上传端施加背压。资源总大小
不受普通 invoke 的 200 MiB 上限约束。Host 限制并发上传并在生产环境保留 1 GiB 磁盘安全
余量;部署还可配置全局和 Brick 维度的 pending bytes 配额。
需要主动分多次写入时使用 create_writer:
writer = brick.resources.create_writer(name="result.bin")
writer.write(header)
writer.write_from(download_stream)
resource = writer.finish()
同一 Writer 的 write、write_from、finish、abort 按调用顺序串行执行;abort 不会越过
已经开始的数据源操作。大文本在 SDK 内分段编码,不会额外创建一份完整 UTF-8 副本。
ResourceHandle 支持迭代字节、text()、json()、save_to()、close() 和
revoke();再次作为 input 时只传 ResourceRef。事件总线回调统一收到外层
ResourceHandle,需要先 json() 取得业务对象。资源内容按普通 JSON 解析,内嵌的
ResourceRef 不会自动水合,需要读取时应显式转换。不要记录 capability token,也不要
长期持久化 Ref。
流式调用:
for event in ctx.invoke_stream("com.brickly.openai", "chat", {"prompt": "hello"}):
if event["type"] == "progress":
ctx.progress(event.get("progress", 0), event.get("message"))
elif event["type"] == "chunk":
ctx.chunk(event.get("chunk"))
elif event["type"] == "output":
ctx.output(event["name"], event.get("value"))
elif event["type"] == "result":
return event["result"]
跨 Brick 调用需要在调用方 manifest 的 dependencies 中声明目标 Brick 和命令:
"dependencies": {
"com.brickly.openai": {
"commands": ["chat"]
}
}
跨 Brick 会话
当目标 Brick 需要保留内存状态时,使用 ctx.open_session(...):
session = ctx.open_session("com.brickly.openai", profile_id="work")
try:
session.invoke("start-thread", {"title": "草稿"})
reply = None
for event in session.invoke_stream("chat", {"prompt": "继续这个话题"}):
if event["type"] == "chunk":
ctx.chunk(event.get("chunk"))
elif event["type"] == "result":
reply = event["result"]
return reply
finally:
session.close()
平台能力
系统 API:
@brick.on_command("show-app-info")
def show_app_info(ctx, _input):
return {
"appName": ctx.system.get_app_name(),
"appVersion": ctx.system.get_app_version(),
"userData": ctx.system.get_path("userData"),
"isWindows": ctx.system.is_windows(),
}
剪贴板 API:
@brick.on_command("replace-clipboard")
def replace_clipboard(ctx, _input):
previous = ctx.platform.clipboard.read_content()
updated = ctx.platform.clipboard.set_content({"kind": "text", "text": "来自 Python"})
return {"previous": previous, "updated": updated}
输入和屏幕 API:
@brick.on_command("screen-info")
def screen_info(ctx, _input):
point = ctx.platform.screen.get_cursor_screen_point()
display = ctx.platform.screen.get_primary_display()
return {"point": point, "display": display}
@brick.on_command("click")
def click(ctx, _input):
ctx.platform.input.mouse_click(100, 100)
ctx.platform.input.keyboard_tap("A", "control")
return {"ok": True}
这些能力由宿主按 manifest 权限校验。缺少权限时,宿主会返回 host.error,SDK 会抛出 BppError。
错误处理
抛出 BppError 可以保留明确错误码:
from brickly import BppError
raise BppError("INVALID_INPUT", "url 不能为空")
普通异常会被 SDK 转换为 INTERNAL_ERROR 并返回给宿主。
日志
brick.log("开始处理", {"id": 1})
brick.log(...) 会发送 runtime.log(info)到宿主。不要手动给日志加 [brickId] 前缀,宿主日志中心会自动附加 Brick ID、来源和作用域信息。
源码结构
实现按领域拆分为 transport / scope / command / session / window / events / platform / runtime,与 Node SDK 对齐。
详情见 brickly/README.md。
AI 对齐框架
本 SDK 是 Follower 实现。用 AI 跟进 Node 时请走:
specs/sdk/AGENT.mdspecs/sdk/capability-matrix.yamlspecs/sdk/api-mapping.yamlspecs/sdk/prompts/follower-agent.md(target=python)
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file brickly_sdk-0.3.0.tar.gz.
File metadata
- Download URL: brickly_sdk-0.3.0.tar.gz
- Upload date:
- Size: 44.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aae63bbcae97fed6b1c8714422f6461b59b746d79a31a733501c1f3a0faba7e9
|
|
| MD5 |
b2470dcbda00b6d91821e16528434dbe
|
|
| BLAKE2b-256 |
b9dfe10b05ebd2eba90b6d0de52ea93d0081b92a073d37e00c3531ce08619a51
|
File details
Details for the file brickly_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: brickly_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 41.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11859d7e7d6c82495b2a5eb4febae1a493c2ad1f007fd747204c92b83331ba62
|
|
| MD5 |
add46ec429c39dd10952019d94125757
|
|
| BLAKE2b-256 |
157be29c79d071af13c66ef49357964e59511a72334e20c84094d0e1acfc4888
|