@buz-extensions/buz 1.0.0-beta.15 → 1.0.0-beta.17

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buz-extensions/buz",
3
- "version": "1.0.0-beta.15",
3
+ "version": "1.0.0-beta.17",
4
4
  "description": "OpenClaw buz channel plugin",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/proto/buz.proto CHANGED
@@ -26,35 +26,33 @@ message BridgeToClientMessage {
26
26
  }
27
27
  }
28
28
 
29
- // --- 详细子结构 ---
30
-
31
29
  message AuthRequest {
32
- string secret_key = 1; // 用户在 OpenClaw 输入的接入凭证
33
- string openclaw_id = 2; // [可选] 客户端唯一标识
30
+ string secret_key = 1;
31
+ string openclaw_id = 2;
34
32
  }
35
33
 
36
34
  message AuthResponse {
37
35
  bool success = 1;
38
36
  string error_message = 2;
39
- string account_id = 3; // 绑定成功的 IM 账户 ID
37
+ string account_id = 3;
40
38
  }
41
39
 
42
40
  message InboundMessage {
43
- string message_id = 1; // IM 侧的全局消息 ID
44
- string sender_id = 2; // 发送者 ID
45
- string sender_name = 3; // 发送者昵称
46
- string chat_type = 4; // 枚举: "direct"(单聊), "group"(群聊)
47
- string group_id = 5; // 如果是群聊,群 ID
48
- string content_text = 6; // 文本内容
49
- // 可扩展媒体字段 (media_url 等)
41
+ string message_id = 1;
42
+ string sender_id = 2;
43
+ string sender_name = 3;
44
+ string chat_type = 4;
45
+ string group_id = 5;
46
+ string content_text = 6;
50
47
  }
51
48
 
52
49
  message OutboundMessage {
53
- string reply_to_id = 1; // 回复的目标消息 ID (Thread 追踪)
54
- string target_id = 2; // 接收方 ID (用户 ID 或 群组 ID)
55
- string chat_type = 3; // "direct" 或 "group"
56
- string content_text = 4; // AI 生成的回复文本
57
- // 可扩展媒体字段
50
+ string reply_to_id = 1;
51
+ string target_id = 2;
52
+ string chat_type = 3;
53
+ string content_text = 4;
54
+ string type = 5; // final_reply / partial_reply / reasoning / tool_start / assistant_message_start / status
55
+ string event = 6; // start / delta / done
58
56
  }
59
57
 
60
58
  message HeartbeatPing {
package/src/inbound.ts CHANGED
@@ -15,8 +15,8 @@ function resolveDefaultAgentIdCompat(cfg: any): string {
15
15
  }
16
16
 
17
17
  function resolveStorePath(cfg: any, agentId: string): string {
18
- const core = getBuzRuntime();
19
- const resolver = core?.channel?.session?.resolveStorePath;
18
+ const runtime = getBuzRuntime();
19
+ const resolver = runtime?.channel?.session?.resolveStorePath;
20
20
  if (typeof resolver === "function") {
21
21
  return resolver(cfg?.session?.store, { agentId });
22
22
  }
@@ -49,6 +49,28 @@ function buildSessionKey(params: {
49
49
  return `agent:${agentId}:buz:${accountId}:${isGroup ? "group" : "direct"}:${conversationId}`;
50
50
  }
51
51
 
52
+ async function emitIntermediate(params: {
53
+ toTarget: string;
54
+ accountId: string;
55
+ messageSid: string;
56
+ type: string;
57
+ event: string;
58
+ text?: string;
59
+ }) {
60
+ const { toTarget, accountId, messageSid, type, event, text } = params;
61
+ if (!text && type !== "assistant_message_start") {
62
+ return;
63
+ }
64
+ await sendText({
65
+ to: toTarget,
66
+ text: text || "",
67
+ accountId,
68
+ replyToId: messageSid,
69
+ type,
70
+ event,
71
+ });
72
+ }
73
+
52
74
  export async function handleInboundMessage(ctx: any, inboundMsg: any) {
53
75
  console.log("[buz inbound] =========================================");
54
76
  console.log("[buz inbound] handleInboundMessage called");
@@ -57,7 +79,7 @@ export async function handleInboundMessage(ctx: any, inboundMsg: any) {
57
79
 
58
80
  const accountId = ctx.account.accountId;
59
81
  const cfg = ctx.cfg;
60
- const core = getBuzRuntime().core;
82
+ const core = getBuzRuntime();
61
83
  const agentId = resolveDefaultAgentIdCompat(cfg);
62
84
 
63
85
  console.log("[buz inbound] accountId:", accountId);
@@ -138,6 +160,8 @@ export async function handleInboundMessage(ctx: any, inboundMsg: any) {
138
160
  text: payload.text,
139
161
  accountId,
140
162
  replyToId: messageSid,
163
+ type: payload?.isReasoning ? "reasoning" : "final_reply",
164
+ event: "done",
141
165
  });
142
166
  console.log("[buz inbound] reply sent successfully via gRPC");
143
167
  },
@@ -148,7 +172,59 @@ export async function handleInboundMessage(ctx: any, inboundMsg: any) {
148
172
  console.error(`[buz inbound] ${info?.kind || "unknown"} reply failed:`, err);
149
173
  },
150
174
  replyOptions: {
151
- disableBlockStreaming: true,
175
+ disableBlockStreaming: false,
176
+ onPartialReply: async (payload: any) => {
177
+ await emitIntermediate({
178
+ toTarget,
179
+ accountId,
180
+ messageSid,
181
+ type: "partial_reply",
182
+ event: "delta",
183
+ text: payload?.text,
184
+ });
185
+ },
186
+ onReasoningStream: async (payload: any) => {
187
+ await emitIntermediate({
188
+ toTarget,
189
+ accountId,
190
+ messageSid,
191
+ type: "reasoning",
192
+ event: "delta",
193
+ text: payload?.text,
194
+ });
195
+ },
196
+ onAssistantMessageStart: async () => {
197
+ await emitIntermediate({
198
+ toTarget,
199
+ accountId,
200
+ messageSid,
201
+ type: "assistant_message_start",
202
+ event: "start",
203
+ text: "",
204
+ });
205
+ },
206
+ onReasoningEnd: async () => {
207
+ await emitIntermediate({
208
+ toTarget,
209
+ accountId,
210
+ messageSid,
211
+ type: "reasoning",
212
+ event: "done",
213
+ text: "",
214
+ });
215
+ },
216
+ onToolStart: async (payload: any) => {
217
+ const toolName = String(payload?.name || "tool").trim() || "tool";
218
+ const phase = String(payload?.phase || "start").trim() || "start";
219
+ await emitIntermediate({
220
+ toTarget,
221
+ accountId,
222
+ messageSid,
223
+ type: "tool_start",
224
+ event: "start",
225
+ text: `${toolName}${phase ? ` (${phase})` : ""}`,
226
+ });
227
+ },
152
228
  },
153
229
  });
154
230
 
package/src/outbound.ts CHANGED
@@ -1,20 +1,43 @@
1
1
  import { activeStreams } from "./gateway.js";
2
2
 
3
+ function resolveTarget(to: string) {
4
+ let chatType = "direct";
5
+ let targetId = to;
6
+
7
+ if (to.startsWith("buz:")) {
8
+ targetId = to.substring("buz:".length);
9
+ }
10
+
11
+ if (targetId.startsWith("group:")) {
12
+ chatType = "group";
13
+ targetId = targetId.substring("group:".length);
14
+ if (targetId.includes(":")) {
15
+ targetId = targetId.split(":")[0];
16
+ }
17
+ } else if (targetId.startsWith("user:")) {
18
+ targetId = targetId.substring("user:".length);
19
+ }
20
+
21
+ return { chatType, targetId };
22
+ }
23
+
3
24
  export async function sendText(params: any) {
4
- const { to, text, accountId, replyToId } = params;
25
+ const { to, text, accountId, replyToId, type = "final_reply", event } = params;
5
26
 
6
27
  console.log("[buz outbound] =========================================");
7
28
  console.log("[buz outbound] sendText called");
8
29
  console.log("[buz outbound] to:", to);
9
- console.log("[buz outbound] text preview:", text?.substring(0, 100));
30
+ console.log("[buz outbound] type:", type);
31
+ console.log("[buz outbound] event:", event);
32
+ console.log("[buz outbound] text preview:", text?.substring?.(0, 100));
10
33
  console.log("[buz outbound] text length:", text?.length);
11
34
  console.log("[buz outbound] accountId:", accountId);
12
35
  console.log("[buz outbound] replyToId:", replyToId);
13
36
 
14
37
  const targetAccountId = accountId || "default";
15
- console.log("[buz outbound] targetAccountId:", targetAccountId);
16
-
17
38
  const stream = activeStreams.get(targetAccountId);
39
+
40
+ console.log("[buz outbound] targetAccountId:", targetAccountId);
18
41
  console.log("[buz outbound] activeStreams size:", activeStreams.size);
19
42
  console.log("[buz outbound] stream found:", !!stream);
20
43
 
@@ -24,38 +47,16 @@ export async function sendText(params: any) {
24
47
  throw new Error(`[buz] No active gRPC stream for account ${targetAccountId}`);
25
48
  }
26
49
 
27
- // to format might be: "buz:group:GROUP_ID" or "buz:USER_ID"
28
- // based on inbound parsing or explicit routing
29
- let chatType = "direct";
30
- let targetId = to;
31
-
32
- console.log("[buz outbound] parsing target:", to);
33
-
34
- if (to.startsWith("buz:")) {
35
- targetId = to.substring("buz:".length);
36
- console.log("[buz outbound] removed 'buz:' prefix, targetId:", targetId);
37
- }
38
-
39
- if (targetId.startsWith("group:")) {
40
- chatType = "group";
41
- targetId = targetId.substring("group:".length);
42
- console.log("[buz outbound] detected group chat, targetId:", targetId);
43
- // if targetId has a suffix like :sender_id, remove it for group target
44
- if (targetId.includes(":")) {
45
- targetId = targetId.split(":")[0];
46
- console.log("[buz outbound] removed sender suffix, final targetId:", targetId);
47
- }
48
- } else if (targetId.startsWith("user:")) {
49
- targetId = targetId.substring("user:".length);
50
- console.log("[buz outbound] removed 'user:' prefix, targetId:", targetId);
51
- }
50
+ const { chatType, targetId } = resolveTarget(to);
52
51
 
53
52
  const outboundMsg = {
54
53
  outbound_msg: {
55
54
  reply_to_id: replyToId || "",
56
55
  target_id: targetId,
57
56
  chat_type: chatType,
58
- content_text: text,
57
+ content_text: text || "",
58
+ type,
59
+ event: event || "",
59
60
  },
60
61
  };
61
62
 
@@ -69,6 +70,5 @@ export async function sendText(params: any) {
69
70
  throw err;
70
71
  }
71
72
 
72
- const result = { messageId: `msg-${Date.now()}`, chatId: to };
73
- return result;
73
+ return { messageId: `msg-${Date.now()}`, chatId: to, type, event };
74
74
  }