@ynhcj/xiaoyi-channel 0.0.62-beta → 0.0.63-beta

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/src/bot.js CHANGED
@@ -239,6 +239,7 @@ export async function handleXYMessage(params) {
239
239
  messageId: parsed.messageId,
240
240
  agentId: route.accountId,
241
241
  };
242
+ log(`[BOT-DISPATCH] ⏳ withReplyDispatcher starting, sessionKey=${route.sessionKey}`);
242
243
  await core.channel.reply.withReplyDispatcher({
243
244
  dispatcher,
244
245
  onSettled: () => {
@@ -257,12 +258,32 @@ export async function handleXYMessage(params) {
257
258
  },
258
259
  run: () =>
259
260
  // 🔐 Use AsyncLocalStorage to provide session context to tools
260
- runWithSessionContext(sessionContext, () => core.channel.reply.dispatchReplyFromConfig({
261
- ctx: ctxPayload,
262
- cfg,
263
- dispatcher,
264
- replyOptions,
265
- })),
261
+ runWithSessionContext(sessionContext, async () => {
262
+ log(`[BOT-DISPATCH] ⏳ dispatchReplyFromConfig starting...`);
263
+ log(`[BOT-DISPATCH] - sessionKey: ${ctxPayload.SessionKey}`);
264
+ log(`[BOT-DISPATCH] - provider: ${ctxPayload.Provider}`);
265
+ log(`[BOT-DISPATCH] - surface: ${ctxPayload.Surface}`);
266
+ log(`[BOT-DISPATCH] - from: ${ctxPayload.From}`);
267
+ log(`[BOT-DISPATCH] - body length: ${ctxPayload.Body?.length ?? 0}`);
268
+ try {
269
+ const result = await core.channel.reply.dispatchReplyFromConfig({
270
+ ctx: ctxPayload,
271
+ cfg,
272
+ dispatcher,
273
+ replyOptions,
274
+ });
275
+ log(`[BOT-DISPATCH] ✅ dispatchReplyFromConfig returned`);
276
+ log(`[BOT-DISPATCH] - result: ${JSON.stringify(result)}`);
277
+ return result;
278
+ }
279
+ catch (dispatchErr) {
280
+ error(`[BOT-DISPATCH] ❌ dispatchReplyFromConfig threw`);
281
+ error(`[BOT-DISPATCH] - error name: ${dispatchErr instanceof Error ? dispatchErr.name : "unknown"}`);
282
+ error(`[BOT-DISPATCH] - error message: ${String(dispatchErr)}`);
283
+ error(`[BOT-DISPATCH] - error stack: ${dispatchErr instanceof Error ? dispatchErr.stack?.slice(0, 500) : "N/A"}`);
284
+ throw dispatchErr;
285
+ }
286
+ }),
266
287
  });
267
288
  log(`[BOT] ✅ Dispatcher completed for session: ${parsed.sessionId}`);
268
289
  log(`xy: dispatch complete (session=${parsed.sessionId})`);
@@ -24,6 +24,7 @@ import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
24
24
  import { viewPushResultTool } from "./tools/view-push-result-tool.js";
25
25
  import { imageReadingTool } from "./tools/image-reading-tool.js";
26
26
  import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
27
+ import { sendCommandToCarTool } from "./tools/send-command-to-car-tool.js";
27
28
  /**
28
29
  * Xiaoyi Channel Plugin for OpenClaw.
29
30
  * Implements Xiaoyi A2A protocol with dual WebSocket connections.
@@ -62,7 +63,7 @@ export const xyPlugin = {
62
63
  schema: xyConfigSchema,
63
64
  },
64
65
  outbound: xyOutbound,
65
- agentTools: [locationTool, noteTool, searchNoteTool, modifyNoteTool, calendarTool, searchCalendarTool, searchContactTool, searchPhotoGalleryTool, uploadPhotoTool, xiaoyiGuiTool, callPhoneTool, searchMessageTool, sendMessageTool, searchFileTool, uploadFileTool, createAlarmTool, searchAlarmTool, modifyAlarmTool, deleteAlarmTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool],
66
+ agentTools: [locationTool, noteTool, searchNoteTool, modifyNoteTool, calendarTool, searchCalendarTool, searchContactTool, searchPhotoGalleryTool, uploadPhotoTool, xiaoyiGuiTool, callPhoneTool, searchMessageTool, sendMessageTool, searchFileTool, uploadFileTool, createAlarmTool, searchAlarmTool, modifyAlarmTool, deleteAlarmTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool, sendCommandToCarTool],
66
67
  messaging: {
67
68
  normalizeTarget: (raw) => {
68
69
  const trimmed = raw.trim();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Send command to car (小艺车机) tool - sends an output command to the car's Xiaoyi system.
3
+ * The command will be received and executed on the car's Xiaoyi device.
4
+ */
5
+ export declare const sendCommandToCarTool: any;
@@ -0,0 +1,85 @@
1
+ // Send Command To Car tool implementation
2
+ import { sendCommand } from "../formatter.js";
3
+ import { getCurrentSessionContext } from "./session-manager.js";
4
+ import { logger } from "../utils/logger.js";
5
+ /**
6
+ * Send command to car (小艺车机) tool - sends an output command to the car's Xiaoyi system.
7
+ * The command will be received and executed on the car's Xiaoyi device.
8
+ */
9
+ export const sendCommandToCarTool = {
10
+ name: "send_command_to_car",
11
+ label: "Send Command To Car",
12
+ description: "将输出指令发送给小艺车机,车机小艺会接收并执行该指令。注意:请勿重复调用此工具,如果超时或失败,最多重试一次。回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案。",
13
+ parameters: {
14
+ type: "object",
15
+ properties: {
16
+ command: {
17
+ type: "string",
18
+ description: "要发送给车机的指令内容(对应intentParam中的out字段)",
19
+ },
20
+ },
21
+ required: ["command"],
22
+ },
23
+ async execute(toolCallId, params) {
24
+ // Validate command parameter
25
+ if (!params.command || typeof params.command !== "string" || params.command.trim() === "") {
26
+ throw new Error("Missing required parameter: command must be a non-empty string");
27
+ }
28
+ // Get session context
29
+ const sessionContext = getCurrentSessionContext();
30
+ if (!sessionContext) {
31
+ throw new Error("No active XY session found. Send command to car tool can only be used during an active conversation.");
32
+ }
33
+ const { config, sessionId, taskId, messageId } = sessionContext;
34
+ // Build PlayStoryBook command
35
+ const command = {
36
+ header: {
37
+ namespace: "Common",
38
+ name: "Action",
39
+ },
40
+ payload: {
41
+ cardParam: {},
42
+ executeParam: {
43
+ achieveType: "INTENT",
44
+ actionResponse: true,
45
+ bundleName: "com.huawei.vassistantcar",
46
+ dimension: "",
47
+ executeMode: "background",
48
+ intentName: "PlayStoryBook",
49
+ intentParam: {
50
+ out: params.command,
51
+ },
52
+ needUnlock: true,
53
+ permissionId: [],
54
+ timeOut: 5,
55
+ },
56
+ needUploadResult: true,
57
+ pageControlRelated: false,
58
+ responses: [
59
+ {
60
+ displayText: "",
61
+ resultCode: "",
62
+ ttsText: "",
63
+ },
64
+ ],
65
+ },
66
+ };
67
+ // Send command - fire and forget, return success once sent
68
+ await sendCommand({
69
+ config,
70
+ sessionId,
71
+ taskId,
72
+ messageId,
73
+ command,
74
+ });
75
+ logger.log("[sendCommandToCar] command sent to car successfully");
76
+ return {
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: JSON.stringify({ success: true, message: "指令已成功下发给车机" }),
81
+ },
82
+ ],
83
+ };
84
+ },
85
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.62-beta",
3
+ "version": "0.0.63-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",