@yahaha-studio/kichi-forwarder 0.1.2-beta.13 → 0.1.2-beta.14
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/README.md +2 -0
- package/dist/index.js +56 -2
- package/dist/src/service.js +25 -0
- package/index.ts +68 -2
- package/openclaw.plugin.json +2 -1
- package/package.json +1 -1
- package/skills/kichi-forwarder/SKILL.md +14 -1
- package/src/service.ts +34 -0
- package/src/types.ts +17 -0
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ It can directly control your companion's avatar in Kichi, show what it is doing,
|
|
|
12
12
|
|
|
13
13
|
- Bring your OpenClaw companion into Kichi
|
|
14
14
|
- Directly control the avatar's poses and actions in Kichi
|
|
15
|
+
- Let the avatar briefly glance at the camera when you ask for attention in chat
|
|
15
16
|
- Keep its visible state in sync while it works
|
|
16
17
|
- Plan human-like idle routines during heartbeat windows
|
|
17
18
|
- Let it leave notes for you in Kichi
|
|
@@ -36,6 +37,7 @@ Get the `host` and `avatarId` from Kichi, then use them with `kichi_switch_host`
|
|
|
36
37
|
|
|
37
38
|
- Connect to your chosen Kichi host and stay in sync while it works
|
|
38
39
|
- Directly control the Kichi avatar's poses and actions
|
|
40
|
+
- Briefly glance toward the camera when you directly ask from chat
|
|
39
41
|
- Show activity in Kichi with actions, bubbles, logs, and timers
|
|
40
42
|
- Leave notes for you on Kichi note boards
|
|
41
43
|
- Recommend music in Kichi as part of your daily routine
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
|
38
38
|
const MAX_MESSAGE_RECEIVED_PREVIEW_WIDTH = 20;
|
|
39
39
|
const MAX_AGENT_END_PREVIEW_WIDTH = 10;
|
|
40
40
|
const MESSAGE_RECEIVED_ELLIPSIS = "...";
|
|
41
|
+
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
41
42
|
const IDLE_PLAN_POMODORO_PHASES = ["focus", "shortBreak", "longBreak", "none"];
|
|
42
43
|
let cachedStaticConfig = null;
|
|
43
44
|
let cachedStaticConfigMtime = 0;
|
|
@@ -814,7 +815,7 @@ function buildKichiActionDescription(service) {
|
|
|
814
815
|
const roomContext = service?.getCachedRoomContext();
|
|
815
816
|
const poseableProps = roomContext?.PoseableProps;
|
|
816
817
|
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
|
|
818
|
+
lines.push("", "Cached RoomContext.PoseableProps (from last kichi_query_status):", JSON.stringify(poseableProps), "When using a sit or lay pose, pick the propId whose PoseableProps information best matches the current task context and whose OccupancyState is not fully_occupied. If no prop fits, omit propId.");
|
|
818
819
|
}
|
|
819
820
|
return lines.join("\n");
|
|
820
821
|
}
|
|
@@ -1238,6 +1239,59 @@ const plugin = {
|
|
|
1238
1239
|
},
|
|
1239
1240
|
});
|
|
1240
1241
|
}, { name: "kichi_action" });
|
|
1242
|
+
api.registerTool((ctx) => ({
|
|
1243
|
+
name: "kichi_glance",
|
|
1244
|
+
label: "kichi_glance",
|
|
1245
|
+
description: "Ask the Kichi avatar to briefly look at the camera. Use only for direct player chat requests such as \"look at me\" or \"look at the camera\". Do not use for heartbeat, idle planning, bot-to-bot messages, lifecycle hooks, or routine work/status sync.",
|
|
1246
|
+
parameters: {
|
|
1247
|
+
type: "object",
|
|
1248
|
+
properties: {
|
|
1249
|
+
requestId: {
|
|
1250
|
+
type: "string",
|
|
1251
|
+
description: "Optional client request ID for tracing. The websocket ack returns this ID.",
|
|
1252
|
+
},
|
|
1253
|
+
target: {
|
|
1254
|
+
type: "string",
|
|
1255
|
+
enum: ["camera"],
|
|
1256
|
+
description: "Glance target. The only supported target is camera.",
|
|
1257
|
+
},
|
|
1258
|
+
duration: {
|
|
1259
|
+
type: "number",
|
|
1260
|
+
description: "Optional glance duration in seconds. Defaults to 1.8.",
|
|
1261
|
+
},
|
|
1262
|
+
},
|
|
1263
|
+
},
|
|
1264
|
+
execute: async (_toolCallId, params) => {
|
|
1265
|
+
const locator = resolveToolLocator(ctx);
|
|
1266
|
+
const agentId = runtimeManager.resolveRuntimeAgentId(locator);
|
|
1267
|
+
if (!agentId) {
|
|
1268
|
+
return jsonResult({ success: false, error: "Failed to resolve agent-scoped Kichi runtime" });
|
|
1269
|
+
}
|
|
1270
|
+
const service = runtimeManager.getRuntime(locator) ?? runtimeManager.createRuntimeForAgent(agentId);
|
|
1271
|
+
const { requestId, target, duration } = (params || {});
|
|
1272
|
+
if (requestId !== undefined && typeof requestId !== "string") {
|
|
1273
|
+
return jsonResult({ success: false, error: "requestId must be a string when provided" });
|
|
1274
|
+
}
|
|
1275
|
+
const normalizedTarget = target === undefined ? "camera" : target;
|
|
1276
|
+
if (normalizedTarget !== "camera") {
|
|
1277
|
+
return jsonResult({ success: false, error: "target must be camera" });
|
|
1278
|
+
}
|
|
1279
|
+
const normalizedDuration = duration === undefined ? DEFAULT_GLANCE_DURATION_SECONDS : duration;
|
|
1280
|
+
if (typeof normalizedDuration !== "number" || !Number.isFinite(normalizedDuration) || normalizedDuration <= 0) {
|
|
1281
|
+
return jsonResult({ success: false, error: "duration must be a positive finite number" });
|
|
1282
|
+
}
|
|
1283
|
+
if (!service.hasValidIdentity() || !service.isConnected()) {
|
|
1284
|
+
return jsonResult({ success: false, error: "Not connected to Kichi world" });
|
|
1285
|
+
}
|
|
1286
|
+
try {
|
|
1287
|
+
const ack = await service.sendGlance("camera", normalizedDuration, typeof requestId === "string" ? requestId : undefined);
|
|
1288
|
+
return jsonResult({ success: true, ...ack });
|
|
1289
|
+
}
|
|
1290
|
+
catch (error) {
|
|
1291
|
+
return jsonResult({ success: false, error: `Failed to send glance: ${error}` });
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
}), { name: "kichi_glance" });
|
|
1241
1295
|
api.registerTool((ctx) => ({
|
|
1242
1296
|
name: "kichi_idle_plan",
|
|
1243
1297
|
label: "kichi_idle_plan",
|
|
@@ -1466,7 +1520,7 @@ const plugin = {
|
|
|
1466
1520
|
api.registerTool((ctx) => ({
|
|
1467
1521
|
name: "kichi_query_status",
|
|
1468
1522
|
label: "kichi_query_status",
|
|
1469
|
-
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.",
|
|
1523
|
+
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, Description, 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.",
|
|
1470
1524
|
parameters: {
|
|
1471
1525
|
type: "object",
|
|
1472
1526
|
properties: {
|
package/dist/src/service.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as path from "path";
|
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
6
6
|
const DEFAULT_LLM_RUNTIME_ENABLED = true;
|
|
7
|
+
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
7
8
|
const JOIN_SOURCE_FILE_NAME = "join-source.json";
|
|
8
9
|
export class KichiForwarderService {
|
|
9
10
|
logger;
|
|
@@ -177,6 +178,30 @@ export class KichiForwarderService {
|
|
|
177
178
|
this.ws.send(JSON.stringify(payload));
|
|
178
179
|
return true;
|
|
179
180
|
}
|
|
181
|
+
async sendGlance(target, durationSeconds = DEFAULT_GLANCE_DURATION_SECONDS, requestId) {
|
|
182
|
+
const identity = this.requireIdentity();
|
|
183
|
+
if (!identity) {
|
|
184
|
+
throw new Error("Missing Kichi identity");
|
|
185
|
+
}
|
|
186
|
+
if (this.ws?.readyState !== WebSocket.OPEN) {
|
|
187
|
+
throw new Error("Kichi websocket is not connected");
|
|
188
|
+
}
|
|
189
|
+
if (target !== "camera") {
|
|
190
|
+
throw new Error("target must be camera");
|
|
191
|
+
}
|
|
192
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
|
|
193
|
+
throw new Error("duration must be a positive finite number");
|
|
194
|
+
}
|
|
195
|
+
const payload = {
|
|
196
|
+
type: "kichi_glance",
|
|
197
|
+
requestId: requestId?.trim() || randomUUID(),
|
|
198
|
+
avatarId: identity.avatarId,
|
|
199
|
+
authKey: identity.authKey,
|
|
200
|
+
target,
|
|
201
|
+
duration: durationSeconds,
|
|
202
|
+
};
|
|
203
|
+
return this.sendRequest(payload, "kichi_glance_ack", 5000);
|
|
204
|
+
}
|
|
180
205
|
async queryStatus(requestId) {
|
|
181
206
|
const identity = this.requireIdentity();
|
|
182
207
|
if (!identity) {
|
package/index.ts
CHANGED
|
@@ -60,6 +60,7 @@ const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
|
60
60
|
const MAX_MESSAGE_RECEIVED_PREVIEW_WIDTH = 20;
|
|
61
61
|
const MAX_AGENT_END_PREVIEW_WIDTH = 10;
|
|
62
62
|
const MESSAGE_RECEIVED_ELLIPSIS = "...";
|
|
63
|
+
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
63
64
|
const IDLE_PLAN_POMODORO_PHASES = ["focus", "shortBreak", "longBreak", "none"] as const;
|
|
64
65
|
let cachedStaticConfig: KichiStaticConfig | null = null;
|
|
65
66
|
let cachedStaticConfigMtime = 0;
|
|
@@ -1014,7 +1015,7 @@ function buildKichiActionDescription(service?: KichiForwarderService): string {
|
|
|
1014
1015
|
"",
|
|
1015
1016
|
"Cached RoomContext.PoseableProps (from last kichi_query_status):",
|
|
1016
1017
|
JSON.stringify(poseableProps),
|
|
1017
|
-
"When using a sit or lay pose, pick the propId whose
|
|
1018
|
+
"When using a sit or lay pose, pick the propId whose PoseableProps information best matches the current task context and whose OccupancyState is not fully_occupied. If no prop fits, omit propId.",
|
|
1018
1019
|
);
|
|
1019
1020
|
}
|
|
1020
1021
|
|
|
@@ -1478,6 +1479,71 @@ const plugin = {
|
|
|
1478
1479
|
});
|
|
1479
1480
|
},
|
|
1480
1481
|
})}, { name: "kichi_action" });
|
|
1482
|
+
|
|
1483
|
+
api.registerTool((ctx) => ({
|
|
1484
|
+
name: "kichi_glance",
|
|
1485
|
+
label: "kichi_glance",
|
|
1486
|
+
description:
|
|
1487
|
+
"Ask the Kichi avatar to briefly look at the camera. Use only for direct player chat requests such as \"look at me\" or \"look at the camera\". Do not use for heartbeat, idle planning, bot-to-bot messages, lifecycle hooks, or routine work/status sync.",
|
|
1488
|
+
parameters: {
|
|
1489
|
+
type: "object",
|
|
1490
|
+
properties: {
|
|
1491
|
+
requestId: {
|
|
1492
|
+
type: "string",
|
|
1493
|
+
description: "Optional client request ID for tracing. The websocket ack returns this ID.",
|
|
1494
|
+
},
|
|
1495
|
+
target: {
|
|
1496
|
+
type: "string",
|
|
1497
|
+
enum: ["camera"],
|
|
1498
|
+
description: "Glance target. The only supported target is camera.",
|
|
1499
|
+
},
|
|
1500
|
+
duration: {
|
|
1501
|
+
type: "number",
|
|
1502
|
+
description: "Optional glance duration in seconds. Defaults to 1.8.",
|
|
1503
|
+
},
|
|
1504
|
+
},
|
|
1505
|
+
},
|
|
1506
|
+
execute: async (_toolCallId, params) => {
|
|
1507
|
+
const locator = resolveToolLocator(ctx);
|
|
1508
|
+
const agentId = runtimeManager.resolveRuntimeAgentId(locator);
|
|
1509
|
+
if (!agentId) {
|
|
1510
|
+
return jsonResult({ success: false, error: "Failed to resolve agent-scoped Kichi runtime" });
|
|
1511
|
+
}
|
|
1512
|
+
const service = runtimeManager.getRuntime(locator) ?? runtimeManager.createRuntimeForAgent(agentId);
|
|
1513
|
+
const { requestId, target, duration } = (params || {}) as {
|
|
1514
|
+
requestId?: unknown;
|
|
1515
|
+
target?: unknown;
|
|
1516
|
+
duration?: unknown;
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
if (requestId !== undefined && typeof requestId !== "string") {
|
|
1520
|
+
return jsonResult({ success: false, error: "requestId must be a string when provided" });
|
|
1521
|
+
}
|
|
1522
|
+
const normalizedTarget = target === undefined ? "camera" : target;
|
|
1523
|
+
if (normalizedTarget !== "camera") {
|
|
1524
|
+
return jsonResult({ success: false, error: "target must be camera" });
|
|
1525
|
+
}
|
|
1526
|
+
const normalizedDuration = duration === undefined ? DEFAULT_GLANCE_DURATION_SECONDS : duration;
|
|
1527
|
+
if (typeof normalizedDuration !== "number" || !Number.isFinite(normalizedDuration) || normalizedDuration <= 0) {
|
|
1528
|
+
return jsonResult({ success: false, error: "duration must be a positive finite number" });
|
|
1529
|
+
}
|
|
1530
|
+
if (!service.hasValidIdentity() || !service.isConnected()) {
|
|
1531
|
+
return jsonResult({ success: false, error: "Not connected to Kichi world" });
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
try {
|
|
1535
|
+
const ack = await service.sendGlance(
|
|
1536
|
+
"camera",
|
|
1537
|
+
normalizedDuration,
|
|
1538
|
+
typeof requestId === "string" ? requestId : undefined,
|
|
1539
|
+
);
|
|
1540
|
+
return jsonResult({ success: true, ...ack });
|
|
1541
|
+
} catch (error) {
|
|
1542
|
+
return jsonResult({ success: false, error: `Failed to send glance: ${error}` });
|
|
1543
|
+
}
|
|
1544
|
+
},
|
|
1545
|
+
}), { name: "kichi_glance" });
|
|
1546
|
+
|
|
1481
1547
|
api.registerTool((ctx) => ({
|
|
1482
1548
|
name: "kichi_idle_plan",
|
|
1483
1549
|
label: "kichi_idle_plan",
|
|
@@ -1717,7 +1783,7 @@ const plugin = {
|
|
|
1717
1783
|
name: "kichi_query_status",
|
|
1718
1784
|
label: "kichi_query_status",
|
|
1719
1785
|
description:
|
|
1720
|
-
"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.",
|
|
1786
|
+
"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, Description, 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.",
|
|
1721
1787
|
parameters: {
|
|
1722
1788
|
type: "object",
|
|
1723
1789
|
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.14",
|
|
6
6
|
"author": "OpenClaw",
|
|
7
7
|
"skills": ["./skills/kichi-forwarder"],
|
|
8
8
|
"contracts": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"kichi_leave",
|
|
14
14
|
"kichi_connection_status",
|
|
15
15
|
"kichi_action",
|
|
16
|
+
"kichi_glance",
|
|
16
17
|
"kichi_idle_plan",
|
|
17
18
|
"kichi_clock",
|
|
18
19
|
"kichi_query_status",
|
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.14",
|
|
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",
|
|
@@ -74,7 +74,7 @@ Use this order unless the user asks for a different explicit action. For install
|
|
|
74
74
|
3. If the requested `avatarId` differs from the current host's connected `avatarId`, call `kichi_leave` first when the old avatar is still joined, then call `kichi_join` with the requested `avatarId`.
|
|
75
75
|
4. If no `authKey` is available, call `kichi_join`.
|
|
76
76
|
5. If `authKey` exists but websocket is not open, call `kichi_rejoin` or wait for automatic reconnect and rejoin.
|
|
77
|
-
6. Use `kichi_action`, `kichi_clock`, note board tools, and music album tools after status is ready.
|
|
77
|
+
6. Use `kichi_action`, `kichi_glance`, `kichi_clock`, note board tools, and music album tools after status is ready.
|
|
78
78
|
|
|
79
79
|
## Tools
|
|
80
80
|
|
|
@@ -141,6 +141,19 @@ Use this for direct Kichi avatar control as well as lifecycle sync.
|
|
|
141
141
|
- For most work, prefer a sit pose and switch actions inside the same task as the work moves between stages.
|
|
142
142
|
- The current action lists are injected into prompt context before the model chooses `kichi_action`.
|
|
143
143
|
|
|
144
|
+
### kichi_glance
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
kichi_glance(target: "camera", duration: 1.8)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Use this only when the player directly asks from chat for attention such as "look at me" or "look at the camera".
|
|
151
|
+
|
|
152
|
+
- `target`: optional. Only `camera` is supported.
|
|
153
|
+
- `duration`: optional seconds, defaults to `1.8`.
|
|
154
|
+
- `requestId`: optional tracing ID; the websocket ack returns it.
|
|
155
|
+
- Do not use this for heartbeat, idle plans, bot messages, lifecycle hooks, or routine work/status sync.
|
|
156
|
+
|
|
144
157
|
### kichi_idle_plan
|
|
145
158
|
|
|
146
159
|
Use this for the avatar's heartbeat idle plan.
|
package/src/service.ts
CHANGED
|
@@ -13,6 +13,9 @@ import type {
|
|
|
13
13
|
ClockPayload,
|
|
14
14
|
CreateMusicAlbumPayload,
|
|
15
15
|
CreateNotesBoardNotePayload,
|
|
16
|
+
GlanceAckPayload,
|
|
17
|
+
GlancePayload,
|
|
18
|
+
GlanceTarget,
|
|
16
19
|
HookNotifyPayload,
|
|
17
20
|
HookNotifyType,
|
|
18
21
|
IdlePlanContent,
|
|
@@ -33,6 +36,7 @@ import type {
|
|
|
33
36
|
|
|
34
37
|
const MAX_NOTEBOARD_TEXT_LENGTH = 200;
|
|
35
38
|
const DEFAULT_LLM_RUNTIME_ENABLED = true;
|
|
39
|
+
const DEFAULT_GLANCE_DURATION_SECONDS = 1.8;
|
|
36
40
|
const JOIN_SOURCE_FILE_NAME = "join-source.json";
|
|
37
41
|
|
|
38
42
|
type AckFailureResult = {
|
|
@@ -264,6 +268,36 @@ export class KichiForwarderService {
|
|
|
264
268
|
return true;
|
|
265
269
|
}
|
|
266
270
|
|
|
271
|
+
async sendGlance(
|
|
272
|
+
target: GlanceTarget,
|
|
273
|
+
durationSeconds = DEFAULT_GLANCE_DURATION_SECONDS,
|
|
274
|
+
requestId?: string,
|
|
275
|
+
): Promise<GlanceAckPayload> {
|
|
276
|
+
const identity = this.requireIdentity();
|
|
277
|
+
if (!identity) {
|
|
278
|
+
throw new Error("Missing Kichi identity");
|
|
279
|
+
}
|
|
280
|
+
if (this.ws?.readyState !== WebSocket.OPEN) {
|
|
281
|
+
throw new Error("Kichi websocket is not connected");
|
|
282
|
+
}
|
|
283
|
+
if (target !== "camera") {
|
|
284
|
+
throw new Error("target must be camera");
|
|
285
|
+
}
|
|
286
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
|
|
287
|
+
throw new Error("duration must be a positive finite number");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const payload: GlancePayload = {
|
|
291
|
+
type: "kichi_glance",
|
|
292
|
+
requestId: requestId?.trim() || randomUUID(),
|
|
293
|
+
avatarId: identity.avatarId,
|
|
294
|
+
authKey: identity.authKey,
|
|
295
|
+
target,
|
|
296
|
+
duration: durationSeconds,
|
|
297
|
+
};
|
|
298
|
+
return this.sendRequest<GlanceAckPayload>(payload, "kichi_glance_ack", 5000);
|
|
299
|
+
}
|
|
300
|
+
|
|
267
301
|
async queryStatus(requestId?: string): Promise<QueryStatusResultPayload> {
|
|
268
302
|
const identity = this.requireIdentity();
|
|
269
303
|
if (!identity) {
|
package/src/types.ts
CHANGED
|
@@ -132,6 +132,23 @@ export type StatusAckPayload = {
|
|
|
132
132
|
warning?: string;
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
+
export type GlanceTarget = "camera";
|
|
136
|
+
|
|
137
|
+
export type GlancePayload = {
|
|
138
|
+
type: "kichi_glance";
|
|
139
|
+
requestId: string;
|
|
140
|
+
avatarId: string;
|
|
141
|
+
authKey: string;
|
|
142
|
+
target: GlanceTarget;
|
|
143
|
+
duration: number;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export type GlanceAckPayload = {
|
|
147
|
+
type: "kichi_glance_ack";
|
|
148
|
+
requestId: string;
|
|
149
|
+
target: GlanceTarget;
|
|
150
|
+
};
|
|
151
|
+
|
|
135
152
|
export type HookNotifyType = "message_received" | "before_send_message";
|
|
136
153
|
|
|
137
154
|
export type HookNotifyPayload = {
|