Skip to main content

brickly-sdk

Brickly Brick Python runtime 官方 SDK。通过 loopback gRPC 接入 Host Runtime (invoke / interact),让 Python Brick 专注写命令逻辑。缺少 Host endpoint 时拒绝 BPP fallback。

业务日志请使用 brick.log(...) 写入 stderr,不要手写旧 stdin/stdout 协议帧。

安装

pip install brickly-sdk==0.6.0

国内环境可以使用 PyPI 镜像:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple brickly-sdk==0.6.0

快速开始

from brickly import BricklyRuntime

brick = BricklyRuntime("com.example.python")


@brick.on_command("hello")
def hello(ctx, input_value):
    ctx.send({"type": "hello", "text": "处理中..."})
    return {"ok": True, "input": input_value}


brick.run()

SDK 会自动处理:

  • 连接 BRICKLY_HOST_ENDPOINT 并注册 gRPC Runtime
  • invoke / interact 命令分发
  • 取消信号、ctx.is_cancelled()ctx.on_cancel(...)
  • invoke 一次一结果;interactctx.send / on_event / closed
  • Host 平台 / UI / Resource 客户端
  • 可选 shutdown hook
  • 子窗口创建、窗口方法调用、window.* 事件路由
  • 事件总线 events.publish(...) / events.on(...)
  • alias-first 跨 Brick 调用与会话:dependencies.require(alias)
  • 平台能力 platform.screenshotplatform.screenplatform.inputplatform.clipboardplatform.system

跨 Brick 的 invoke / interact 不设置 SDK 本地固定超时,由 Host 调用生命周期统一终止,避免大资源或长任务被误判超时。其他底层 Host API 仍保留默认超时,显式 timeout 的调用方式不变。

与 Node SDK 的同步关系

Python SDK 的协议语义与 @syllm/brickly-sdk 保持一致:

  • Python 使用 snake_case 方法名,例如 create_browser_window()set_full_screen()
  • Node 使用 camelCase 方法名,例如 createBrowserWindow()setFullScreen()
  • 两者底层走同一套 gRPC Runtime / Host 服务,窗口方法名一致。
  • 当前 SDK 包版本为 0.6.0;生产协议是 brickly.runtime.v1
  • Python 不提供 Node 的 TypeScript CommandMap 类型生成能力;Python 侧依赖类型标注和中文 docstring 提供 IDE 补全。

命令上下文

命令处理函数会收到 CommandContext

@brick.on_command("process")
def process(ctx, input_value):
    if ctx.is_cancelled():
        return {"cancelled": True}

    ctx.send({"type": "status", "step": "start"})
    return {"ok": True}

长期占用使用 ToolSdk.start() / ToolHandle。异步上下文管理器是 dispose() 语法糖。一次性 invoke 不会 pin 进程。

常用属性和方法:

  • ctx.request_id:当前请求 ID
  • ctx.command_id:当前命令 ID
  • ctx.invocation:宿主传入的可信调用来源和依赖 Profile 映射
  • ctx.config:当前 Profile 配置快照
  • ctx.ui:子窗口 API
  • ctx.events:事件总线 API
  • ctx.platform:平台能力 API
  • ctx.systemctx.platform.system 的快捷别名
  • ctx.send(event):推给调用方(仅 interact)
  • ctx.on_event(handler):收调用方 send(仅 interact)
  • ctx.closed.wait():等到调用方 closeInput / 断开
  • ctx.dependencies.require(alias):获取绑定当前 command parent、trace 与 Profile 的依赖客户端

子窗口

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-foundwindow.closed 终态事件会把句柄标记为 closed、从 Runtime Map 删除并清空 listener。终态 eventId 有界去重,transport 结束时也会释放全部窗口句柄。

跨 Brick 调用

命令处理函数内部只使用 manifest alias:

result = ctx.dependencies.require("openai").invoke(
    "chat",
    {"prompt": "hello"},
    profile_id="work",
)

session = await ctx.dependencies.require("openai").interact(
    "complete",
    {"prompt": "写一首诗"},
)
await session.close_input()
poem = await session.result

精确来源和版本由 Host 握手绑定。热键依赖 Profile 会按绑定的精确 BrickKey 自动使用,显式 profile_id 始终优先。

命令处理函数外部需要使用显式 root 调用:

result = brick.dependencies.require("openai").invoke_root(
    "chat",
    {"prompt": "hello"},
    profile_id="work",
)

大载荷与资源

普通 invoke / invoke_root 始终返回直接值,逻辑 JSON 输入和结果上限为 10 MiB,一次传完; 超限抛出 PAYLOAD_TOO_LARGE,不会静默改成资源类型。大结果由作者 createreturn Handle;invoke 交回 ResourceRef,调用方再 open

ref = ctx.dependencies.require("report").invoke("export", input_value)
resource = brick.resources.open(ref)

if resource.ref["sizeBytes"] <= 200 * 1024 * 1024:
    report = resource.json()
else:
    resource.save_to(output_path)

ctx.dependencies.require("consumer").invoke(
    "analyse",
    {"source": resource},
)

Brick 可主动创建资源:

input_resource = brick.resources.create(data, name="input.bin")

str 默认 text/plain; charset=utf-8bytes 默认 application/octet-stream;只有下游需要 具体类型时才传 mime_type。该能力无需声明 manifest 权限,但仍受 Host 配额与生命周期治理。小内容走一次性快速路径,大内容 自动切换到 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 的 10 MiB 上限约束。Host 限制并发上传并在生产环境保留 1 GiB 磁盘安全 余量;部署还可配置全局和 Brick 维度的 pending bytes 配额。

ResourceHandle 支持迭代字节、text()json()save_to()close()revoke();再次作为 input 时只传 ResourceRef。事件总线回调统一收到外层 ResourceHandle,需要先 json() 取得业务对象。资源内容按普通 JSON 解析,内嵌的 ResourceRef 不会自动水合,需要读取时应显式转换。不要记录 capability token,也不要 长期持久化 Ref。无论事件大小,回调都不会收到内联对象或内部 {"resource": ..., "encoding": "json"} 包装;消费完成后应调用 close()

普通 invoke、interact、命令输入和资源 JSON 中的嵌套引用保持 ResourceRef。发送 invoke、 command 结果或事件时,SDK 自动把嵌套 ResourceHandle 转为完整 Ref。接收方通过 brick.resources.open(ref) 显式创建惰性 Handle;open() 不会立即访问 Host:

resource = brick.resources.open(payload["attachment"])
try:
    resource.save_to(output_path)
finally:
    resource.close()

流式调用用 interact,收事件后再 result()

session = await ctx.dependencies.require("openai").interact(
    "chat",
    {"prompt": "hello"},
)
async for event in session.events:
    ctx.send(event)
await session.close_input()
return await session.result

跨 Brick 调用需要在调用方 manifest 的 dependencies 中声明目标 Brick 和命令:

"dependencies": {
  "openai": {
    "target": {
      "brickId": "com.brickly.openai",
      "origin": "installed",
      "version": "2.1.0"
    },
    "commands": ["chat"]
  }
}

跨 Brick 会话

目标 Brick 有状态时,在 command handler 里 interact,不要另做 open()

session = await ctx.dependencies.require("openai").interact(
    "chat",
    {"prompt": "继续这个话题"},
)
async for event in session.events:
    ctx.send(event)
await session.close_input()
return await session.result

平台能力

系统 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.md
  • specs/sdk/capability-matrix.yaml
  • specs/sdk/api-mapping.yaml
  • specs/sdk/prompts/follower-agent.mdtarget=python

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

brickly_sdk-0.6.0.tar.gz (74.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

brickly_sdk-0.6.0-py3-none-any.whl (88.7 kB view details)

Uploaded Python 3

File details

Details for the file brickly_sdk-0.6.0.tar.gz.

File metadata

  • Download URL: brickly_sdk-0.6.0.tar.gz
  • Upload date:
  • Size: 74.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for brickly_sdk-0.6.0.tar.gz
Algorithm Hash digest
SHA256 a4559cdb046eb7247860057be8c8527e14e6a97c68b5c7bb723f9fe764ea0032
MD5 61cae0f81a5b5de7eced322d00c05cd5
BLAKE2b-256 d29997dc91abbe030abf923e8eb808046c3f34c374cc8b92d0c4cbecd1017ce3

See more details on using hashes here.

File details

Details for the file brickly_sdk-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: brickly_sdk-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 88.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for brickly_sdk-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 069b5e5d801c14174a5299f10eb5832338ac532f0dc1e7c0f626db96b52b6345
MD5 242f632b715181dd162daf8f79c84d33
BLAKE2b-256 a96f8553e1e02597a965d429cf64e402a2957ce84a2490e1e608f6683a0afd42

See more details on using hashes here.

Release history Release notifications | RSS feed

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.0

2 files

This release

0.6.0 This release

2 files

0.5.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page