@mutirolabs/openclaw-brain 0.1.1 → 0.2.1
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/CHANGELOG.md +70 -3
- package/README.md +44 -217
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/src/actions.js +40 -0
- package/dist/src/actions.js.map +1 -0
- package/dist/src/agent-tools.js +547 -0
- package/dist/src/agent-tools.js.map +1 -0
- package/dist/src/bridge-client.js +172 -0
- package/dist/src/bridge-client.js.map +1 -0
- package/dist/src/bridge-messages.js +226 -0
- package/dist/src/bridge-messages.js.map +1 -0
- package/dist/src/bridge-protocol.js +42 -0
- package/dist/src/bridge-protocol.js.map +1 -0
- package/dist/src/bridge-session.js +279 -0
- package/dist/src/bridge-session.js.map +1 -0
- package/dist/src/channel.js +167 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/channel.runtime.js +422 -0
- package/dist/src/channel.runtime.js.map +1 -0
- package/dist/src/config.js +61 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/inbound.js +92 -0
- package/dist/src/inbound.js.map +1 -0
- package/dist/src/live-snapshot.js +151 -0
- package/dist/src/live-snapshot.js.map +1 -0
- package/dist/src/outbound.js +205 -0
- package/dist/src/outbound.js.map +1 -0
- package/dist/src/setup-surface.js +252 -0
- package/dist/src/setup-surface.js.map +1 -0
- package/dist/src/signal-forwarder.js +119 -0
- package/dist/src/signal-forwarder.js.map +1 -0
- package/docs/assets/mutiro-openclaw-ui.png +0 -0
- package/docs/guides/manage-allowlist.md +3 -3
- package/docs/guides/use-openclaw-as-brain.md +15 -15
- package/index.ts +1 -1
- package/openclaw.plugin.json +5 -3
- package/package.json +9 -7
- package/src/agent-tools.ts +3 -3
- package/src/bridge-client.ts +1 -2
- package/src/bridge-messages.ts +2 -2
- package/src/bridge-protocol.ts +2 -2
- package/src/bridge-session.ts +2 -2
- package/src/channel.runtime.ts +54 -3
- package/src/channel.ts +61 -2
- package/src/outbound.ts +5 -7
- package/src/setup-surface.ts +39 -11
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// NDJSON envelope codec + subprocess manager for the Mutiro chatbridge.
|
|
2
|
+
// Kept transport-shaped so the rest of the plugin can treat the bridge as a
|
|
3
|
+
// request/response channel regardless of which brain is on the other side.
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import * as readline from "node:readline";
|
|
6
|
+
import { PROTOCOL_VERSION, TYPE_URLS, generateId, } from "./bridge-protocol.js";
|
|
7
|
+
const defaultLogger = {
|
|
8
|
+
info: (msg) => console.log(`[openclaw-mutiro] ${msg}`),
|
|
9
|
+
warn: (msg) => console.warn(`[openclaw-mutiro] ${msg}`),
|
|
10
|
+
error: (msg) => console.error(`[openclaw-mutiro] ${msg}`),
|
|
11
|
+
};
|
|
12
|
+
// In bridge mode the Mutiro host writes slog JSON records to stderr. Parse
|
|
13
|
+
// each line and route it through the OpenClaw channel logger so the output
|
|
14
|
+
// matches the rest of the gateway's log stream instead of leaking the raw
|
|
15
|
+
// Go-side format.
|
|
16
|
+
const HOST_ATTR_DROP = new Set(["time", "level", "msg", "component", "agent_username"]);
|
|
17
|
+
const formatAttrValue = (value) => {
|
|
18
|
+
if (value === null || value === undefined)
|
|
19
|
+
return "";
|
|
20
|
+
if (typeof value === "string")
|
|
21
|
+
return value;
|
|
22
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.stringify(value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return String(value);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const normalizeHostLogLine = (raw) => {
|
|
33
|
+
const trimmed = raw.trim();
|
|
34
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(trimmed);
|
|
37
|
+
if (parsed && typeof parsed.msg === "string") {
|
|
38
|
+
const rawLevel = typeof parsed.level === "string" ? parsed.level.toLowerCase() : "info";
|
|
39
|
+
const level = rawLevel === "error"
|
|
40
|
+
? "error"
|
|
41
|
+
: rawLevel === "warn" || rawLevel === "warning"
|
|
42
|
+
? "warn"
|
|
43
|
+
: "info";
|
|
44
|
+
const attrs = Object.entries(parsed)
|
|
45
|
+
.filter(([key]) => !HOST_ATTR_DROP.has(key))
|
|
46
|
+
.map(([key, value]) => `${key}=${formatAttrValue(value)}`)
|
|
47
|
+
.filter((entry) => entry.length > `=`.length + 1);
|
|
48
|
+
const detail = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
49
|
+
return { level, text: `host: ${parsed.msg}${detail}` };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// fall through to raw passthrough
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { level: "info", text: `host: ${trimmed}` };
|
|
57
|
+
};
|
|
58
|
+
export const createHostProcess = (options) => {
|
|
59
|
+
const logger = options.logger ?? defaultLogger;
|
|
60
|
+
const hostProcess = spawn("mutiro", ["agent", "host", "--mode=bridge"], {
|
|
61
|
+
cwd: options.agentDir,
|
|
62
|
+
env: options.env ?? process.env,
|
|
63
|
+
});
|
|
64
|
+
const stderrReader = readline.createInterface({
|
|
65
|
+
input: hostProcess.stderr,
|
|
66
|
+
terminal: false,
|
|
67
|
+
});
|
|
68
|
+
stderrReader.on("line", (line) => {
|
|
69
|
+
if (!line.trim())
|
|
70
|
+
return;
|
|
71
|
+
const { level, text } = normalizeHostLogLine(line);
|
|
72
|
+
if (level === "error")
|
|
73
|
+
logger.error(text);
|
|
74
|
+
else if (level === "warn")
|
|
75
|
+
logger.warn(text);
|
|
76
|
+
else
|
|
77
|
+
logger.info(text);
|
|
78
|
+
});
|
|
79
|
+
hostProcess.on("exit", (code) => {
|
|
80
|
+
stderrReader.close();
|
|
81
|
+
logger.info(`mutiro host exited with code ${code}`);
|
|
82
|
+
options.onExit?.(code ?? null);
|
|
83
|
+
});
|
|
84
|
+
return hostProcess;
|
|
85
|
+
};
|
|
86
|
+
export const createBridgeClient = (hostProcess) => {
|
|
87
|
+
// Bridge requests are ordinary NDJSON envelopes with request/response
|
|
88
|
+
// correlation on request_id. Visible chat replies are *not* the response to
|
|
89
|
+
// message.observed; they are separate outbound bridge requests.
|
|
90
|
+
const pendingRequests = new Map();
|
|
91
|
+
const send = (type, payload, extras = {}) => {
|
|
92
|
+
const envelope = {
|
|
93
|
+
protocol_version: PROTOCOL_VERSION,
|
|
94
|
+
type,
|
|
95
|
+
request_id: extras.request_id || generateId(),
|
|
96
|
+
payload,
|
|
97
|
+
...extras,
|
|
98
|
+
};
|
|
99
|
+
hostProcess.stdin.write(`${JSON.stringify(envelope)}\n`);
|
|
100
|
+
};
|
|
101
|
+
const request = (type, payload, extras = {}) => new Promise((resolve, reject) => {
|
|
102
|
+
const requestId = generateId();
|
|
103
|
+
pendingRequests.set(requestId, {
|
|
104
|
+
resolve: resolve,
|
|
105
|
+
reject,
|
|
106
|
+
});
|
|
107
|
+
send(type, payload, { ...extras, request_id: requestId });
|
|
108
|
+
});
|
|
109
|
+
const ack = (requestId, payloadType) => {
|
|
110
|
+
// Acknowledge host-owned request delivery. This is separate from sending a
|
|
111
|
+
// user-visible message back into Mutiro.
|
|
112
|
+
send("command_result", {
|
|
113
|
+
"@type": TYPE_URLS.bridgeCommandResult,
|
|
114
|
+
ok: true,
|
|
115
|
+
response: { "@type": payloadType },
|
|
116
|
+
}, { request_id: requestId });
|
|
117
|
+
};
|
|
118
|
+
const resolveResponse = (requestId, payload) => {
|
|
119
|
+
if (!requestId || !pendingRequests.has(requestId))
|
|
120
|
+
return false;
|
|
121
|
+
const pending = pendingRequests.get(requestId);
|
|
122
|
+
const resolved = payload && typeof payload === "object" && "response" in payload
|
|
123
|
+
? payload.response
|
|
124
|
+
: payload;
|
|
125
|
+
pending.resolve(resolved);
|
|
126
|
+
pendingRequests.delete(requestId);
|
|
127
|
+
return true;
|
|
128
|
+
};
|
|
129
|
+
const rejectResponse = (requestId, error) => {
|
|
130
|
+
if (!requestId || !pendingRequests.has(requestId))
|
|
131
|
+
return false;
|
|
132
|
+
pendingRequests.get(requestId).reject(error);
|
|
133
|
+
pendingRequests.delete(requestId);
|
|
134
|
+
return true;
|
|
135
|
+
};
|
|
136
|
+
const sendError = (requestId, code, message, extras = {}) => {
|
|
137
|
+
if (!requestId)
|
|
138
|
+
return;
|
|
139
|
+
const envelope = {
|
|
140
|
+
protocol_version: PROTOCOL_VERSION,
|
|
141
|
+
type: "error",
|
|
142
|
+
request_id: requestId,
|
|
143
|
+
error: { code, message },
|
|
144
|
+
...extras,
|
|
145
|
+
};
|
|
146
|
+
hostProcess.stdin.write(`${JSON.stringify(envelope)}\n`);
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
ack,
|
|
150
|
+
rejectResponse,
|
|
151
|
+
request,
|
|
152
|
+
resolveResponse,
|
|
153
|
+
send,
|
|
154
|
+
sendError,
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
export const attachEnvelopeReader = (hostProcess, handler, logger = defaultLogger) => {
|
|
158
|
+
const rl = readline.createInterface({ input: hostProcess.stdout, terminal: false });
|
|
159
|
+
rl.on("line", async (line) => {
|
|
160
|
+
if (!line.trim())
|
|
161
|
+
return;
|
|
162
|
+
try {
|
|
163
|
+
const envelope = JSON.parse(line);
|
|
164
|
+
await handler(envelope);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
logger.error(`error processing bridge line: ${err instanceof Error ? err.message : String(err)}`);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
return rl;
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=bridge-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-client.js","sourceRoot":"","sources":["../../src/bridge-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Message normalization helpers for inbound bridge envelopes. The host
|
|
2
|
+
// delivers `envelope.payload.message` as a pre-normalized bag of parts;
|
|
3
|
+
// these helpers turn that into plain text for the brain and into structured
|
|
4
|
+
// ObservedTurn records for downstream dispatch.
|
|
5
|
+
import { generateId } from "./bridge-protocol.js";
|
|
6
|
+
const shortMessageId = (value) => {
|
|
7
|
+
const id = (value || "").trim();
|
|
8
|
+
return id.length <= 8 ? id : id.slice(-8);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Converts a normalized bridge message into plain text for the LLM.
|
|
12
|
+
*
|
|
13
|
+
* The host delivers messages as `envelope.payload.message` with the following shape:
|
|
14
|
+
*
|
|
15
|
+
* { text?: string, parts?: ChatBridgeMessagePart[], reply_to_message_id?: string, ... }
|
|
16
|
+
*
|
|
17
|
+
* `parts` is an array of flat objects, each carrying a `type` string discriminator.
|
|
18
|
+
* The host digests the raw wire format into this clean shape before delivery, so
|
|
19
|
+
* brain implementations only need to care about the fields documented below.
|
|
20
|
+
*
|
|
21
|
+
* Attachment bytes for `image` and `file` parts are downloaded by the host into
|
|
22
|
+
* `{agent_workspace}/Downloads/` before delivery. The local paths are conveyed
|
|
23
|
+
* separately via `envelope.payload.attachment_context`; see `buildObservedTurn`.
|
|
24
|
+
*
|
|
25
|
+
* @see https://docs.mutiro.com/chatbridge-protocol
|
|
26
|
+
*/
|
|
27
|
+
const REACTION_QUOTE_MAX_CHARS = 160;
|
|
28
|
+
const truncateReactionQuote = (raw) => {
|
|
29
|
+
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
30
|
+
if (!collapsed)
|
|
31
|
+
return "";
|
|
32
|
+
if (collapsed.length <= REACTION_QUOTE_MAX_CHARS)
|
|
33
|
+
return collapsed;
|
|
34
|
+
return `${collapsed.slice(0, REACTION_QUOTE_MAX_CHARS - 1).trimEnd()}…`;
|
|
35
|
+
};
|
|
36
|
+
export const extractBridgeMessageText = (message, context) => {
|
|
37
|
+
if (!message)
|
|
38
|
+
return "";
|
|
39
|
+
const replyPreview = (context?.replyToMessagePreview ?? "").trim();
|
|
40
|
+
const parts = [];
|
|
41
|
+
const push = (value) => {
|
|
42
|
+
const trimmed = (value || "").trim();
|
|
43
|
+
if (trimmed)
|
|
44
|
+
parts.push(trimmed);
|
|
45
|
+
};
|
|
46
|
+
push(message.text);
|
|
47
|
+
for (const part of Array.isArray(message.parts) ? message.parts : []) {
|
|
48
|
+
if (!part || typeof part !== "object")
|
|
49
|
+
continue;
|
|
50
|
+
const partType = part.type;
|
|
51
|
+
switch (partType) {
|
|
52
|
+
case "text":
|
|
53
|
+
push(part.text);
|
|
54
|
+
break;
|
|
55
|
+
case "audio":
|
|
56
|
+
push(part.transcript);
|
|
57
|
+
break;
|
|
58
|
+
case "card": {
|
|
59
|
+
const cardId = part.card_id;
|
|
60
|
+
push(cardId ? `[Interactive card: ${cardId}]` : "[Interactive card]");
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case "card_action": {
|
|
64
|
+
const p = part;
|
|
65
|
+
push(`[Card interaction: card=${p.card_id || ""} action=${p.action_id || ""} data=${p.data_json || ""}]`);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "contact": {
|
|
69
|
+
const meta = (part.metadata || {});
|
|
70
|
+
const username = (meta.contact_username || "").trim();
|
|
71
|
+
if (!username)
|
|
72
|
+
break;
|
|
73
|
+
const displayName = (meta.contact_display_name || "").trim();
|
|
74
|
+
const role = (meta.contact_member_type || "").trim() === "agent" ? "agent" : "user";
|
|
75
|
+
push(`[Shared contact: ${displayName || username} (@${username}, ${role})]`);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case "reaction": {
|
|
79
|
+
const p = part;
|
|
80
|
+
const emoji = (p.reaction || "").trim();
|
|
81
|
+
if (!emoji)
|
|
82
|
+
break;
|
|
83
|
+
const removed = (p.reaction_operation || "").trim().toLowerCase() === "removed";
|
|
84
|
+
const quote = truncateReactionQuote(replyPreview);
|
|
85
|
+
if (quote) {
|
|
86
|
+
push(removed
|
|
87
|
+
? `[reaction ${emoji} removed from message: "${quote}"]`
|
|
88
|
+
: `[reaction ${emoji} received on message: "${quote}"]`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const target = shortMessageId(message.reply_to_message_id);
|
|
92
|
+
if (removed) {
|
|
93
|
+
push(target
|
|
94
|
+
? `[removed reaction ${emoji} from #${target}]`
|
|
95
|
+
: `[removed reaction ${emoji}]`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
push(target ? `[reacted ${emoji} to #${target}]` : `[reacted ${emoji}]`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "live_call": {
|
|
104
|
+
const p = part;
|
|
105
|
+
const summary = (p.summary_text || "").trim();
|
|
106
|
+
const actionItems = Array.isArray(p.action_items)
|
|
107
|
+
? p.action_items.map((item) => item.trim()).filter(Boolean)
|
|
108
|
+
: [];
|
|
109
|
+
const followUps = Array.isArray(p.follow_ups)
|
|
110
|
+
? p.follow_ups.map((item) => item.trim()).filter(Boolean)
|
|
111
|
+
: [];
|
|
112
|
+
// Always emit at least the header — the part existing signals the
|
|
113
|
+
// call ended, even when summarization produced no text. Skipping
|
|
114
|
+
// here produces an empty turn text, and downstream that becomes a
|
|
115
|
+
// "no extractable content" drop. Symmetric to the host-side fix in
|
|
116
|
+
// chatbridge/normalize.go.
|
|
117
|
+
const lines = [
|
|
118
|
+
`[Voice call summary (call_id=${(p.call_id || "").trim()}, end_reason=${(p.end_reason || "").trim()})]`,
|
|
119
|
+
];
|
|
120
|
+
if (summary)
|
|
121
|
+
lines.push(summary);
|
|
122
|
+
if (actionItems.length > 0)
|
|
123
|
+
lines.push(`Action items:\n${actionItems.map((item) => `- ${item}`).join("\n")}`);
|
|
124
|
+
if (followUps.length > 0)
|
|
125
|
+
lines.push(`Follow-ups:\n${followUps.map((item) => `- ${item}`).join("\n")}`);
|
|
126
|
+
push(lines.join("\n"));
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case "image": {
|
|
130
|
+
const caption = ((part.metadata || {}).caption || "").trim();
|
|
131
|
+
push(caption ? `[Image attachment: ${caption}]` : "[Image attachment]");
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "file": {
|
|
135
|
+
const filename = (part.filename || "").trim();
|
|
136
|
+
const caption = ((part.metadata || {}).caption || "").trim();
|
|
137
|
+
push(caption
|
|
138
|
+
? `[File attachment: ${filename || "attachment"} — ${caption}]`
|
|
139
|
+
: `[File attachment: ${filename || "attachment"}]`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return parts.join(" ").trim();
|
|
145
|
+
};
|
|
146
|
+
export const normalizeOutputText = (value) => {
|
|
147
|
+
const trimmed = (value || "").trim();
|
|
148
|
+
const lowered = trimmed.toLowerCase();
|
|
149
|
+
if (!trimmed)
|
|
150
|
+
return "";
|
|
151
|
+
if (lowered === "noop" || lowered === "noop.")
|
|
152
|
+
return "";
|
|
153
|
+
return trimmed;
|
|
154
|
+
};
|
|
155
|
+
const cloneJson = (value) => JSON.parse(JSON.stringify(value));
|
|
156
|
+
export const trimRecentMessages = (messages, max) => messages.length > max ? messages.slice(-max) : messages;
|
|
157
|
+
export const buildSyntheticBridgeMessage = (params) => ({
|
|
158
|
+
id: `openclaw-${generateId()}`,
|
|
159
|
+
conversation_id: params.conversationId,
|
|
160
|
+
reply_to_message_id: params.replyToMessageId || "",
|
|
161
|
+
from: {
|
|
162
|
+
username: params.senderUsername,
|
|
163
|
+
},
|
|
164
|
+
text: params.text,
|
|
165
|
+
metadata: params.metadata || {},
|
|
166
|
+
});
|
|
167
|
+
export const cloneMessage = (message) => cloneJson(message);
|
|
168
|
+
/**
|
|
169
|
+
* Assembles a promptable ObservedTurn from an inbound host envelope.
|
|
170
|
+
*
|
|
171
|
+
* `extractBridgeMessageText(envelope.payload.message)` converts each message
|
|
172
|
+
* part (text, audio transcript, card placeholder, etc.) into inline plain text
|
|
173
|
+
* for the body.
|
|
174
|
+
*
|
|
175
|
+
* We intentionally do NOT glue `envelope.payload.attachment_context` onto the
|
|
176
|
+
* body. The host-authored description can carry stale or wrong metadata (for
|
|
177
|
+
* example "0x0 pixels" when its image probe fails) and, once real bytes are
|
|
178
|
+
* staged via MediaPaths, mixing it into Body confuses the model more than it
|
|
179
|
+
* helps. Callers that need the raw description can read it separately via
|
|
180
|
+
* `InboundMessage.attachmentContext`.
|
|
181
|
+
*
|
|
182
|
+
* Returns null if conversation/message ids are missing, or when both the text
|
|
183
|
+
* body and any inline image attachments are empty.
|
|
184
|
+
*/
|
|
185
|
+
export const buildObservedTurn = (envelope) => {
|
|
186
|
+
const conversationId = envelope.conversation_id || envelope.payload?.message?.conversation_id;
|
|
187
|
+
const messageId = envelope.message_id || envelope.payload?.message?.id;
|
|
188
|
+
const text = extractBridgeMessageText(envelope.payload?.message, {
|
|
189
|
+
replyToMessagePreview: envelope.payload?.reply_to_message_preview,
|
|
190
|
+
});
|
|
191
|
+
const hasAttachments = Array.isArray(envelope.payload?.images) && (envelope.payload.images?.length ?? 0) > 0;
|
|
192
|
+
if (!conversationId || !messageId || (!text && !hasAttachments)) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
conversationId,
|
|
197
|
+
messageId,
|
|
198
|
+
replyToMessageId: envelope.reply_to_message_id ||
|
|
199
|
+
envelope.payload?.reply_to_message_id ||
|
|
200
|
+
envelope.payload?.message?.reply_to_message_id,
|
|
201
|
+
senderUsername: envelope.payload?.message?.from?.username || "unknown",
|
|
202
|
+
text,
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
export const isSelfEventMessage = (envelope, agentUsername) => {
|
|
206
|
+
const senderUsername = envelope.payload?.message?.from?.username;
|
|
207
|
+
const selfUsername = (agentUsername || "").trim();
|
|
208
|
+
return !senderUsername || (!!selfUsername && senderUsername === selfUsername);
|
|
209
|
+
};
|
|
210
|
+
export const applyVoiceLanguage = (voiceName, language) => {
|
|
211
|
+
const trimmedVoice = voiceName.trim();
|
|
212
|
+
const trimmedLanguage = language.trim();
|
|
213
|
+
if (!trimmedVoice || !trimmedLanguage) {
|
|
214
|
+
return trimmedVoice;
|
|
215
|
+
}
|
|
216
|
+
const languageParts = trimmedLanguage.split("-");
|
|
217
|
+
if (languageParts.length < 2) {
|
|
218
|
+
return trimmedVoice;
|
|
219
|
+
}
|
|
220
|
+
const voiceParts = trimmedVoice.split("-");
|
|
221
|
+
if (voiceParts.length < 4) {
|
|
222
|
+
return trimmedVoice;
|
|
223
|
+
}
|
|
224
|
+
return `${languageParts[0]}-${languageParts[1]}-${voiceParts.slice(2).join("-")}`;
|
|
225
|
+
};
|
|
226
|
+
//# sourceMappingURL=bridge-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-messages.js","sourceRoot":"","sources":["../../src/bridge-messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// NDJSON protocol constants used by the Mutiro chatbridge envelope.
|
|
2
|
+
// These type URLs and helpers mirror the Mutiro bridge's protobuf surface
|
|
3
|
+
// envelope-for-envelope.
|
|
4
|
+
export const PROTOCOL_VERSION = "mutiro.agent.bridge.v1";
|
|
5
|
+
export const TYPE_URLS = {
|
|
6
|
+
addReactionRequest: "type.googleapis.com/mutiro.messaging.AddReactionRequest",
|
|
7
|
+
bridgeCommandResult: "type.googleapis.com/mutiro.chatbridge.ChatBridgeCommandResult",
|
|
8
|
+
bridgeInitializeCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeInitializeCommand",
|
|
9
|
+
bridgeMediaUploadCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeMediaUploadCommand",
|
|
10
|
+
bridgeSendMessageCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeSendMessageCommand",
|
|
11
|
+
bridgeSendVoiceMessageCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeSendVoiceMessageCommand",
|
|
12
|
+
bridgeMessageObservedResult: "type.googleapis.com/mutiro.chatbridge.ChatBridgeMessageObservedResult",
|
|
13
|
+
bridgeSessionObservedResult: "type.googleapis.com/mutiro.chatbridge.ChatBridgeSessionObservedResult",
|
|
14
|
+
bridgeSessionSnapshotResult: "type.googleapis.com/mutiro.chatbridge.ChatBridgeSessionSnapshotResult",
|
|
15
|
+
bridgeSubscriptionSetCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeSubscriptionSetCommand",
|
|
16
|
+
bridgeTaskResult: "type.googleapis.com/mutiro.chatbridge.ChatBridgeTaskResult",
|
|
17
|
+
bridgeTurnEndCommand: "type.googleapis.com/mutiro.chatbridge.ChatBridgeTurnEndCommand",
|
|
18
|
+
forwardMessageRequest: "type.googleapis.com/mutiro.messaging.ForwardMessageRequest",
|
|
19
|
+
recallGetRequest: "type.googleapis.com/mutiro.recall.RecallGetRequest",
|
|
20
|
+
recallSearchRequest: "type.googleapis.com/mutiro.recall.RecallSearchRequest",
|
|
21
|
+
sendSignalRequest: "type.googleapis.com/mutiro.signal.SendSignalRequest",
|
|
22
|
+
};
|
|
23
|
+
export const DEFAULT_OPTIONAL_CAPABILITIES = [
|
|
24
|
+
"message.send_voice",
|
|
25
|
+
"signal.emit",
|
|
26
|
+
"recall.search",
|
|
27
|
+
"recall.get",
|
|
28
|
+
"media.upload",
|
|
29
|
+
// Advertising session.snapshot opts us into the live-call handoff: the
|
|
30
|
+
// host only sends ChatBridgeSessionSnapshotRequest to brains that
|
|
31
|
+
// declare support. Without this, our resolver never fires and the live
|
|
32
|
+
// voice model starts the call with no persona, no transcript, no tools.
|
|
33
|
+
"session.snapshot",
|
|
34
|
+
// Advertising task.request lets the host delegate one-shot prompts to
|
|
35
|
+
// the brain (e.g. scheduled reminders, background lookups). Our
|
|
36
|
+
// resolver runs the prompt against OpenClaw's agent and returns the
|
|
37
|
+
// accumulated reply text in the ChatBridgeTaskResult envelope.
|
|
38
|
+
"task.request",
|
|
39
|
+
];
|
|
40
|
+
export const MAX_RECENT_MESSAGES = 30;
|
|
41
|
+
export const generateId = () => Math.random().toString(36).substring(2, 15);
|
|
42
|
+
//# sourceMappingURL=bridge-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-protocol.js","sourceRoot":"","sources":["../../src/bridge-protocol.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,0EAA0E;AAC1E,yBAAyB;AAEzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAEzD,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,kBAAkB,EAAE,yDAAyD;IAC7E,mBAAmB,EAAE,+DAA+D;IACpF,uBAAuB,EAAE,mEAAmE;IAC5F,wBAAwB,EAAE,oEAAoE;IAC9F,wBAAwB,EAAE,oEAAoE;IAC9F,6BAA6B,EAAE,yEAAyE;IACxG,2BAA2B,EAAE,uEAAuE;IACpG,2BAA2B,EAAE,uEAAuE;IACpG,2BAA2B,EAAE,uEAAuE;IACpG,4BAA4B,EAAE,wEAAwE;IACtG,gBAAgB,EAAE,4DAA4D;IAC9E,oBAAoB,EAAE,gEAAgE;IACtF,qBAAqB,EAAE,4DAA4D;IACnF,gBAAgB,EAAE,oDAAoD;IACtE,mBAAmB,EAAE,uDAAuD;IAC5E,iBAAiB,EAAE,qDAAqD;CAChE,CAAC;AAEX,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,oBAAoB;IACpB,aAAa;IACb,eAAe;IACf,YAAY;IACZ,cAAc;IACd,uEAAuE;IACvE,kEAAkE;IAClE,uEAAuE;IACvE,wEAAwE;IACxE,kBAAkB;IAClB,sEAAsE;IACtE,gEAAgE;IAChE,oEAAoE;IACpE,+DAA+D;IAC/D,cAAc;CACf,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAiCtC,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC"}
|