@zhin.js/adapter-sandbox 1.1.12 → 1.1.13

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +89 -6
  3. package/package.json +17 -17
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @zhin.js/adapter-process
2
2
 
3
+ ## 1.1.13
4
+
5
+ ### Patch Changes
6
+
7
+ - b8317b0: Document the full Sandbox WebSocket wire protocol in the README: connection paths, token and demo-scope rules, close codes, every inbound field (including `messageId`, button `action` segments and `agentRun`), and the `ready`, reply and read-only `error` frames with media segment handling.
8
+ - Updated dependencies [5be09ae]
9
+ - Updated dependencies [a3ab153]
10
+ - Updated dependencies [e8f7309]
11
+ - Updated dependencies [5afc18f]
12
+ - Updated dependencies [f30be42]
13
+ - Updated dependencies [d3563d9]
14
+ - Updated dependencies [c618eb7]
15
+ - Updated dependencies [fbfefb7]
16
+ - @zhin.js/core@1.1.47
17
+ - @zhin.js/adapter@1.1.21
18
+ - @zhin.js/client@1.1.15
19
+ - @zhin.js/feature-kit@1.1.7
20
+ - @zhin.js/im-contract@1.1.5
21
+ - @zhin.js/page@1.1.8
22
+ - @zhin.js/skill@1.1.8
23
+ - @zhin.js/host-http@1.1.8
24
+
3
25
  ## 1.1.12
4
26
 
5
27
  ### Patch Changes
package/README.md CHANGED
@@ -79,17 +79,100 @@ sandbox:
79
79
 
80
80
  浏览器客户端连接到默认 `sandbox-bot`,也可以通过多个显式 endpoint 使用不同 WebSocket 路径。
81
81
 
82
- 通过 `Router.ws("/sandbox")`(插件 `useContext("router")` 自动挂载)建立连接。
82
+ 每个 endpoint 通过 Root 提供的 HTTP Host(`httpHostToken`)挂载一个 WebSocket 路径,协议见下文「消息格式(wire 协议)」。
83
83
 
84
- ## 消息格式
84
+ ## 消息格式(wire 协议)
85
85
 
86
- Sandbox 使用 JSON 消息格式:
86
+ Console 沙盒页和自己写的测试客户端都用这套协议。每个 WebSocket 文本帧是一个 UTF-8 JSON 对象。
87
+
88
+ ### 连接
89
+
90
+ - **地址**:`ws://<host>:<port>/sandbox`。同一个 HTTP Host 上的第一个 Sandbox endpoint 挂在 `/sandbox`,其余 endpoint 挂在 `/sandbox/<endpoint id>`(重名时依次加 `-2`、`-3`),启动日志会打印 `ws mounted <path>`。
91
+ - **鉴权**:Host 配置了 token 时,握手请求需带 `Authorization: Bearer <token>` 或查询参数 `?token=<token>`,否则返回 `401`。demo 权限的 token 只能连 `/sandbox`,而且是只读的:消息会被接收,但不会进入命令和 Agent,服务端回一条 `type: "error"`。
92
+ - **单连接**:endpoint 使用固定名称(默认),同一 endpoint 只保留最新的浏览器连接。新连接接入时,旧连接以关闭码 `4000`(`replaced by new sandbox client`)断开;endpoint 停止时以 `1001` 断开;插件热重载使当前 generation 退役时,Host 以 `1012` 断开,客户端重连即可。
93
+
94
+ ### 客户端 → 服务端:发送消息
95
+
96
+ ```json
97
+ {
98
+ "type": "group",
99
+ "id": "test-group",
100
+ "content": [{ "type": "text", "data": { "text": "/hello" } }],
101
+ "messageId": "client-msg-001",
102
+ "timestamp": 1700000000000
103
+ }
104
+ ```
105
+
106
+ | 字段 | 类型 | 说明 |
107
+ | --- | --- | --- |
108
+ | `type` | `private` \| `group` \| `channel` \| `direct` \| `guild` | 会话类型,默认 `private`。`direct` 按 `private` 处理,`guild` 按 `channel` 处理 |
109
+ | `id` | string | 会话 id,默认使用 endpoint 的 `owner`(默认 `sandbox-user`) |
110
+ | `content` | string 或消息段数组 | 消息段格式为 `{ "type": string, "data": object }`;字符串等同于一个 `text` 段 |
111
+ | `text` | string | 可选。没有 `content` 时作为纯文本;`content` 里没有文本段时也用它作为消息文本 |
112
+ | `messageId` | string | 可选。客户端生成的消息 id,须匹配 `^[A-Za-z0-9._:-]{1,160}$`,不匹配时忽略;填写后作为这条入站消息的 id,引用回复时可据此定位 |
113
+ | `timestamp` | number | 可选。毫秒时间戳,默认取服务端收到的时间 |
114
+ | `agentRun` | object | 可选。Agent 试验台运行配置,见下表 |
115
+
116
+ - 帧内容不是 JSON 时,整段文本按一条纯文本消息处理。
117
+ - 消息的发送者固定为 endpoint 的 `owner`。
118
+ - **按钮回传**:`content` 中的 `{ "type": "action", "data": { "id": "...", "payload": "..." } }` 段会作为交互动作交给命令或 Agent;只填 `id` 或 `payload` 时,另一个取相同的值。消息里没有文本时,`payload` 作为消息文本。
119
+
120
+ `agentRun` 字段:
121
+
122
+ | 字段 | 取值 | 默认 |
123
+ | --- | --- | --- |
124
+ | `workingDirectory` | string,最长 4096 字符 | `""` |
125
+ | `safetyMode` | `read-only` \| `workspace-write` \| `danger-full-access` | `workspace-write` |
126
+ | `approvalMode` | `ask` \| `auto` \| `bypass` | `ask` |
127
+ | `networkAccess` | boolean | `false`;`safetyMode` 为 `danger-full-access` 时恒为 `true` |
128
+
129
+ 无法识别的取值按默认值处理。
130
+
131
+ ### 服务端 → 客户端
132
+
133
+ **连接就绪**:每次连接成功后发送一次。
134
+
135
+ ```json
136
+ {
137
+ "type": "ready",
138
+ "id": "sandbox-user",
139
+ "endpoint": "sandbox-bot",
140
+ "workingDirectory": "/path/to/bot",
141
+ "canExecute": true,
142
+ "shellIsolation": { "available": false, "provider": "docker", "message": "Docker daemon is unavailable" },
143
+ "content": [{ "type": "text", "data": { "text": "已连接 Sandbox「sandbox-bot」…" } }],
144
+ "timestamp": 1700000000000
145
+ }
146
+ ```
147
+
148
+ `canExecute` 表示当前连接是否为 full 权限(能运行命令和 Agent 任务);`shellIsolation` 是 Docker 隔离环境的探测结果,仅供展示。
149
+
150
+ **回复消息**:
151
+
152
+ ```json
153
+ {
154
+ "type": "group",
155
+ "id": "test-group",
156
+ "bot": "sandbox-bot",
157
+ "endpoint": "sandbox-bot",
158
+ "content": [{ "type": "text", "data": { "text": "Hello!" } }],
159
+ "timestamp": 1700000000001
160
+ }
161
+ ```
162
+
163
+ - `type` / `id` 是回复所在的会话(`direct` 已归一为 `private`,`guild` 已归一为 `channel`),客户端按这两个字段把消息放进对应会话;`bot` 是 endpoint id,`endpoint` 是收到消息的连接名。
164
+ - `content` 是消息段数组。文本、`html`(JSX 卡片,见上文 `html: direct`)、按钮等段原样透传。
165
+ - `image` / `audio` / `video` / `file` 段只读 `data.media`(MediaRef):`url` 原样透传;`base64` 补上 `base64://` 前缀后内联;`path` 由服务端读取文件后转成 `base64` 内联;其他类型和缺少 `data.media` 的媒体段会被丢弃,并在日志中记录 `sandbox_outbound_media_dropped`。
166
+ - 插件直接发送完整消息对象时,其他字段会原样保留。
167
+
168
+ **只读连接的提示**:demo 权限的连接发送消息后,服务端回复:
87
169
 
88
170
  ```json
89
171
  {
90
- "type": "message",
91
- "id": "msg-001",
92
- "content": "你好",
172
+ "type": "error",
173
+ "id": "sandbox-user",
174
+ "endpoint": "sandbox-bot",
175
+ "content": [{ "type": "text", "data": { "text": "当前连接是只读演示权限,不能运行 Agent 任务。" } }],
93
176
  "timestamp": 1700000000000
94
177
  }
95
178
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-sandbox",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "Zhin.js Sandbox adapter for Plugin Runtime (WebSocket /sandbox)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -47,16 +47,16 @@
47
47
  "dependencies": {
48
48
  "lucide-react": "^0.525.0",
49
49
  "react": "^19.2.8",
50
- "@zhin.js/adapter": "1.1.20",
51
- "@zhin.js/client": "1.1.14",
50
+ "@zhin.js/adapter": "1.1.21",
51
+ "@zhin.js/client": "1.1.15",
52
52
  "@zhin.js/console-contract": "1.1.2",
53
- "@zhin.js/core": "1.1.46",
54
- "@zhin.js/feature-kit": "1.1.6",
55
- "@zhin.js/host-http": "1.1.7",
56
- "@zhin.js/im-contract": "1.1.4",
53
+ "@zhin.js/core": "1.1.47",
54
+ "@zhin.js/feature-kit": "1.1.7",
55
+ "@zhin.js/host-http": "1.1.8",
56
+ "@zhin.js/im-contract": "1.1.5",
57
57
  "@zhin.js/logger": "1.1.2",
58
- "@zhin.js/page": "1.1.7",
59
- "@zhin.js/skill": "1.1.7"
58
+ "@zhin.js/page": "1.1.8",
59
+ "@zhin.js/skill": "1.1.8"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/react": "^19.2.18",
@@ -64,18 +64,18 @@
64
64
  "typescript": "^6.0.3",
65
65
  "vitest": "^4.1.10",
66
66
  "ws": "^8.21.1",
67
- "@zhin.js/pagemanager": "1.1.10",
68
- "@zhin.js/runtime": "1.1.9",
69
- "zhin.js": "1.1.11"
67
+ "@zhin.js/pagemanager": "1.1.11",
68
+ "@zhin.js/runtime": "1.1.10",
69
+ "zhin.js": "1.1.12"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "react": "^19.0.0",
73
- "@zhin.js/adapter": "^1.1.20",
73
+ "@zhin.js/adapter": "^1.1.21",
74
74
  "@zhin.js/console-contract": "^1.1.2",
75
- "@zhin.js/core": "^1.1.46",
76
- "@zhin.js/host-http": "^1.1.7",
77
- "@zhin.js/page": "^1.1.7",
78
- "zhin.js": "^1.1.11"
75
+ "@zhin.js/core": "^1.1.47",
76
+ "@zhin.js/host-http": "^1.1.8",
77
+ "@zhin.js/page": "^1.1.8",
78
+ "zhin.js": "^1.1.12"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "react": {