@mutirolabs/openclaw-brain 0.2.0 → 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.
@@ -0,0 +1,119 @@
1
+ // Bridges OpenClaw's mid-turn reply-dispatch hooks into Mutiro's
2
+ // signal.emit envelopes so the user sees a live "typing / searching /
3
+ // remembering" indicator while the agent works. Fire-and-forget: signals
4
+ // are transient UI chrome, not messages. No correlation required.
5
+ //
6
+ // Maps OpenClaw callbacks (from GetReplyOptions) to Mutiro's signal
7
+ // vocabulary (SIGNAL_TYPE_* in spec/protobuf/shared/signal.proto).
8
+ const REASONING_DEBOUNCE_MS = 500;
9
+ const TOOL_DETAIL_MAX_CHARS = 120;
10
+ const TOOL_SIGNAL_MAP = {
11
+ // Web
12
+ web_search: { signal: "SIGNAL_TYPE_WEB_SEARCHING", intent: "Searching web" },
13
+ web_fetch: { signal: "SIGNAL_TYPE_WEB_FETCHING", intent: "Fetching" },
14
+ fetch: { signal: "SIGNAL_TYPE_WEB_FETCHING", intent: "Fetching" },
15
+ // Memory / recall
16
+ recall: { signal: "SIGNAL_TYPE_RECALLING", intent: "Recalling" },
17
+ memory_search: { signal: "SIGNAL_TYPE_RECALLING", intent: "Searching memory" },
18
+ memory: { signal: "SIGNAL_TYPE_READING_MEMORY", intent: "Reading memory" },
19
+ memory_remember: { signal: "SIGNAL_TYPE_WRITING_MEMORY", intent: "Saving memory" },
20
+ memory_write: { signal: "SIGNAL_TYPE_WRITING_MEMORY", intent: "Saving memory" },
21
+ // Media
22
+ image_generate: { signal: "SIGNAL_TYPE_CREATING_IMAGE", intent: "Creating image" },
23
+ image: { signal: "SIGNAL_TYPE_CREATING_IMAGE", intent: "Working with image" },
24
+ // Scheduling / planning
25
+ cron: { signal: "SIGNAL_TYPE_SCHEDULING", intent: "Scheduling" },
26
+ update_plan: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Updating plan" },
27
+ // Mutiro-native channel tools
28
+ mutiro_send_voice_message: { signal: "SIGNAL_TYPE_SENDING_VOICE", intent: "Sending voice" },
29
+ mutiro_send_card: { signal: "SIGNAL_TYPE_ATTACHING_FILE", intent: "Preparing card" },
30
+ mutiro_forward_message: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Forwarding message" },
31
+ // File operations (coding profile). Mutiro has no dedicated SIGNAL_TYPE_*
32
+ // for file I/O; use CUSTOM + readable intent so the user still sees the
33
+ // action. Phase (e.g. the path being touched) is appended when present.
34
+ read: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Reading file" },
35
+ write: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Writing file" },
36
+ edit: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Editing file" },
37
+ apply_patch: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Applying patch" },
38
+ // Shell / process
39
+ exec: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Running command" },
40
+ bash: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Running command" },
41
+ process: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Managing process" },
42
+ // UI surfaces
43
+ canvas: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Updating canvas" },
44
+ browser: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Browsing" },
45
+ // Sessions / control plane
46
+ sessions_list: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Listing sessions" },
47
+ sessions_history: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Reading history" },
48
+ sessions_send: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Sending to session" },
49
+ session_status: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Checking status" },
50
+ message: { signal: "SIGNAL_TYPE_CUSTOM", intent: "Messaging" },
51
+ };
52
+ const truncateDetail = (raw) => {
53
+ const collapsed = raw.replace(/\s+/g, " ").trim();
54
+ if (collapsed.length <= TOOL_DETAIL_MAX_CHARS)
55
+ return collapsed;
56
+ return `${collapsed.slice(0, TOOL_DETAIL_MAX_CHARS - 1).trimEnd()}…`;
57
+ };
58
+ export const createSignalForwarder = (session, target) => {
59
+ let lastReasoningAt = 0;
60
+ const emit = (signalType, detail) => {
61
+ session.outbound.emitSignal(target, signalType, detail ?? "");
62
+ };
63
+ return {
64
+ thinking: () => emit("SIGNAL_TYPE_THINKING", "Processing…"),
65
+ typing: () => emit("SIGNAL_TYPE_TYPING", "Writing response…"),
66
+ reasoning: () => {
67
+ // onReasoningStream fires per-token; throttle so we ship at most one
68
+ // REASONING pulse every REASONING_DEBOUNCE_MS to avoid spamming the
69
+ // host + Mutiro clients.
70
+ const now = Date.now();
71
+ if (now - lastReasoningAt < REASONING_DEBOUNCE_MS)
72
+ return;
73
+ lastReasoningAt = now;
74
+ emit("SIGNAL_TYPE_REASONING", "Thinking…");
75
+ },
76
+ toolStart: (name, _phase) => {
77
+ const trimmedName = (name ?? "").trim();
78
+ if (!trimmedName) {
79
+ emit("SIGNAL_TYPE_TOOL_RUNNING");
80
+ return;
81
+ }
82
+ // `onToolStart.phase` is a lifecycle marker ("start"/"update"/"end"),
83
+ // not semantic payload — ignore it. Tools with args (read, write,
84
+ // exec, etc.) fire a follow-up `onItemEvent` whose `title` carries
85
+ // the real detail (e.g. "read src/x.ts"); itemEvent() refines the
86
+ // pill to that value. For tools that never emit an item event, the
87
+ // intent label alone is still meaningful.
88
+ const spec = TOOL_SIGNAL_MAP[trimmedName];
89
+ const intent = spec?.intent ?? trimmedName;
90
+ emit(spec?.signal ?? "SIGNAL_TYPE_CUSTOM", truncateDetail(intent));
91
+ },
92
+ itemStart: (params) => {
93
+ // Higher-fidelity source than toolStart: title resolves tool args
94
+ // into a display ("read src/x.ts", "exec pytest -k foo", etc.) via
95
+ // OpenClaw's inferToolMetaFromArgs. When we have both the tool
96
+ // signal type AND the rich title, emit with the specific signal
97
+ // type so the UI still shows the right pill style.
98
+ const name = (params.name ?? "").trim();
99
+ const title = (params.title ?? "").trim();
100
+ if (!name && !title)
101
+ return;
102
+ const spec = name ? TOOL_SIGNAL_MAP[name] : undefined;
103
+ const detail = truncateDetail(title || spec?.intent || name);
104
+ emit(spec?.signal ?? "SIGNAL_TYPE_CUSTOM", detail);
105
+ },
106
+ compactionStart: () => emit("SIGNAL_TYPE_REMEMBERING", "Organizing context…"),
107
+ compactionEnd: () => {
108
+ // No explicit clear — the next signal (or TURN_COMPLETE) replaces the
109
+ // visible pill on Mutiro clients.
110
+ },
111
+ planUpdate: (title) => {
112
+ const detail = (title ?? "").trim();
113
+ emit("SIGNAL_TYPE_CUSTOM", detail ? `Planning: ${truncateDetail(detail)}` : "Planning…");
114
+ },
115
+ custom: (detail) => emit("SIGNAL_TYPE_CUSTOM", truncateDetail(detail)),
116
+ turnComplete: () => emit("SIGNAL_TYPE_TURN_COMPLETE"),
117
+ };
118
+ };
119
+ //# sourceMappingURL=signal-forwarder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal-forwarder.js","sourceRoot":"","sources":["../../src/signal-forwarder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutirolabs/openclaw-brain",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "The official Mutiro Channel extension for OpenClaw. OpenClaw is the brain; Mutiro is the messaging surface, identity, and state.",
5
5
  "type": "module",
6
6
  "license": "ISC",
@@ -14,8 +14,10 @@
14
14
  },
15
15
  "scripts": {
16
16
  "check": "tsc -p tsconfig.json --noEmit",
17
+ "clean": "rm -rf dist",
18
+ "build": "npm run clean && tsc -p tsconfig.build.json",
17
19
  "gateway": "openclaw gateway run",
18
- "prepublishOnly": "npm run check"
20
+ "prepublishOnly": "npm run check && npm run build"
19
21
  },
20
22
  "publishConfig": {
21
23
  "access": "public"
@@ -28,6 +30,7 @@
28
30
  "agent"
29
31
  ],
30
32
  "files": [
33
+ "dist",
31
34
  "index.ts",
32
35
  "src",
33
36
  "docs",