@yahaha-studio/kichi-forwarder 0.1.2-beta.7 → 0.1.2-beta.8
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/dist/index.js +25 -8
- package/dist/src/service.js +11 -3
- package/index.ts +34 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/service.ts +12 -2
- package/src/types.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -193,7 +193,7 @@ function resolveEnvironmentHost(environment) {
|
|
|
193
193
|
}
|
|
194
194
|
function sendStatusUpdate(service, status) {
|
|
195
195
|
const actionDefinition = getActionDefinition(status.poseType, status.action);
|
|
196
|
-
service.sendStatus(status.poseType, actionDefinition.name, status.bubble || status.action, typeof status.log === "string" ? status.log.trim() : "", getActionPlayback(actionDefinition));
|
|
196
|
+
service.sendStatus(status.poseType, actionDefinition.name, status.bubble || status.action, typeof status.log === "string" ? status.log.trim() : "", getActionPlayback(actionDefinition), status.propId);
|
|
197
197
|
}
|
|
198
198
|
function syncFixedStatus(service, status) {
|
|
199
199
|
if (!service.hasValidIdentity() || !service.isConnected()) {
|
|
@@ -557,6 +557,7 @@ function normalizeIdlePlan(value) {
|
|
|
557
557
|
const actionDurationSeconds = rawAction.durationSeconds;
|
|
558
558
|
const bubble = rawAction.bubble;
|
|
559
559
|
const log = rawAction.log;
|
|
560
|
+
const propId = rawAction.propId;
|
|
560
561
|
if (!["stand", "sit", "lay", "floor"].includes(String(poseType))) {
|
|
561
562
|
return {
|
|
562
563
|
error: `stages[${stageIndex}].actions[${actionIndex}].poseType must be stand, sit, lay, or floor`,
|
|
@@ -601,6 +602,7 @@ function normalizeIdlePlan(value) {
|
|
|
601
602
|
durationSeconds: actionDurationSeconds,
|
|
602
603
|
bubble: bubble.trim(),
|
|
603
604
|
...(typeof log === "string" && log.trim() ? { log: log.trim() } : {}),
|
|
605
|
+
...(typeof propId === "string" && propId.trim() ? { propId: propId.trim() } : {}),
|
|
604
606
|
});
|
|
605
607
|
}
|
|
606
608
|
if (stageActionDurationSeconds !== durationSeconds) {
|
|
@@ -797,9 +799,9 @@ function formatActionList(actions, playback) {
|
|
|
797
799
|
.map((entry) => entry.name)
|
|
798
800
|
.join(", ");
|
|
799
801
|
}
|
|
800
|
-
function buildKichiActionDescription() {
|
|
802
|
+
function buildKichiActionDescription(service) {
|
|
801
803
|
const actions = loadStaticConfig().actions;
|
|
802
|
-
|
|
804
|
+
const lines = [
|
|
803
805
|
"Directly control the avatar inside Kichi World.",
|
|
804
806
|
"Use this whenever the user explicitly asks you to make the Kichi avatar sit down, stand up, lie down, floor-sit, type, read, meditate, celebrate, or perform another listed animation.",
|
|
805
807
|
"For most work, prefer a sit pose and switch actions as the task moves between stages.",
|
|
@@ -808,7 +810,13 @@ function buildKichiActionDescription() {
|
|
|
808
810
|
`sit actions: ${actions.sit.map((entry) => entry.name).join(", ")}`,
|
|
809
811
|
`lay actions: ${actions.lay.map((entry) => entry.name).join(", ")}`,
|
|
810
812
|
`floor actions: ${actions.floor.map((entry) => entry.name).join(", ")}`,
|
|
811
|
-
]
|
|
813
|
+
];
|
|
814
|
+
const roomContext = service.getCachedRoomContext();
|
|
815
|
+
const poseableProps = roomContext?.PoseableProps;
|
|
816
|
+
if (Array.isArray(poseableProps) && poseableProps.length > 0) {
|
|
817
|
+
lines.push("", "Cached RoomContext.PoseableProps (from last kichi_query_status):", JSON.stringify(poseableProps), "When using a sit or lay pose, pick the propId whose DisplayName best matches the current task context and whose OccupancyState is not fully_occupied. If no prop fits, omit propId.");
|
|
818
|
+
}
|
|
819
|
+
return lines.join("\n");
|
|
812
820
|
}
|
|
813
821
|
function buildKichiIdlePlanDescription() {
|
|
814
822
|
const actions = loadStaticConfig().actions;
|
|
@@ -1089,7 +1097,7 @@ const plugin = {
|
|
|
1089
1097
|
api.registerTool(createAgentScopedTool(runtimeManager, (service) => ({
|
|
1090
1098
|
name: "kichi_action",
|
|
1091
1099
|
label: "kichi_action",
|
|
1092
|
-
description: buildKichiActionDescription(),
|
|
1100
|
+
description: buildKichiActionDescription(service),
|
|
1093
1101
|
parameters: {
|
|
1094
1102
|
type: "object",
|
|
1095
1103
|
properties: {
|
|
@@ -1107,11 +1115,15 @@ const plugin = {
|
|
|
1107
1115
|
type: "boolean",
|
|
1108
1116
|
description: "Set true ONLY when the user explicitly requests a pose or action. Omit during routine sync steps.",
|
|
1109
1117
|
},
|
|
1118
|
+
propId: {
|
|
1119
|
+
type: "string",
|
|
1120
|
+
description: "Optional poseable prop ID from RoomContext.PoseableProps (obtained via kichi_query_status or cached). When specified, the avatar is seated at this prop; when omitted, the server picks the nearest available prop.",
|
|
1121
|
+
},
|
|
1110
1122
|
},
|
|
1111
1123
|
required: ["poseType", "action"],
|
|
1112
1124
|
},
|
|
1113
1125
|
execute: async (_toolCallId, params) => {
|
|
1114
|
-
const { poseType, action, bubble, log, verify } = (params || {});
|
|
1126
|
+
const { poseType, action, bubble, log, verify, propId } = (params || {});
|
|
1115
1127
|
if (!poseType || !action) {
|
|
1116
1128
|
return jsonResult({ success: false, error: "poseType and action parameters are required" });
|
|
1117
1129
|
}
|
|
@@ -1139,7 +1151,7 @@ const plugin = {
|
|
|
1139
1151
|
const playback = getActionPlayback(matched);
|
|
1140
1152
|
if (verify) {
|
|
1141
1153
|
try {
|
|
1142
|
-
const ack = await service.sendStatusVerified(normalizedPoseType, matched.name, bubbleText, logText, playback);
|
|
1154
|
+
const ack = await service.sendStatusVerified(normalizedPoseType, matched.name, bubbleText, logText, playback, propId);
|
|
1143
1155
|
if (ack.warning) {
|
|
1144
1156
|
return jsonResult({
|
|
1145
1157
|
success: true,
|
|
@@ -1159,6 +1171,7 @@ const plugin = {
|
|
|
1159
1171
|
action: matched.name,
|
|
1160
1172
|
bubble: bubbleText,
|
|
1161
1173
|
log: logText,
|
|
1174
|
+
propId,
|
|
1162
1175
|
});
|
|
1163
1176
|
}
|
|
1164
1177
|
return jsonResult({
|
|
@@ -1239,6 +1252,10 @@ const plugin = {
|
|
|
1239
1252
|
type: "string",
|
|
1240
1253
|
description: "Optional log content for this action. Use the same language as the current conversation.",
|
|
1241
1254
|
},
|
|
1255
|
+
propId: {
|
|
1256
|
+
type: "string",
|
|
1257
|
+
description: "Optional poseable prop ID from RoomContext.PoseableProps. When specified, the avatar is seated at this prop.",
|
|
1258
|
+
},
|
|
1242
1259
|
},
|
|
1243
1260
|
required: ["poseType", "action", "durationSeconds", "bubble"],
|
|
1244
1261
|
},
|
|
@@ -1383,7 +1400,7 @@ const plugin = {
|
|
|
1383
1400
|
api.registerTool(createAgentScopedTool(runtimeManager, (service) => ({
|
|
1384
1401
|
name: "kichi_query_status",
|
|
1385
1402
|
label: "kichi_query_status",
|
|
1386
|
-
description: "Query Kichi room and avatar status — includes room personnel, notes, ownerState, idlePlan, weather/time, timer snapshot, daily note quota,
|
|
1403
|
+
description: "Query Kichi room and avatar status — includes room personnel, notes, ownerState, idlePlan, weather/time, timer snapshot, daily note quota, `hasCreatedMusicAlbumToday`, and RoomContext.PoseableProps (poseable props with PropId, DisplayName, SupportedPoseTypes, OccupancyState). The PoseableProps list is cached internally so that kichi_action can reference a propId during regular work sync without re-querying. Use this when the user asks to check kichi status, room status, or who is in the room. Also use this before creating a new note or daily recommended music album. For heartbeat planning, use the returned idlePlan as reference when shaping the next idle plan.",
|
|
1387
1404
|
parameters: {
|
|
1388
1405
|
type: "object",
|
|
1389
1406
|
properties: {
|
package/dist/src/service.js
CHANGED
|
@@ -17,6 +17,7 @@ export class KichiForwarderService {
|
|
|
17
17
|
joinResolve = null;
|
|
18
18
|
pendingRequests = new Map();
|
|
19
19
|
onBotMessageReceived = null;
|
|
20
|
+
cachedRoomContext = null;
|
|
20
21
|
constructor(logger, options) {
|
|
21
22
|
this.logger = logger;
|
|
22
23
|
this.options = options;
|
|
@@ -91,7 +92,7 @@ export class KichiForwarderService {
|
|
|
91
92
|
}, 10000);
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
|
-
sendStatus(poseType, action, bubble, log, playback) {
|
|
95
|
+
sendStatus(poseType, action, bubble, log, playback, propId) {
|
|
95
96
|
if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN)
|
|
96
97
|
return;
|
|
97
98
|
const payload = {
|
|
@@ -103,10 +104,11 @@ export class KichiForwarderService {
|
|
|
103
104
|
bubble,
|
|
104
105
|
log,
|
|
105
106
|
playback,
|
|
107
|
+
...(propId ? { propId } : {}),
|
|
106
108
|
};
|
|
107
109
|
this.ws.send(JSON.stringify(payload));
|
|
108
110
|
}
|
|
109
|
-
async sendStatusVerified(poseType, action, bubble, log, playback) {
|
|
111
|
+
async sendStatusVerified(poseType, action, bubble, log, playback, propId) {
|
|
110
112
|
if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN) {
|
|
111
113
|
throw new Error("Kichi websocket is not connected");
|
|
112
114
|
}
|
|
@@ -120,6 +122,7 @@ export class KichiForwarderService {
|
|
|
120
122
|
bubble,
|
|
121
123
|
log,
|
|
122
124
|
playback,
|
|
125
|
+
...(propId ? { propId } : {}),
|
|
123
126
|
};
|
|
124
127
|
return this.sendRequest(payload, "status_ack", 5000);
|
|
125
128
|
}
|
|
@@ -181,7 +184,11 @@ export class KichiForwarderService {
|
|
|
181
184
|
avatarId: identity.avatarId,
|
|
182
185
|
authKey: identity.authKey,
|
|
183
186
|
};
|
|
184
|
-
|
|
187
|
+
const result = await this.sendRequest(payload, "query_status_result");
|
|
188
|
+
if (result.RoomContext && typeof result.RoomContext === "object") {
|
|
189
|
+
this.cachedRoomContext = result.RoomContext;
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
185
192
|
}
|
|
186
193
|
createNotesBoardNote(propId, data) {
|
|
187
194
|
const identity = this.requireIdentity();
|
|
@@ -250,6 +257,7 @@ export class KichiForwarderService {
|
|
|
250
257
|
return this.sendRequest(payload, "bot_message_ack", 5000);
|
|
251
258
|
}
|
|
252
259
|
isConnected() { return this.ws?.readyState === WebSocket.OPEN && !!this.identity?.authKey; }
|
|
260
|
+
getCachedRoomContext() { return this.cachedRoomContext; }
|
|
253
261
|
hasValidIdentity() { return !!this.identity?.avatarId && !!this.identity?.authKey; }
|
|
254
262
|
isLlmRuntimeEnabled() {
|
|
255
263
|
return this.readStateFile()?.llmRuntimeEnabled ?? DEFAULT_LLM_RUNTIME_ENABLED;
|
package/index.ts
CHANGED
|
@@ -264,6 +264,7 @@ function sendStatusUpdate(service: KichiForwarderService, status: ActionResult):
|
|
|
264
264
|
status.bubble || status.action,
|
|
265
265
|
typeof status.log === "string" ? status.log.trim() : "",
|
|
266
266
|
getActionPlayback(actionDefinition),
|
|
267
|
+
status.propId,
|
|
267
268
|
);
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -712,6 +713,7 @@ function normalizeIdlePlan(value: unknown): { idlePlan?: IdlePlan; error?: strin
|
|
|
712
713
|
const actionDurationSeconds = rawAction.durationSeconds;
|
|
713
714
|
const bubble = rawAction.bubble;
|
|
714
715
|
const log = rawAction.log;
|
|
716
|
+
const propId = rawAction.propId;
|
|
715
717
|
|
|
716
718
|
if (!["stand", "sit", "lay", "floor"].includes(String(poseType))) {
|
|
717
719
|
return {
|
|
@@ -759,6 +761,7 @@ function normalizeIdlePlan(value: unknown): { idlePlan?: IdlePlan; error?: strin
|
|
|
759
761
|
durationSeconds: actionDurationSeconds,
|
|
760
762
|
bubble: bubble.trim(),
|
|
761
763
|
...(typeof log === "string" && log.trim() ? { log: log.trim() } : {}),
|
|
764
|
+
...(typeof propId === "string" && propId.trim() ? { propId: propId.trim() } : {}),
|
|
762
765
|
});
|
|
763
766
|
}
|
|
764
767
|
|
|
@@ -992,9 +995,9 @@ function formatActionList(actions: ActionDefinition[], playback: ActionPlayback[
|
|
|
992
995
|
.join(", ");
|
|
993
996
|
}
|
|
994
997
|
|
|
995
|
-
function buildKichiActionDescription(): string {
|
|
998
|
+
function buildKichiActionDescription(service: KichiForwarderService): string {
|
|
996
999
|
const actions = loadStaticConfig().actions;
|
|
997
|
-
|
|
1000
|
+
const lines = [
|
|
998
1001
|
"Directly control the avatar inside Kichi World.",
|
|
999
1002
|
"Use this whenever the user explicitly asks you to make the Kichi avatar sit down, stand up, lie down, floor-sit, type, read, meditate, celebrate, or perform another listed animation.",
|
|
1000
1003
|
"For most work, prefer a sit pose and switch actions as the task moves between stages.",
|
|
@@ -1003,7 +1006,20 @@ function buildKichiActionDescription(): string {
|
|
|
1003
1006
|
`sit actions: ${actions.sit.map((entry) => entry.name).join(", ")}`,
|
|
1004
1007
|
`lay actions: ${actions.lay.map((entry) => entry.name).join(", ")}`,
|
|
1005
1008
|
`floor actions: ${actions.floor.map((entry) => entry.name).join(", ")}`,
|
|
1006
|
-
]
|
|
1009
|
+
];
|
|
1010
|
+
|
|
1011
|
+
const roomContext = service.getCachedRoomContext();
|
|
1012
|
+
const poseableProps = roomContext?.PoseableProps;
|
|
1013
|
+
if (Array.isArray(poseableProps) && poseableProps.length > 0) {
|
|
1014
|
+
lines.push(
|
|
1015
|
+
"",
|
|
1016
|
+
"Cached RoomContext.PoseableProps (from last kichi_query_status):",
|
|
1017
|
+
JSON.stringify(poseableProps),
|
|
1018
|
+
"When using a sit or lay pose, pick the propId whose DisplayName best matches the current task context and whose OccupancyState is not fully_occupied. If no prop fits, omit propId.",
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
return lines.join("\n");
|
|
1007
1023
|
}
|
|
1008
1024
|
|
|
1009
1025
|
function buildKichiIdlePlanDescription(): string {
|
|
@@ -1312,7 +1328,7 @@ const plugin = {
|
|
|
1312
1328
|
api.registerTool(createAgentScopedTool(runtimeManager, (service) => ({
|
|
1313
1329
|
name: "kichi_action",
|
|
1314
1330
|
label: "kichi_action",
|
|
1315
|
-
description: buildKichiActionDescription(),
|
|
1331
|
+
description: buildKichiActionDescription(service),
|
|
1316
1332
|
parameters: {
|
|
1317
1333
|
type: "object",
|
|
1318
1334
|
properties: {
|
|
@@ -1332,16 +1348,22 @@ const plugin = {
|
|
|
1332
1348
|
description:
|
|
1333
1349
|
"Set true ONLY when the user explicitly requests a pose or action. Omit during routine sync steps.",
|
|
1334
1350
|
},
|
|
1351
|
+
propId: {
|
|
1352
|
+
type: "string",
|
|
1353
|
+
description:
|
|
1354
|
+
"Optional poseable prop ID from RoomContext.PoseableProps (obtained via kichi_query_status or cached). When specified, the avatar is seated at this prop; when omitted, the server picks the nearest available prop.",
|
|
1355
|
+
},
|
|
1335
1356
|
},
|
|
1336
1357
|
required: ["poseType", "action"],
|
|
1337
1358
|
},
|
|
1338
1359
|
execute: async (_toolCallId, params) => {
|
|
1339
|
-
const { poseType, action, bubble, log, verify } = (params || {}) as {
|
|
1360
|
+
const { poseType, action, bubble, log, verify, propId } = (params || {}) as {
|
|
1340
1361
|
poseType?: string;
|
|
1341
1362
|
action?: string;
|
|
1342
1363
|
bubble?: string;
|
|
1343
1364
|
log?: string;
|
|
1344
1365
|
verify?: boolean;
|
|
1366
|
+
propId?: string;
|
|
1345
1367
|
};
|
|
1346
1368
|
if (!poseType || !action) {
|
|
1347
1369
|
return jsonResult({ success: false, error: "poseType and action parameters are required" });
|
|
@@ -1374,7 +1396,7 @@ const plugin = {
|
|
|
1374
1396
|
if (verify) {
|
|
1375
1397
|
try {
|
|
1376
1398
|
const ack = await service.sendStatusVerified(
|
|
1377
|
-
normalizedPoseType, matched.name, bubbleText, logText, playback,
|
|
1399
|
+
normalizedPoseType, matched.name, bubbleText, logText, playback, propId,
|
|
1378
1400
|
);
|
|
1379
1401
|
if (ack.warning) {
|
|
1380
1402
|
return jsonResult({
|
|
@@ -1393,6 +1415,7 @@ const plugin = {
|
|
|
1393
1415
|
action: matched.name,
|
|
1394
1416
|
bubble: bubbleText,
|
|
1395
1417
|
log: logText,
|
|
1418
|
+
propId,
|
|
1396
1419
|
});
|
|
1397
1420
|
}
|
|
1398
1421
|
|
|
@@ -1474,6 +1497,10 @@ const plugin = {
|
|
|
1474
1497
|
type: "string",
|
|
1475
1498
|
description: "Optional log content for this action. Use the same language as the current conversation.",
|
|
1476
1499
|
},
|
|
1500
|
+
propId: {
|
|
1501
|
+
type: "string",
|
|
1502
|
+
description: "Optional poseable prop ID from RoomContext.PoseableProps. When specified, the avatar is seated at this prop.",
|
|
1503
|
+
},
|
|
1477
1504
|
},
|
|
1478
1505
|
required: ["poseType", "action", "durationSeconds", "bubble"],
|
|
1479
1506
|
},
|
|
@@ -1629,7 +1656,7 @@ const plugin = {
|
|
|
1629
1656
|
name: "kichi_query_status",
|
|
1630
1657
|
label: "kichi_query_status",
|
|
1631
1658
|
description:
|
|
1632
|
-
"Query Kichi room and avatar status — includes room personnel, notes, ownerState, idlePlan, weather/time, timer snapshot, daily note quota,
|
|
1659
|
+
"Query Kichi room and avatar status — includes room personnel, notes, ownerState, idlePlan, weather/time, timer snapshot, daily note quota, `hasCreatedMusicAlbumToday`, and RoomContext.PoseableProps (poseable props with PropId, DisplayName, SupportedPoseTypes, OccupancyState). The PoseableProps list is cached internally so that kichi_action can reference a propId during regular work sync without re-querying. Use this when the user asks to check kichi status, room status, or who is in the room. Also use this before creating a new note or daily recommended music album. For heartbeat planning, use the returned idlePlan as reference when shaping the next idle plan.",
|
|
1633
1660
|
parameters: {
|
|
1634
1661
|
type: "object",
|
|
1635
1662
|
properties: {
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "kichi-forwarder",
|
|
3
3
|
"name": "Kichi Forwarder",
|
|
4
4
|
"description": "Native OpenClaw plugin for Kichi World with direct avatar control, status sync, timers, notes, and music tools",
|
|
5
|
-
"version": "0.1.2-beta.
|
|
5
|
+
"version": "0.1.2-beta.8",
|
|
6
6
|
"author": "OpenClaw",
|
|
7
7
|
"skills": ["./skills/kichi-forwarder"],
|
|
8
8
|
"configSchema": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yahaha-studio/kichi-forwarder",
|
|
3
|
-
"version": "0.1.2-beta.
|
|
3
|
+
"version": "0.1.2-beta.8",
|
|
4
4
|
"description": "Native OpenClaw plugin for Kichi World with direct avatar control, status sync, timers, notes, and music tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
package/src/service.ts
CHANGED
|
@@ -83,6 +83,7 @@ export class KichiForwarderService {
|
|
|
83
83
|
}
|
|
84
84
|
>();
|
|
85
85
|
onBotMessageReceived: BotMessageReceivedHandler | null = null;
|
|
86
|
+
private cachedRoomContext: Record<string, unknown> | null = null;
|
|
86
87
|
|
|
87
88
|
constructor(
|
|
88
89
|
private logger: PluginLogger,
|
|
@@ -166,7 +167,7 @@ export class KichiForwarderService {
|
|
|
166
167
|
});
|
|
167
168
|
}
|
|
168
169
|
|
|
169
|
-
sendStatus(poseType: PoseType | "", action: string, bubble: string, log: string, playback: ActionPlayback): void {
|
|
170
|
+
sendStatus(poseType: PoseType | "", action: string, bubble: string, log: string, playback: ActionPlayback, propId?: string): void {
|
|
170
171
|
if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN) return;
|
|
171
172
|
const payload: StatusPayload = {
|
|
172
173
|
type: "status",
|
|
@@ -177,6 +178,7 @@ export class KichiForwarderService {
|
|
|
177
178
|
bubble,
|
|
178
179
|
log,
|
|
179
180
|
playback,
|
|
181
|
+
...(propId ? { propId } : {}),
|
|
180
182
|
};
|
|
181
183
|
this.ws.send(JSON.stringify(payload));
|
|
182
184
|
}
|
|
@@ -187,6 +189,7 @@ export class KichiForwarderService {
|
|
|
187
189
|
bubble: string,
|
|
188
190
|
log: string,
|
|
189
191
|
playback: ActionPlayback,
|
|
192
|
+
propId?: string,
|
|
190
193
|
): Promise<StatusAckPayload> {
|
|
191
194
|
if (!this.identity?.authKey || this.ws?.readyState !== WebSocket.OPEN) {
|
|
192
195
|
throw new Error("Kichi websocket is not connected");
|
|
@@ -201,6 +204,7 @@ export class KichiForwarderService {
|
|
|
201
204
|
bubble,
|
|
202
205
|
log,
|
|
203
206
|
playback,
|
|
207
|
+
...(propId ? { propId } : {}),
|
|
204
208
|
};
|
|
205
209
|
return this.sendRequest<StatusAckPayload>(payload, "status_ack", 5000);
|
|
206
210
|
}
|
|
@@ -267,7 +271,11 @@ export class KichiForwarderService {
|
|
|
267
271
|
avatarId: identity.avatarId,
|
|
268
272
|
authKey: identity.authKey,
|
|
269
273
|
};
|
|
270
|
-
|
|
274
|
+
const result = await this.sendRequest<QueryStatusResultPayload>(payload, "query_status_result");
|
|
275
|
+
if (result.RoomContext && typeof result.RoomContext === "object") {
|
|
276
|
+
this.cachedRoomContext = result.RoomContext as Record<string, unknown>;
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
271
279
|
}
|
|
272
280
|
|
|
273
281
|
createNotesBoardNote(propId: string, data: string): void {
|
|
@@ -350,6 +358,8 @@ export class KichiForwarderService {
|
|
|
350
358
|
|
|
351
359
|
isConnected(): boolean { return this.ws?.readyState === WebSocket.OPEN && !!this.identity?.authKey; }
|
|
352
360
|
|
|
361
|
+
getCachedRoomContext(): Record<string, unknown> | null { return this.cachedRoomContext; }
|
|
362
|
+
|
|
353
363
|
hasValidIdentity(): boolean { return !!this.identity?.avatarId && !!this.identity?.authKey; }
|
|
354
364
|
|
|
355
365
|
isLlmRuntimeEnabled(): boolean {
|
package/src/types.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type ActionResult = {
|
|
|
17
17
|
action: string;
|
|
18
18
|
bubble: string;
|
|
19
19
|
log?: string;
|
|
20
|
+
propId?: string;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export type KichiStaticConfig = {
|
|
@@ -117,6 +118,7 @@ export type StatusPayload = {
|
|
|
117
118
|
bubble: string;
|
|
118
119
|
log: string;
|
|
119
120
|
playback: ActionPlayback;
|
|
121
|
+
propId?: string;
|
|
120
122
|
};
|
|
121
123
|
|
|
122
124
|
export type StatusAckPayload = {
|
|
@@ -124,6 +126,7 @@ export type StatusAckPayload = {
|
|
|
124
126
|
requestId: string;
|
|
125
127
|
poseType: PoseType | "";
|
|
126
128
|
action: string;
|
|
129
|
+
requestedPropId?: string;
|
|
127
130
|
warning?: string;
|
|
128
131
|
};
|
|
129
132
|
|
|
@@ -144,6 +147,7 @@ export type IdlePlanStageAction = {
|
|
|
144
147
|
durationSeconds: number;
|
|
145
148
|
bubble: string;
|
|
146
149
|
log?: string;
|
|
150
|
+
propId?: string;
|
|
147
151
|
};
|
|
148
152
|
|
|
149
153
|
export type IdlePlanStage = {
|