Skip to content

Commit ffe123d

Browse files
committed
feat(bridge): reserve channel notifications for actionable events in Claude Code bridge
Channel notifications are now only pushed for actionable events (DMs, room messages, invites) where the sender did not explicitly flag streamingBehavior: "info". Informational system events (member_joined, delivery_status, member_status, etc.) and info-hinted messages buffer locally and drain on the next tool call response, matching the pi bridge behaviour. This prevents the channel from being used as a noise pipe and reserves it for content that actually requires the model's attention.
1 parent 6ab60a7 commit ffe123d

1 file changed

Lines changed: 25 additions & 9 deletions

File tree

src/bridges/claude-code/channel.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
ensureRegistered,
2020
extractStreamingBehavior,
2121
formatDeliveryEvent,
22+
isActionableEvent,
2223
MCP_TOOL_PARAMS,
2324
} from "../../core/index.js";
2425
import { TlsTransport } from "../../core/tls-transport.js";
@@ -37,6 +38,7 @@ export async function run(): Promise<void> {
3738
store.setTransport(new TlsTransport(store.events, identity));
3839
const tool = new CommsTool(store, store.discovery);
3940
let agentId: string | undefined;
41+
const informationalBuffer: string[] = [];
4042

4143
const mcp = new McpServer(
4244
{ name: "agent-comms", version: "0.2.0" },
@@ -47,17 +49,25 @@ export async function run(): Promise<void> {
4749
},
4850
);
4951

50-
// Incoming messages arrive via TCP mesh — push as channel notifications
52+
// Actionable events with a non-info hint push immediately as channel
53+
// notifications. Everything else (informational system events, or messages
54+
// the sender flagged as info) buffers and drains on the next tool call.
5155
store.onDelivery = async (_targetId: string, event) => {
5256
const line = formatDeliveryEvent(event);
5357
const hint = extractStreamingBehavior(event);
54-
await mcp.server.notification({
55-
method: "notifications/claude/channel",
56-
params: {
57-
content: line,
58-
meta: { streamingBehavior: hint ?? "info" },
59-
},
60-
});
58+
const shouldPush = isActionableEvent(event) && hint !== "info";
59+
60+
if (shouldPush) {
61+
await mcp.server.notification({
62+
method: "notifications/claude/channel",
63+
params: {
64+
content: line,
65+
meta: { streamingBehavior: hint ?? "steer" },
66+
},
67+
});
68+
} else {
69+
informationalBuffer.push(line);
70+
}
6171
};
6272

6373
// -----------------------------------------------------------------------
@@ -104,8 +114,14 @@ export async function run(): Promise<void> {
104114
action,
105115
);
106116

117+
const pending = informationalBuffer.splice(0);
118+
const prefix =
119+
pending.length > 0
120+
? `[comms] Pending:\n${pending.map((l) => ` 📬 ${l}`).join("\n")}\n\n`
121+
: "";
122+
107123
return {
108-
content: [{ type: "text", text: result.content }],
124+
content: [{ type: "text", text: `${prefix}${result.content}` }],
109125
isError: result.isError,
110126
};
111127
},

0 commit comments

Comments
 (0)