@ynhcj/xiaoyi-channel 0.0.159-beta → 0.0.159-next

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.
Files changed (70) hide show
  1. package/dist/src/bot.js +59 -5
  2. package/dist/src/cron-query-handler.d.ts +1 -11
  3. package/dist/src/cron-query-handler.js +89 -2
  4. package/dist/src/cspl/call_api.d.ts +1 -1
  5. package/dist/src/cspl/call_api.js +2 -2
  6. package/dist/src/cspl/config.js +30 -10
  7. package/dist/src/cspl/constants.d.ts +3 -0
  8. package/dist/src/cspl/constants.js +5 -0
  9. package/dist/src/cspl/sentinel_hook.js +26 -7
  10. package/dist/src/cspl/utils.d.ts +9 -3
  11. package/dist/src/cspl/utils.js +17 -11
  12. package/dist/src/file-upload.d.ts +5 -0
  13. package/dist/src/file-upload.js +102 -0
  14. package/dist/src/formatter.d.ts +30 -0
  15. package/dist/src/formatter.js +65 -10
  16. package/dist/src/monitor.js +35 -23
  17. package/dist/src/parser.d.ts +6 -0
  18. package/dist/src/parser.js +47 -1
  19. package/dist/src/provider.js +51 -17
  20. package/dist/src/reply-dispatcher.js +67 -21
  21. package/dist/src/self-evolution-handler.d.ts +1 -1
  22. package/dist/src/self-evolution-handler.js +12 -1
  23. package/dist/src/tools/calendar-tool.js +1 -1
  24. package/dist/src/tools/call-device-tool.js +0 -3
  25. package/dist/src/tools/call-phone-tool.js +1 -1
  26. package/dist/src/tools/check-plugin-privilege-tool.d.ts +6 -0
  27. package/dist/src/tools/check-plugin-privilege-tool.js +182 -0
  28. package/dist/src/tools/create-alarm-tool.js +1 -1
  29. package/dist/src/tools/create-all-tools.js +8 -8
  30. package/dist/src/tools/delete-alarm-tool.js +1 -1
  31. package/dist/src/tools/device-tool-map.js +1 -0
  32. package/dist/src/tools/discover-cross-devices-tool.js +1 -1
  33. package/dist/src/tools/display-a2ui-card-tool.d.ts +2 -0
  34. package/dist/src/tools/display-a2ui-card-tool.js +85 -0
  35. package/dist/src/tools/get-device-file-tool-schema.js +2 -3
  36. package/dist/src/tools/location-tool.js +1 -1
  37. package/dist/src/tools/modify-alarm-tool.js +1 -1
  38. package/dist/src/tools/modify-note-tool.js +1 -1
  39. package/dist/src/tools/note-tool.js +1 -1
  40. package/dist/src/tools/query-app-message-tool.js +1 -1
  41. package/dist/src/tools/query-memory-data-tool.js +1 -1
  42. package/dist/src/tools/query-todo-task-tool.js +1 -1
  43. package/dist/src/tools/save-file-to-phone-tool.js +1 -1
  44. package/dist/src/tools/save-media-to-gallery-tool.js +1 -1
  45. package/dist/src/tools/schema-tool-factory.js +1 -1
  46. package/dist/src/tools/search-alarm-tool.js +1 -1
  47. package/dist/src/tools/search-calendar-tool.js +1 -1
  48. package/dist/src/tools/search-contact-tool.js +1 -1
  49. package/dist/src/tools/search-email-tool.js +1 -1
  50. package/dist/src/tools/search-file-tool.js +5 -10
  51. package/dist/src/tools/search-note-tool.js +1 -1
  52. package/dist/src/tools/search-photo-gallery-tool.js +1 -1
  53. package/dist/src/tools/send-cross-device-task-tool.js +18 -22
  54. package/dist/src/tools/send-email-tool.js +1 -1
  55. package/dist/src/tools/send-file-to-user-tool.d.ts +1 -1
  56. package/dist/src/tools/send-file-to-user-tool.js +35 -6
  57. package/dist/src/tools/send-html-card-tool.d.ts +7 -0
  58. package/dist/src/tools/send-html-card-tool.js +113 -0
  59. package/dist/src/tools/session-manager.d.ts +6 -2
  60. package/dist/src/tools/session-manager.js +42 -7
  61. package/dist/src/tools/upload-file-tool.d.ts +1 -1
  62. package/dist/src/tools/upload-file-tool.js +3 -17
  63. package/dist/src/tools/upload-photo-tool.js +1 -1
  64. package/dist/src/tools/xiaoyi-add-collection-tool.js +2 -2
  65. package/dist/src/tools/xiaoyi-collection-tool.js +1 -1
  66. package/dist/src/tools/xiaoyi-delete-collection-tool.js +1 -1
  67. package/dist/src/tools/xiaoyi-gui-tool.js +6 -1
  68. package/dist/src/types.d.ts +10 -3
  69. package/dist/src/websocket.js +29 -8
  70. package/package.json +1 -1
@@ -1,6 +1,5 @@
1
1
  import { getXYWebSocketManager } from "../client.js";
2
2
  import { sendCommand } from "../formatter.js";
3
- import { appendRunCrossTaskFileUrls } from "./session-manager.js";
4
3
  import { getCurrentTaskId } from "../task-manager.js";
5
4
  import { logger } from "../utils/logger.js";
6
5
  /**
@@ -20,19 +19,14 @@ export function createUploadFileTool(ctx) {
20
19
  return {
21
20
  name: "upload_file",
22
21
  label: "Upload File",
23
- description: `工具能力描述:将手机或PC/电脑本地文件上传并获取可公网访问的 URL。
22
+ description: `工具能力描述:将用户设备(可以使手机或者鸿蒙PC等)本地文件上传并获取可公网访问的 URL。
24
23
 
25
24
  前置工具调用:此工具使用前必须先通过call_device_tool调用 search_file 或者 query_collection 工具获取文件的 uri
26
25
 
27
- 使用场景与调用流程:
28
- 1. 上传手机文件:直接调用此工具,无需传入 udid。
29
- 2. 上传PC/电脑文件:当用户要求上传PC/电脑上的文件时,需要先通过 find_pc_devices 工具获取设备ID(udid),然后将 udid 传入此工具。
30
-
31
26
  工具参数说明:
32
27
  a. 入参中的fileInfos数组,每个元素必须包含mediaUri字段(对应于search_file工具或者query_collection返回结果中的uri),必须与search_file或者query_collection结果中对应的uri完全保持一致,不要自行修改。
33
28
  b. fileInfos中的timeout字段是可选的,表示上传文件超时时间,单位是毫秒,默认是20000(20秒)。
34
29
  c. fileInfos 是文件在本地的信息数组(从 search_file 工具或者query_collection 工具响应中获取)。限制:每次最多支持传入 5 条文件信息。
35
- d. udid 是PC/电脑设备ID,仅在上传PC/电脑文件时需要传入(通过 find_pc_devices 工具获取)。
36
30
 
37
31
  注意事项:
38
32
  a. 操作超时时间为60秒,请勿重复调用此工具,如果超时或失败,最多重试一次。
@@ -44,11 +38,7 @@ export function createUploadFileTool(ctx) {
44
38
  // 不指定 type,允许传入数组或 JSON 字符串
45
39
  // 具体的类型验证和转换在 execute 函数内部进行
46
40
  description: "文件信息数组,每个元素包含mediaUri(必需)和timeout(可选,默认20000)。必须先通过 search_file 工具获取。每次最多支持 5 条文件信息。",
47
- },
48
- udid: {
49
- type: "string",
50
- description: "PC/电脑设备ID。当上传PC/电脑上的文件时,需要先通过 find_pc_devices 工具获取设备ID后传入。上传手机文件时不需要传入此参数。",
51
- },
41
+ }
52
42
  },
53
43
  required: ["fileInfos"],
54
44
  },
@@ -108,10 +98,6 @@ export function createUploadFileTool(ctx) {
108
98
  // Get public URLs for the files
109
99
  const currentTaskId = getCurrentTaskId(sessionId) ?? taskId;
110
100
  const fileUrls = await getFileUrls(wsManager, config, sessionId, currentTaskId, messageId, toolCallId, fileInfos, params.udid);
111
- if (ctx.runCrossTaskContext && fileUrls.length > 0) {
112
- const cachedFileUrls = appendRunCrossTaskFileUrls(fileUrls, ctx.runCrossTaskContext);
113
- logger.log(`[RunCrossTask] cached ${fileUrls.length} upload_file URL(s) for cross-task result, total=${cachedFileUrls.length}`);
114
- }
115
101
  return {
116
102
  content: [
117
103
  {
@@ -208,7 +194,7 @@ async function getFileUrls(wsManager, config, sessionId, taskId, messageId, tool
208
194
  resolve(fileUrls);
209
195
  }
210
196
  else {
211
- reject(new Error(`获取文件URL失败: ${event.status}`));
197
+ reject(new Error(`获取文件URL失败: ${JSON.stringify(event.outputs)}`));
212
198
  }
213
199
  }
214
200
  };
@@ -158,7 +158,7 @@ async function getPhotoUrls(wsManager, config, sessionId, taskId, messageId, too
158
158
  resolve(imageUrls);
159
159
  }
160
160
  else {
161
- reject(new Error(`获取照片URL失败: ${event.status}`));
161
+ reject(new Error(`获取照片URL失败: ${JSON.stringify(event.outputs)}`));
162
162
  }
163
163
  }
164
164
  };
@@ -32,7 +32,7 @@ export function createXiaoyiAddCollectionTool(ctx) {
32
32
  ● title:非必填字段,数据类型为string,功能描述是标识文件类型数据的文件名称。适用于FILE类型。
33
33
  说明:如果dataType为HYPER_LINK或TEXT,则content字段必填且不能为空;如果dataType为IMAGE或FILE,则uri字段必填且不能为空。当用户希望收藏海报、截图等图片类数据时,请将数据以图片IMAGE的形式存入到小艺帮记;当用户希望收藏电子书、笔记、报告、素材、文档、合同、协议、简历、证书、报表、日志、安装包、压缩包等描述的文件时,请将数据以文件FILE的形式存入到小艺帮记。
34
34
  当你成功收藏这个数据到小艺帮记后,请在最后显示"已成功把数据添加到[小艺帮记](vassistant://voice/main?page=CollectionPage&jumpHomePageTab=myCollection)",
35
- 请额外注意,如果当前用户的设备是鸿蒙PC,则最后显示的内容需要额外定制,内容是"已成功把数据添加到[小艺帮记](vassistant://voice/main?agentId=celia_collection_share&agentPage=CollectionPage)"
35
+ 请额外注意,如果当前用户的设备是鸿蒙PC,则最后显示的内容需要额外定制,内容是"已成功把数据添加到[小艺帮记](vassistant://voice/main?agentId=celia_collection_share&agentPage=CollectionPage&from=push&action=openFlashCardPage)"
36
36
  注意:
37
37
  a. 操作超时时间为60秒,请勿重复调用此工具
38
38
  b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
@@ -165,7 +165,7 @@ export function createXiaoyiAddCollectionTool(ctx) {
165
165
  });
166
166
  }
167
167
  else {
168
- reject(new Error(`添加小艺收藏失败: ${event.status}`));
168
+ reject(new Error(`添加小艺收藏失败: ${JSON.stringify(event.outputs)}`));
169
169
  }
170
170
  }
171
171
  };
@@ -120,7 +120,7 @@ export function createXiaoyiCollectionTool(ctx) {
120
120
  });
121
121
  }
122
122
  else {
123
- reject(new Error(`查询小艺收藏失败: ${event.status}`));
123
+ reject(new Error(`查询小艺收藏失败: ${JSON.stringify(event.outputs)}`));
124
124
  }
125
125
  }
126
126
  };
@@ -135,7 +135,7 @@ export function createXiaoyiDeleteCollectionTool(ctx) {
135
135
  });
136
136
  }
137
137
  else {
138
- reject(new Error(`删除小艺收藏失败: ${event.status}`));
138
+ reject(new Error(`删除小艺收藏失败: ${JSON.stringify(event.outputs)}`));
139
139
  }
140
140
  }
141
141
  };
@@ -2,6 +2,7 @@
2
2
  import { getXYWebSocketManager } from "../client.js";
3
3
  import { sendCommand } from "../formatter.js";
4
4
  import { getCurrentTaskId } from "../task-manager.js";
5
+ import { isCronToolCall } from "./session-manager.js";
5
6
  import { logger } from "../utils/logger.js";
6
7
  /**
7
8
  * XiaoYi GUI tool - executes phone app interactions through GUI agent.
@@ -46,6 +47,10 @@ export function createXiaoyiGuiTool(ctx) {
46
47
  if (!params.query || typeof params.query !== "string") {
47
48
  throw new Error("Missing or invalid required parameter: query must be a non-empty string");
48
49
  }
50
+ // GUI agent only works in active WebSocket sessions — reject cron-triggered calls
51
+ if (sessionId.startsWith("cron-") || isCronToolCall(toolCallId)) {
52
+ throw new Error("xiaoyi_gui_agent 不支持定时任务触发,只能在活跃对话中使用");
53
+ }
49
54
  // Get WebSocket manager
50
55
  const wsManager = getXYWebSocketManager(config);
51
56
  // Build InvokeJarvisGUIAgentRequest command
@@ -66,7 +71,7 @@ export function createXiaoyiGuiTool(ctx) {
66
71
  wsManager.off("gui-agent-response", handler);
67
72
  logger.error("超时: XiaoYi GUI Agent 操作超时(5分钟)", { toolCallId });
68
73
  reject(new Error("XiaoYi GUI Agent 操作超时(5分钟)"));
69
- }, 180000); // 5 minutes timeout
74
+ }, 300000); // 5 minutes timeout
70
75
  // Listen for GUI agent response events
71
76
  const handler = (event) => {
72
77
  // Check if this is the InvokeJarvisGUIAgentResponse we're waiting for
@@ -13,8 +13,10 @@ export interface XYChannelConfig {
13
13
  export interface A2AJsonRpcRequest {
14
14
  jsonrpc: "2.0";
15
15
  method: string;
16
- params: A2ARequestParams;
16
+ params?: A2ARequestParams;
17
17
  id: string;
18
+ /** Top-level sessionId for clearContext/tasks/cancel (no params field) */
19
+ sessionId?: string;
18
20
  }
19
21
  export interface A2AJsonRpcResponse {
20
22
  jsonrpc: "2.0";
@@ -66,7 +68,7 @@ export interface CrossDeviceTaskResultEvent {
66
68
  sessionId: string;
67
69
  code: string;
68
70
  message: string;
69
- fileUrls: string[];
71
+ sentFiles: SentFileParams[];
70
72
  status: "success" | "failed";
71
73
  rawEvent: any;
72
74
  }
@@ -76,9 +78,14 @@ export interface RunCrossTaskContext {
76
78
  isDistributed: boolean;
77
79
  networkId: string;
78
80
  isSupportAgent: boolean;
79
- fileUrls?: string[];
81
+ sentFiles: SentFileParams[];
80
82
  rawContext: any;
81
83
  }
84
+ export interface SentFileParams {
85
+ fileLocalUrls?: string[];
86
+ fileRemoteUrls?: string[];
87
+ fileNames?: string[];
88
+ }
82
89
  export interface A2ATaskArtifactUpdateEvent {
83
90
  taskId: string;
84
91
  kind: "artifact-update";
@@ -392,15 +392,36 @@ export class XYWebSocketManager extends EventEmitter {
392
392
  }
393
393
  const code = item?.payload?.code === undefined ? "" : String(item.payload.code);
394
394
  const message = typeof item?.payload?.message === "string" ? item.payload.message : "";
395
- const fileUrls = Array.isArray(item?.payload?.fileUrls)
396
- ? item.payload.fileUrls.filter((url) => typeof url === "string" && url.length > 0)
395
+ const sentFiles = Array.isArray(item?.payload?.sentFiles)
396
+ ? item.payload.sentFiles.map((entry) => {
397
+ if (!entry || typeof entry !== "object") {
398
+ return null;
399
+ }
400
+ const fileLocalUrls = Array.isArray(entry.fileLocalUrls)
401
+ ? entry.fileLocalUrls.filter((url) => typeof url === "string" && url.length > 0)
402
+ : [];
403
+ const fileRemoteUrls = Array.isArray(entry.fileRemoteUrls)
404
+ ? entry.fileRemoteUrls.filter((url) => typeof url === "string" && url.length > 0)
405
+ : [];
406
+ const fileNames = Array.isArray(entry.fileNames)
407
+ ? entry.fileNames.filter((name) => typeof name === "string" && name.length > 0)
408
+ : [];
409
+ if (fileLocalUrls.length === 0 && fileRemoteUrls.length === 0) {
410
+ return null;
411
+ }
412
+ return {
413
+ ...(fileLocalUrls.length > 0 ? { fileLocalUrls } : {}),
414
+ ...(fileRemoteUrls.length > 0 ? { fileRemoteUrls } : {}),
415
+ ...(fileNames.length > 0 && fileNames.length === fileRemoteUrls.length ? { fileNames } : {}),
416
+ };
417
+ }).filter((entry) => entry !== null)
397
418
  : [];
398
419
  const status = code === "0" ? "success" : "failed";
399
420
  const event = {
400
421
  sessionId,
401
422
  code,
402
423
  message,
403
- fileUrls,
424
+ sentFiles,
404
425
  status,
405
426
  rawEvent: item,
406
427
  };
@@ -444,7 +465,7 @@ export class XYWebSocketManager extends EventEmitter {
444
465
  networkId,
445
466
  isDistributed: true,
446
467
  isSupportAgent: true,
447
- fileUrls: [],
468
+ sentFiles: [],
448
469
  rawContext: parsed,
449
470
  };
450
471
  const request = {
@@ -602,8 +623,8 @@ export class XYWebSocketManager extends EventEmitter {
602
623
  event: item,
603
624
  });
604
625
  }
605
- else if (item.header?.namespace === "System" && item.header?.name === "CronQuery") {
606
- log.log("[XY] System.CronQuery detected, emitting cron-query-event");
626
+ else if (item.header?.namespace === "AgentEvent" && item.header?.name === "CronQuery") {
627
+ log.log("[XY] AgentEvent.CronQuery detected, emitting cron-query-event");
607
628
  this.emit("cron-query-event", {
608
629
  ...(item.payload ?? {}),
609
630
  sessionId,
@@ -691,8 +712,8 @@ export class XYWebSocketManager extends EventEmitter {
691
712
  event: item,
692
713
  });
693
714
  }
694
- else if (item.header?.namespace === "System" && item.header?.name === "CronQuery") {
695
- log.log("[XY] System.CronQuery detected (wrapped format), emitting cron-query-event");
715
+ else if (item.header?.namespace === "AgentEvent" && item.header?.name === "CronQuery") {
716
+ log.log("[XY] AgentEvent.CronQuery detected (wrapped format), emitting cron-query-event");
696
717
  this.emit("cron-query-event", {
697
718
  ...(item.payload ?? {}),
698
719
  sessionId: inboundMsg.sessionId || a2aRequest.params?.sessionId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.159-beta",
3
+ "version": "0.0.159-next",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",