brickly-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ .mypy_cache/
5
+ dist/
6
+ build/
7
+ *.egg-info/
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: brickly-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Brickly brick runtimes.
5
+ Author: Brickly
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+
10
+ # brickly-sdk-python
11
+
12
+ Python SDK for Brickly brick runtimes. It speaks BPP over stdin/stdout and keeps stdout reserved for protocol messages.
13
+
14
+ ## Quick Start
15
+
16
+ ```python
17
+ from brickly import BricklyRuntime
18
+
19
+ brick = BricklyRuntime("com.example.python")
20
+
21
+
22
+ @brick.on_command("hello")
23
+ def hello(ctx, input):
24
+ ctx.progress(0.5, "working...")
25
+ ctx.chunk("hello\n")
26
+ return {"ok": True, "input": input}
27
+
28
+
29
+ brick.run()
30
+ ```
31
+
32
+ The SDK handles:
33
+
34
+ - `host.hello` -> `runtime.ready`
35
+ - `runtime.ping` -> `runtime.pong`
36
+ - `command.invoke` dispatch
37
+ - `command.cancel` via `ctx.cancel_event`, `ctx.is_cancelled()`, and `ctx.on_cancel(...)`
38
+ - `command.progress`, `command.chunk`, and `command.output`
39
+ - `host.*` request id allocation and `host.result` / `host.error` routing
40
+ - `runtime.shutdown` -> optional shutdown hook -> `runtime.bye`
41
+ - `ui.create_browser_window`, `WindowHandle.call(...)`, and event routing for `window.*`
42
+ - `events.publish(...)` and `events.on(...)`
43
+ - `brick.platform.system.*` / `ctx.platform.system.*`, plus `brick.system.*` / `ctx.system.*` aliases
44
+ - `brick.invoke(...)` / `ctx.invoke(...)` for child cross-brick command calls inside command scope
45
+ - `brick.invoke_root(...)` for root cross-brick command calls outside command scope
46
+ - `brick.invoke_stream(...)` / `ctx.invoke_stream(...)` for streaming child cross-brick command calls
47
+ - `brick.open_session(...)` / `ctx.open_session(...)` for stateful cross-brick sessions
48
+ - `brick.platform.clipboard.read_content()` / `set_content(...)`
49
+
50
+ ## Logging
51
+
52
+ `brick.log(...)` writes plain messages to stderr. Stdout is reserved for BPP protocol messages. The Brickly host log center attaches the brick id, source, stream, and scope metadata when collecting stderr, so brick code should not add a `[brickId]` prefix by itself.
53
+
54
+ ## Window Example
55
+
56
+ ```python
57
+ from brickly import BricklyRuntime
58
+
59
+ brick = BricklyRuntime("com.example.window")
60
+
61
+
62
+ @brick.on_command("open")
63
+ def open_window(ctx, input):
64
+ win = ctx.ui.create_browser_window("ui/index.html", {"width": 640, "height": 480})
65
+ win.on("closed", lambda payload: brick.log("closed", payload))
66
+ win.set_title("Hello from Python")
67
+ return {"windowId": win.id}
68
+
69
+
70
+ brick.run()
71
+ ```
72
+
73
+ ## Cross-Brick Invoke
74
+
75
+ Inside a command handler, use `ctx.invoke` to call another brick command. The SDK automatically sends the current `parentRequestId`, so the host attaches the child call to the same invocation graph. Brickly starts, reuses, and recycles the target brick instance automatically. Pass `profile_id` when the target brick should run with a specific Profile; omit it to use the target brick's default Profile.
76
+
77
+ ```python
78
+ result = ctx.invoke(
79
+ "com.brickly.openai",
80
+ "chat",
81
+ {"prompt": "hello"},
82
+ profile_id="work",
83
+ )
84
+ ```
85
+
86
+ Use `invoke_stream` when the target command emits progress, chunks, or named outputs before its final result. The SDK sends `host.invoke` with `stream: true` and yields events in host order:
87
+
88
+ ```python
89
+ for event in ctx.invoke_stream("com.brickly.openai", "chat", {"prompt": "hello"}):
90
+ if event["type"] == "progress":
91
+ ctx.progress(event.get("progress", 0), event.get("message"))
92
+ elif event["type"] == "chunk":
93
+ ctx.chunk(event.get("chunk"))
94
+ elif event["type"] == "output":
95
+ ctx.output(event["name"], event.get("value"))
96
+ elif event["type"] == "result":
97
+ return event["result"]
98
+ ```
99
+
100
+ If the host returns `host.error`, `invoke_stream` raises `BppError`, matching normal `invoke` error handling.
101
+
102
+ To create a top-level cross-brick call outside command scope, use the explicit root API:
103
+
104
+ ```python
105
+ result = brick.invoke_root(
106
+ "com.brickly.openai",
107
+ "chat",
108
+ {"prompt": "hello"},
109
+ profile_id="work",
110
+ )
111
+ ```
112
+
113
+ The caller manifest must declare the target brick and allowed commands in `dependencies`:
114
+
115
+ ```json
116
+ "dependencies": {
117
+ "com.brickly.openai": {
118
+ "commands": ["chat"]
119
+ }
120
+ }
121
+ ```
122
+
123
+ ## Platform System API
124
+
125
+ `brick.platform.system.*`, `brick.system.*`, `ctx.platform.system.*`, and `ctx.system.*` call host system capabilities through BPP `host.platform.system.*`:
126
+
127
+ ```python
128
+ @brick.on_command("show-app-info")
129
+ def show_app_info(ctx, _input):
130
+ return {
131
+ "appName": ctx.system.get_app_name(),
132
+ "appVersion": ctx.system.get_app_version(),
133
+ "userData": ctx.system.get_path("userData"),
134
+ "isMacOS": ctx.system.is_macos(),
135
+ }
136
+ ```
137
+
138
+ Current methods are `show_notification`, `shell_open_path`, `shell_trash_item`, `shell_show_item_in_folder`, `shell_open_external`, `shell_beep`, `get_native_id`, `get_app_name`, `get_app_version`, `get_path`, `get_file_icon`, `read_current_folder_path`, `read_current_browser_url`, `is_dev`, `is_macos`, `is_windows`, and `is_linux`.
139
+
140
+ `get_path()` supports `home`, `appData`, `assets`, `userData`, `sessionData`, `temp`, `exe`, `module`, `desktop`, `documents`, `downloads`, `music`, `pictures`, `videos`, `recent`, `logs`, and `crashDumps`. Runtime calls are still checked by manifest permissions on the host side: notifications require `os.notification`; Shell capabilities require `os.exec`; app info, paths, native ID, platform checks, and current folder path reads require `os.env`; file icons require `fs.read`. `read_current_folder_path()` works when Finder is frontmost on macOS or Explorer is frontmost on Windows; it raises `CURRENT_FOLDER_UNAVAILABLE` when no readable foreground file-manager folder is available. `read_current_browser_url()` is reserved and currently returns `UNSUPPORTED_PLATFORM`.
141
+
142
+ ## Platform Clipboard API
143
+
144
+ `brick.platform.clipboard.*` and `ctx.platform.clipboard.*` call host clipboard capabilities through BPP `host.platform.clipboard.*`:
145
+
146
+ ```python
147
+ @brick.on_command("replace-clipboard")
148
+ def replace_clipboard(ctx, _input):
149
+ previous = ctx.platform.clipboard.read_content()
150
+ updated = ctx.platform.clipboard.set_content({"kind": "text", "text": "Updated by Python"})
151
+ return {"previous": previous, "updated": updated}
152
+ ```
153
+
154
+ Current methods are `read_content()` and `set_content(content)`.
155
+
156
+ ## Cross-Brick Sessions
157
+
158
+ Use `ctx.open_session` when the target brick keeps in-memory state that must survive across multiple command calls. Calls through the same session are routed to the same target brick instance, and each `session.invoke` automatically carries the current `parentRequestId`, until `close()` is called or the caller brick instance exits.
159
+
160
+ ```python
161
+ session = ctx.open_session("com.brickly.openai", profile_id="work")
162
+
163
+ try:
164
+ session.invoke("start-thread", {"title": "Draft"})
165
+ reply = session.invoke("chat", {"prompt": "continue the thread"})
166
+ finally:
167
+ session.close()
168
+ ```
169
+
170
+ `profile_id` is the target brick Profile ID. Session invokes are checked against the caller manifest's `dependencies[target].commands` on every command call.
171
+
172
+ ## Errors
173
+
174
+ Raise `BppError` to preserve a specific Brickly error code:
175
+
176
+ ```python
177
+ from brickly import BppError
178
+
179
+ raise BppError("INVALID_INPUT", "url is required")
180
+ ```
@@ -0,0 +1,171 @@
1
+ # brickly-sdk-python
2
+
3
+ Python SDK for Brickly brick runtimes. It speaks BPP over stdin/stdout and keeps stdout reserved for protocol messages.
4
+
5
+ ## Quick Start
6
+
7
+ ```python
8
+ from brickly import BricklyRuntime
9
+
10
+ brick = BricklyRuntime("com.example.python")
11
+
12
+
13
+ @brick.on_command("hello")
14
+ def hello(ctx, input):
15
+ ctx.progress(0.5, "working...")
16
+ ctx.chunk("hello\n")
17
+ return {"ok": True, "input": input}
18
+
19
+
20
+ brick.run()
21
+ ```
22
+
23
+ The SDK handles:
24
+
25
+ - `host.hello` -> `runtime.ready`
26
+ - `runtime.ping` -> `runtime.pong`
27
+ - `command.invoke` dispatch
28
+ - `command.cancel` via `ctx.cancel_event`, `ctx.is_cancelled()`, and `ctx.on_cancel(...)`
29
+ - `command.progress`, `command.chunk`, and `command.output`
30
+ - `host.*` request id allocation and `host.result` / `host.error` routing
31
+ - `runtime.shutdown` -> optional shutdown hook -> `runtime.bye`
32
+ - `ui.create_browser_window`, `WindowHandle.call(...)`, and event routing for `window.*`
33
+ - `events.publish(...)` and `events.on(...)`
34
+ - `brick.platform.system.*` / `ctx.platform.system.*`, plus `brick.system.*` / `ctx.system.*` aliases
35
+ - `brick.invoke(...)` / `ctx.invoke(...)` for child cross-brick command calls inside command scope
36
+ - `brick.invoke_root(...)` for root cross-brick command calls outside command scope
37
+ - `brick.invoke_stream(...)` / `ctx.invoke_stream(...)` for streaming child cross-brick command calls
38
+ - `brick.open_session(...)` / `ctx.open_session(...)` for stateful cross-brick sessions
39
+ - `brick.platform.clipboard.read_content()` / `set_content(...)`
40
+
41
+ ## Logging
42
+
43
+ `brick.log(...)` writes plain messages to stderr. Stdout is reserved for BPP protocol messages. The Brickly host log center attaches the brick id, source, stream, and scope metadata when collecting stderr, so brick code should not add a `[brickId]` prefix by itself.
44
+
45
+ ## Window Example
46
+
47
+ ```python
48
+ from brickly import BricklyRuntime
49
+
50
+ brick = BricklyRuntime("com.example.window")
51
+
52
+
53
+ @brick.on_command("open")
54
+ def open_window(ctx, input):
55
+ win = ctx.ui.create_browser_window("ui/index.html", {"width": 640, "height": 480})
56
+ win.on("closed", lambda payload: brick.log("closed", payload))
57
+ win.set_title("Hello from Python")
58
+ return {"windowId": win.id}
59
+
60
+
61
+ brick.run()
62
+ ```
63
+
64
+ ## Cross-Brick Invoke
65
+
66
+ Inside a command handler, use `ctx.invoke` to call another brick command. The SDK automatically sends the current `parentRequestId`, so the host attaches the child call to the same invocation graph. Brickly starts, reuses, and recycles the target brick instance automatically. Pass `profile_id` when the target brick should run with a specific Profile; omit it to use the target brick's default Profile.
67
+
68
+ ```python
69
+ result = ctx.invoke(
70
+ "com.brickly.openai",
71
+ "chat",
72
+ {"prompt": "hello"},
73
+ profile_id="work",
74
+ )
75
+ ```
76
+
77
+ Use `invoke_stream` when the target command emits progress, chunks, or named outputs before its final result. The SDK sends `host.invoke` with `stream: true` and yields events in host order:
78
+
79
+ ```python
80
+ for event in ctx.invoke_stream("com.brickly.openai", "chat", {"prompt": "hello"}):
81
+ if event["type"] == "progress":
82
+ ctx.progress(event.get("progress", 0), event.get("message"))
83
+ elif event["type"] == "chunk":
84
+ ctx.chunk(event.get("chunk"))
85
+ elif event["type"] == "output":
86
+ ctx.output(event["name"], event.get("value"))
87
+ elif event["type"] == "result":
88
+ return event["result"]
89
+ ```
90
+
91
+ If the host returns `host.error`, `invoke_stream` raises `BppError`, matching normal `invoke` error handling.
92
+
93
+ To create a top-level cross-brick call outside command scope, use the explicit root API:
94
+
95
+ ```python
96
+ result = brick.invoke_root(
97
+ "com.brickly.openai",
98
+ "chat",
99
+ {"prompt": "hello"},
100
+ profile_id="work",
101
+ )
102
+ ```
103
+
104
+ The caller manifest must declare the target brick and allowed commands in `dependencies`:
105
+
106
+ ```json
107
+ "dependencies": {
108
+ "com.brickly.openai": {
109
+ "commands": ["chat"]
110
+ }
111
+ }
112
+ ```
113
+
114
+ ## Platform System API
115
+
116
+ `brick.platform.system.*`, `brick.system.*`, `ctx.platform.system.*`, and `ctx.system.*` call host system capabilities through BPP `host.platform.system.*`:
117
+
118
+ ```python
119
+ @brick.on_command("show-app-info")
120
+ def show_app_info(ctx, _input):
121
+ return {
122
+ "appName": ctx.system.get_app_name(),
123
+ "appVersion": ctx.system.get_app_version(),
124
+ "userData": ctx.system.get_path("userData"),
125
+ "isMacOS": ctx.system.is_macos(),
126
+ }
127
+ ```
128
+
129
+ Current methods are `show_notification`, `shell_open_path`, `shell_trash_item`, `shell_show_item_in_folder`, `shell_open_external`, `shell_beep`, `get_native_id`, `get_app_name`, `get_app_version`, `get_path`, `get_file_icon`, `read_current_folder_path`, `read_current_browser_url`, `is_dev`, `is_macos`, `is_windows`, and `is_linux`.
130
+
131
+ `get_path()` supports `home`, `appData`, `assets`, `userData`, `sessionData`, `temp`, `exe`, `module`, `desktop`, `documents`, `downloads`, `music`, `pictures`, `videos`, `recent`, `logs`, and `crashDumps`. Runtime calls are still checked by manifest permissions on the host side: notifications require `os.notification`; Shell capabilities require `os.exec`; app info, paths, native ID, platform checks, and current folder path reads require `os.env`; file icons require `fs.read`. `read_current_folder_path()` works when Finder is frontmost on macOS or Explorer is frontmost on Windows; it raises `CURRENT_FOLDER_UNAVAILABLE` when no readable foreground file-manager folder is available. `read_current_browser_url()` is reserved and currently returns `UNSUPPORTED_PLATFORM`.
132
+
133
+ ## Platform Clipboard API
134
+
135
+ `brick.platform.clipboard.*` and `ctx.platform.clipboard.*` call host clipboard capabilities through BPP `host.platform.clipboard.*`:
136
+
137
+ ```python
138
+ @brick.on_command("replace-clipboard")
139
+ def replace_clipboard(ctx, _input):
140
+ previous = ctx.platform.clipboard.read_content()
141
+ updated = ctx.platform.clipboard.set_content({"kind": "text", "text": "Updated by Python"})
142
+ return {"previous": previous, "updated": updated}
143
+ ```
144
+
145
+ Current methods are `read_content()` and `set_content(content)`.
146
+
147
+ ## Cross-Brick Sessions
148
+
149
+ Use `ctx.open_session` when the target brick keeps in-memory state that must survive across multiple command calls. Calls through the same session are routed to the same target brick instance, and each `session.invoke` automatically carries the current `parentRequestId`, until `close()` is called or the caller brick instance exits.
150
+
151
+ ```python
152
+ session = ctx.open_session("com.brickly.openai", profile_id="work")
153
+
154
+ try:
155
+ session.invoke("start-thread", {"title": "Draft"})
156
+ reply = session.invoke("chat", {"prompt": "continue the thread"})
157
+ finally:
158
+ session.close()
159
+ ```
160
+
161
+ `profile_id` is the target brick Profile ID. Session invokes are checked against the caller manifest's `dependencies[target].commands` on every command call.
162
+
163
+ ## Errors
164
+
165
+ Raise `BppError` to preserve a specific Brickly error code:
166
+
167
+ ```python
168
+ from brickly import BppError
169
+
170
+ raise BppError("INVALID_INPUT", "url is required")
171
+ ```
@@ -0,0 +1,31 @@
1
+ from .api import (
2
+ BricklyRuntime,
3
+ CommandContext,
4
+ EventEnvelope,
5
+ EventsApi,
6
+ UiApi,
7
+ WebContentsApi,
8
+ WindowHandle,
9
+ )
10
+ from .errors import BppError, payload_to_error
11
+ from .protocol import PROTOCOL_VERSION, PlatformSystemPathName
12
+ from .runtime import BppTransport
13
+ from .system import ClipboardApi, PlatformApi, SystemApi
14
+
15
+ __all__ = [
16
+ "BppError",
17
+ "BppTransport",
18
+ "BricklyRuntime",
19
+ "ClipboardApi",
20
+ "CommandContext",
21
+ "EventEnvelope",
22
+ "EventsApi",
23
+ "PlatformApi",
24
+ "PROTOCOL_VERSION",
25
+ "PlatformSystemPathName",
26
+ "SystemApi",
27
+ "UiApi",
28
+ "WebContentsApi",
29
+ "WindowHandle",
30
+ "payload_to_error",
31
+ ]