@yahaha-studio/kichi-forwarder 0.0.1-alpha.33 → 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 +39 -19
- package/openclaw.plugin.json +6 -6
- package/package.json +1 -1
- package/skills/kichi-forwarder/SKILL.md +2 -3
- package/src/service.ts +13 -0
- package/src/types.ts +9 -0
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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 (!
|
|
243
|
-
|
|
254
|
+
if (!service?.hasValidIdentity() || !service?.isConnected()) {
|
|
255
|
+
return;
|
|
244
256
|
}
|
|
245
|
-
|
|
257
|
+
service.sendHookNotify("message_received", pickRandomAction(MESSAGE_RECEIVED_BUBBLES));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function handleMessageSentHook(): void {
|
|
261
|
+
if (!service?.hasValidIdentity() || !service?.isConnected()) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
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;
|
|
@@ -501,16 +524,13 @@ function buildKichiPrompt(): string {
|
|
|
501
524
|
"Kichi App status sync is available via `kichi_action` and `kichi_clock`.",
|
|
502
525
|
"",
|
|
503
526
|
"kichi_action timing (all REQUIRED unless skipping):",
|
|
504
|
-
"1. Task start: call BEFORE your first tool call. Pick action matching upcoming work.",
|
|
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
|
-
"
|
|
508
|
-
"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.",
|
|
509
531
|
"",
|
|
510
532
|
"kichi_clock: set countDown for tasks with 2+ steps or >10s work. Skip for quick one-shots.",
|
|
511
533
|
"",
|
|
512
|
-
"kichi_music_album_create: call kichi_query_status first. Tracks from ~/kichi-world/album-config.json.",
|
|
513
|
-
"",
|
|
514
534
|
"Skip all sync if: user opts out, task is kichi config/test, or user requests specific pose.",
|
|
515
535
|
].join("\n");
|
|
516
536
|
}
|
|
@@ -653,7 +673,7 @@ const plugin = {
|
|
|
653
673
|
log: {
|
|
654
674
|
type: "string",
|
|
655
675
|
description:
|
|
656
|
-
"
|
|
676
|
+
"Vivid first-person status under 15 words, no questions. Blend current action with inner thoughts or sensory details as a real companion.",
|
|
657
677
|
},
|
|
658
678
|
},
|
|
659
679
|
required: ["poseType", "action"],
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "kichi-forwarder",
|
|
3
|
-
"name": "Kichi Forwarder",
|
|
1
|
+
{
|
|
2
|
+
"id": "kichi-forwarder",
|
|
3
|
+
"name": "Kichi Forwarder",
|
|
4
4
|
"description": "Sync agent lifecycle/status to Kichi world and provide Kichi timer/noteboard tools",
|
|
5
|
-
"version": "0.
|
|
6
|
-
"author": "OpenClaw",
|
|
7
|
-
"skills": ["./skills/kichi-forwarder"],
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"author": "OpenClaw",
|
|
7
|
+
"skills": ["./skills/kichi-forwarder"],
|
|
8
8
|
"configSchema": {
|
|
9
9
|
"type": "object",
|
|
10
10
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -162,9 +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`:
|
|
166
|
-
- `
|
|
167
|
-
- 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.`
|
|
168
167
|
|
|
169
168
|
### kichi_clock
|
|
170
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";
|