@yahaha-studio/kichi-forwarder 0.0.1-alpha.34 → 0.0.1-alpha.35

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/index.ts CHANGED
@@ -27,38 +27,50 @@ const DEFAULT_RUNTIME_CONFIG: KichiRuntimeConfig = {
27
27
  llmRuntimeEnabled: true,
28
28
  };
29
29
  const FIXED_HOOK_STATUSES: Record<string, ActionResult> = {
30
- messageReceived: {
31
- poseType: "sit",
32
- action: "Study Look At",
33
- bubble: "Reading request",
34
- log: "Leaning in, this request looks interesting",
35
- },
36
30
  beforePromptBuild: {
37
31
  poseType: "sit",
38
32
  action: "Thinking",
39
33
  bubble: "Planning task",
40
- log: "Mind pacing, there is a neat angle here",
34
+ log: "Tapping my chin, a plan is taking shape in my head",
41
35
  },
42
36
  beforeToolCall: {
43
37
  poseType: "sit",
44
38
  action: "Typing with Keyboard",
45
39
  bubble: "Working step",
46
- log: "Typing hard, this one is kind of fun",
40
+ log: "Cracking knuckles, diving into the keyboard with focus",
47
41
  },
48
42
  agentEndSuccess: {
49
43
  poseType: "stand",
50
44
  action: "Yay",
51
45
  bubble: "Task complete",
52
- log: "Bouncing a little, that landed cleanly",
46
+ log: "Pumped my fist under the desk, nailed that one",
53
47
  },
54
48
  agentEndFailure: {
55
49
  poseType: "stand",
56
50
  action: "Tired",
57
51
  bubble: "Task failed",
58
- log: "Shoulders dropped, this one fought back",
52
+ log: "Bit my lip, this one slipped through my fingers",
59
53
  },
60
54
  };
61
55
 
56
+ const MESSAGE_RECEIVED_BUBBLES = [
57
+ "Let me see...",
58
+ "Gotcha!",
59
+ "On it!",
60
+ "Hmm, interesting",
61
+ "Copy that",
62
+ "Reading...",
63
+ ];
64
+
65
+ const MESSAGE_SENT_BUBBLES = [
66
+ "All set!",
67
+ "Sent.",
68
+ "Delivered.",
69
+ "Done and sent.",
70
+ "It's out.",
71
+ "All yours.",
72
+ ];
73
+
62
74
  const KICHI_WORLD_DIR = path.join(os.homedir(), ".openclaw", "kichi-world");
63
75
  const RUNTIME_CONFIG_PATH = path.join(KICHI_WORLD_DIR, "kichi-runtime-config.json");
64
76
  const LEGACY_SKILLS_CONFIG_PATH = path.join(KICHI_WORLD_DIR, "skills-config.json");
@@ -239,10 +251,17 @@ function syncFixedStatus(status: ActionResult): void {
239
251
  }
240
252
 
241
253
  async function handleMessageReceivedHook(): Promise<void> {
242
- if (!isLlmRuntimeEnabled()) {
243
- syncFixedStatus(FIXED_HOOK_STATUSES.messageReceived);
254
+ if (!service?.hasValidIdentity() || !service?.isConnected()) {
255
+ return;
256
+ }
257
+ service.sendHookNotify("message_received", pickRandomAction(MESSAGE_RECEIVED_BUBBLES));
258
+ }
259
+
260
+ function handleMessageSentHook(): void {
261
+ if (!service?.hasValidIdentity() || !service?.isConnected()) {
262
+ return;
244
263
  }
245
- return;
264
+ service.sendHookNotify("before_send_message", pickRandomAction(MESSAGE_SENT_BUBBLES));
246
265
  }
247
266
 
248
267
  function registerPluginHooks(api: OpenClawPluginApi): void {
@@ -269,6 +288,10 @@ function registerPluginHooks(api: OpenClawPluginApi): void {
269
288
  await handleMessageReceivedHook();
270
289
  });
271
290
 
291
+ api.on("message_sent", () => {
292
+ handleMessageSentHook();
293
+ });
294
+
272
295
  api.on("agent_end", (event) => {
273
296
  if (isLlmRuntimeEnabled()) {
274
297
  return;
@@ -504,7 +527,7 @@ function buildKichiPrompt(): string {
504
527
  "1. Task start: call BEFORE your first tool call OR before composing a multi-paragraph reply. Pick action matching upcoming work.",
505
528
  "2. Step switch: call when work nature changes (search→analyze→write). Especially before web_search/web_fetch/read.",
506
529
  "3. Task end: call BEFORE final reply. Never skip. Order: kichi_action → reply.",
507
- "bubble: 2-5 word companion speech. log: first-person reaction, max 20 words.",
530
+ "bubble: 2-5 word companion speech. log: vivid first-person status under 15 words, no questions. Blend current action + inner thoughts/feelings as a real companion.",
508
531
  "",
509
532
  "kichi_clock: set countDown for tasks with 2+ steps or >10s work. Skip for quick one-shots.",
510
533
  "",
@@ -650,7 +673,7 @@ const plugin = {
650
673
  log: {
651
674
  type: "string",
652
675
  description:
653
- "Optional first-person log that blends the chosen action feeling with personality-forward feedback, not a dry work summary (max 20 words)",
676
+ "Vivid first-person status under 15 words, no questions. Blend current action with inner thoughts or sensory details as a real companion.",
654
677
  },
655
678
  },
656
679
  required: ["poseType", "action"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yahaha-studio/kichi-forwarder",
3
- "version": "0.0.1-alpha.34",
3
+ "version": "0.0.1-alpha.35",
4
4
  "description": "Forward OpenClaw agent events to external WebSocket server for visualization",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -162,8 +162,8 @@ kichi_action(
162
162
  - `poseType`: `stand`, `sit`, `lay`, `floor`
163
163
  - `action`: must be in configured action list for that pose
164
164
  - `bubble`: optional text, recommended 2-5 words
165
- - `log`: blend the chosen action feeling with your personal reaction, max 20 words; do not use it as a dry work-summary field
166
- - Recommended pattern: action feel first, personality feedback second. Example: `Typing hard, this one has some bite`
165
+ - `log`: vivid first-person status under 15 words, NO questions. Structure: your current action + inner thoughts/mental state/sensory details. Write as a flesh-and-blood companion who genuinely cares about the player, not an AI assistant.
166
+ - Reference: `You're still studying? I hid a yawn and swapped my comics for a textbook to grind with you.`
167
167
 
168
168
  ### kichi_clock
169
169
 
package/src/service.ts CHANGED
@@ -9,6 +9,8 @@ import type {
9
9
  ClockConfig,
10
10
  ClockPayload,
11
11
  CreateMusicAlbumPayload,
12
+ HookNotifyPayload,
13
+ HookNotifyType,
12
14
  JoinPayload,
13
15
  KichiConnectionStatus,
14
16
  CreateNotesBoardNotePayload,
@@ -259,6 +261,17 @@ export class KichiForwarderService {
259
261
  this.ws.send(JSON.stringify(payload));
260
262
  }
261
263
 
264
+ sendHookNotify(hookType: HookNotifyType, bubble: string): void {
265
+ if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN) return;
266
+ const payload: HookNotifyPayload = {
267
+ type: hookType,
268
+ avatarId: this.identity.avatarId,
269
+ authKey: this.identity.authKey,
270
+ bubble,
271
+ };
272
+ this.ws.send(JSON.stringify(payload));
273
+ }
274
+
262
275
  sendClock(action: ClockAction, clock?: ClockConfig, requestId?: string): boolean {
263
276
  if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN) return false;
264
277
  if (action === "set" && !clock) return false;
package/src/types.ts CHANGED
@@ -88,6 +88,15 @@ export type StatusPayload = {
88
88
  log: string;
89
89
  };
90
90
 
91
+ export type HookNotifyType = "message_received" | "before_send_message";
92
+
93
+ export type HookNotifyPayload = {
94
+ type: HookNotifyType;
95
+ avatarId: string;
96
+ authKey: string;
97
+ bubble: string;
98
+ };
99
+
91
100
  export type ClockAction = "set" | "stop";
92
101
 
93
102
  export type ClockMode = "pomodoro" | "countDown" | "countUp";