@ynhcj/xiaoyi-channel 0.0.88-beta → 0.0.90-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.
@@ -2,34 +2,21 @@ import { resolveXYConfig, listXYAccountIds, getDefaultXYAccountId } from "./conf
2
2
  import { xyConfigSchema } from "./config-schema.js";
3
3
  import { xyOutbound } from "./outbound.js";
4
4
  import { locationTool } from "./tools/location-tool.js";
5
- import { noteTool } from "./tools/note-tool.js";
6
- import { searchNoteTool } from "./tools/search-note-tool.js";
7
- import { modifyNoteTool } from "./tools/modify-note-tool.js";
8
- import { calendarTool } from "./tools/calendar-tool.js";
9
- import { searchCalendarTool } from "./tools/search-calendar-tool.js";
10
- import { searchContactTool } from "./tools/search-contact-tool.js";
11
- import { searchPhotoGalleryTool } from "./tools/search-photo-gallery-tool.js";
12
- import { uploadPhotoTool } from "./tools/upload-photo-tool.js";
13
5
  import { xiaoyiGuiTool } from "./tools/xiaoyi-gui-tool.js";
14
- import { callPhoneTool } from "./tools/call-phone-tool.js";
15
- import { searchMessageTool } from "./tools/search-message-tool.js";
16
- import { sendMessageTool } from "./tools/send-message-tool.js";
17
- import { searchFileTool } from "./tools/search-file-tool.js";
18
- import { uploadFileTool } from "./tools/upload-file-tool.js";
19
- import { createAlarmTool } from "./tools/create-alarm-tool.js";
20
- import { searchAlarmTool } from "./tools/search-alarm-tool.js";
21
- import { modifyAlarmTool } from "./tools/modify-alarm-tool.js";
22
- import { deleteAlarmTool } from "./tools/delete-alarm-tool.js";
23
6
  import { sendFileToUserTool } from "./tools/send-file-to-user-tool.js";
24
7
  import { viewPushResultTool } from "./tools/view-push-result-tool.js";
25
8
  import { imageReadingTool } from "./tools/image-reading-tool.js";
26
9
  import { timestampToUtc8Tool } from "./tools/timestamp-to-utc8-tool.js";
27
- import { xiaoyiCollectionTool } from "./tools/xiaoyi-collection-tool.js";
28
- import { xiaoyiAddCollectionTool } from "./tools/xiaoyi-add-collection-tool.js";
29
- import { xiaoyiDeleteCollectionTool } from "./tools/xiaoyi-delete-collection-tool.js";
30
- import { saveMediaToGalleryTool } from "./tools/save-media-to-gallery-tool.js";
31
- import { saveFileToPhoneTool } from "./tools/save-file-to-phone-tool.js";
10
+ import { sendEmailTool } from "./tools/send-email-tool.js";
32
11
  import { searchEmailTool } from "./tools/search-email-tool.js";
12
+ import { callDeviceTool } from "./tools/call-device-tool.js";
13
+ import { getNoteToolSchemaTool } from "./tools/get-note-tool-schema.js";
14
+ import { getCalendarToolSchemaTool } from "./tools/get-calendar-tool-schema.js";
15
+ import { getContactToolSchemaTool } from "./tools/get-contact-tool-schema.js";
16
+ import { getPhotoToolSchemaTool } from "./tools/get-photo-tool-schema.js";
17
+ import { getDeviceFileToolSchemaTool } from "./tools/get-device-file-tool-schema.js";
18
+ import { getAlarmToolSchemaTool } from "./tools/get-alarm-tool-schema.js";
19
+ import { getCollectionToolSchemaTool } from "./tools/get-collection-tool-schema.js";
33
20
  import { filterToolsByDevice } from "./tools/device-tool-map.js";
34
21
  import { getCurrentSessionContext } from "./tools/session-manager.js";
35
22
  import { logger } from "./utils/logger.js";
@@ -72,7 +59,7 @@ export const xyPlugin = {
72
59
  },
73
60
  outbound: xyOutbound,
74
61
  agentTools: () => {
75
- const allTools = [locationTool, noteTool, searchNoteTool, modifyNoteTool, calendarTool, searchCalendarTool, searchContactTool, searchPhotoGalleryTool, uploadPhotoTool, xiaoyiGuiTool, callPhoneTool, searchMessageTool, sendMessageTool, searchFileTool, uploadFileTool, createAlarmTool, searchAlarmTool, modifyAlarmTool, deleteAlarmTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool, xiaoyiCollectionTool, xiaoyiAddCollectionTool, xiaoyiDeleteCollectionTool, saveMediaToGalleryTool, saveFileToPhoneTool, searchEmailTool];
62
+ const allTools = [locationTool, callDeviceTool, getNoteToolSchemaTool, getCalendarToolSchemaTool, getContactToolSchemaTool, getPhotoToolSchemaTool, xiaoyiGuiTool, getDeviceFileToolSchemaTool, getAlarmToolSchemaTool, getCollectionToolSchemaTool, sendFileToUserTool, viewPushResultTool, imageReadingTool, timestampToUtc8Tool, sendEmailTool, searchEmailTool];
76
63
  const ctx = getCurrentSessionContext();
77
64
  const filtered = filterToolsByDevice(allTools, ctx?.deviceType);
78
65
  logger.log(`[DEVICE-FILTER] deviceType=${ctx?.deviceType ?? "(none)"}, tools: ${allTools.length} → ${filtered.length} (${filtered.map(t => t.name).join(", ")})`);
@@ -267,6 +267,12 @@ export function createXYReplyDispatcher(params) {
267
267
  log(`[TOOL START] Tool: ${name}, phase: ${phase}, taskId: ${currentTaskId}`);
268
268
  if (phase === "start") {
269
269
  const toolName = name || "unknown";
270
+ // call_device_tool 由自身 execute() 内部发送具体子工具名的状态更新
271
+ // get_xxx_tool_schema 是给 LLM 查 schema 用的,无需向用户展示
272
+ if (toolName === "call_device_tool" || toolName.endsWith("_tool_schema")) {
273
+ log(`[TOOL START] Skipping generic status for ${toolName}`);
274
+ return;
275
+ }
270
276
  try {
271
277
  await sendStatusUpdate({
272
278
  config,
@@ -0,0 +1,5 @@
1
+ /**
2
+ * call_device_tool - 通用端工具调度器。
3
+ * LLM 必须先通过 get_xxx_tool_schema 获取具体工具 schema,再用本工具执行。
4
+ */
5
+ export declare const callDeviceTool: any;
@@ -0,0 +1,126 @@
1
+ import { noteTool } from "./note-tool.js";
2
+ import { searchNoteTool } from "./search-note-tool.js";
3
+ import { modifyNoteTool } from "./modify-note-tool.js";
4
+ import { createAlarmTool } from "./create-alarm-tool.js";
5
+ import { searchAlarmTool } from "./search-alarm-tool.js";
6
+ import { modifyAlarmTool } from "./modify-alarm-tool.js";
7
+ import { deleteAlarmTool } from "./delete-alarm-tool.js";
8
+ import { searchContactTool } from "./search-contact-tool.js";
9
+ import { callPhoneTool } from "./call-phone-tool.js";
10
+ import { searchMessageTool } from "./search-message-tool.js";
11
+ import { sendMessageTool } from "./send-message-tool.js";
12
+ import { xiaoyiAddCollectionTool } from "./xiaoyi-add-collection-tool.js";
13
+ import { xiaoyiCollectionTool } from "./xiaoyi-collection-tool.js";
14
+ import { xiaoyiDeleteCollectionTool } from "./xiaoyi-delete-collection-tool.js";
15
+ import { calendarTool } from "./calendar-tool.js";
16
+ import { searchCalendarTool } from "./search-calendar-tool.js";
17
+ import { searchPhotoGalleryTool } from "./search-photo-gallery-tool.js";
18
+ import { uploadPhotoTool } from "./upload-photo-tool.js";
19
+ import { saveMediaToGalleryTool } from "./save-media-to-gallery-tool.js";
20
+ import { searchFileTool } from "./search-file-tool.js";
21
+ import { uploadFileTool } from "./upload-file-tool.js";
22
+ import { saveFileToPhoneTool } from "./save-file-to-phone-tool.js";
23
+ import { sendStatusUpdate } from "../formatter.js";
24
+ import { getCurrentSessionContext } from "./session-manager.js";
25
+ import { getCurrentTaskId, getCurrentMessageId } from "../task-manager.js";
26
+ /**
27
+ * 端工具注册表 —— 按 name 索引所有可通过 call_device_tool 调度的工具。
28
+ */
29
+ const deviceToolRegistry = new Map([
30
+ [noteTool.name, noteTool],
31
+ [searchNoteTool.name, searchNoteTool],
32
+ [modifyNoteTool.name, modifyNoteTool],
33
+ [createAlarmTool.name, createAlarmTool],
34
+ [searchAlarmTool.name, searchAlarmTool],
35
+ [modifyAlarmTool.name, modifyAlarmTool],
36
+ [deleteAlarmTool.name, deleteAlarmTool],
37
+ [searchContactTool.name, searchContactTool],
38
+ [callPhoneTool.name, callPhoneTool],
39
+ [searchMessageTool.name, searchMessageTool],
40
+ [sendMessageTool.name, sendMessageTool],
41
+ [xiaoyiAddCollectionTool.name, xiaoyiAddCollectionTool],
42
+ [xiaoyiCollectionTool.name, xiaoyiCollectionTool],
43
+ [xiaoyiDeleteCollectionTool.name, xiaoyiDeleteCollectionTool],
44
+ [calendarTool.name, calendarTool],
45
+ [searchCalendarTool.name, searchCalendarTool],
46
+ [searchPhotoGalleryTool.name, searchPhotoGalleryTool],
47
+ [uploadPhotoTool.name, uploadPhotoTool],
48
+ [saveMediaToGalleryTool.name, saveMediaToGalleryTool],
49
+ [searchFileTool.name, searchFileTool],
50
+ [uploadFileTool.name, uploadFileTool],
51
+ [saveFileToPhoneTool.name, saveFileToPhoneTool],
52
+ ]);
53
+ /**
54
+ * call_device_tool - 通用端工具调度器。
55
+ * LLM 必须先通过 get_xxx_tool_schema 获取具体工具 schema,再用本工具执行。
56
+ */
57
+ export const callDeviceTool = {
58
+ name: "call_device_tool",
59
+ label: "Call Device Tool",
60
+ description: "用户设备侧工具调用。必须先调用get_xxx_tool_schema获取了具体的工具schema,才能使用本工具执行对应设备侧工具。",
61
+ parameters: {
62
+ type: "object",
63
+ properties: {
64
+ toolName: {
65
+ type: "string",
66
+ description: "要调用的具体端工具名称,即get_xxx_tool_schema返回的工具的name",
67
+ },
68
+ arguments: {
69
+ type: "object",
70
+ description: "工具所需的具体参数JSON键值对",
71
+ },
72
+ },
73
+ required: ["toolName", "arguments"],
74
+ },
75
+ async execute(toolCallId, params) {
76
+ const { toolName, arguments: toolArgs } = params;
77
+ // 向用户端发送具体工具名的状态更新
78
+ const ctx = getCurrentSessionContext();
79
+ if (ctx) {
80
+ const currentTaskId = getCurrentTaskId(ctx.sessionId) ?? ctx.taskId;
81
+ const currentMessageId = getCurrentMessageId(ctx.sessionId) ?? ctx.messageId;
82
+ try {
83
+ await sendStatusUpdate({
84
+ config: ctx.config,
85
+ sessionId: ctx.sessionId,
86
+ taskId: currentTaskId,
87
+ messageId: currentMessageId,
88
+ text: `正在使用工具: ${toolName}...`,
89
+ state: "working",
90
+ });
91
+ }
92
+ catch (_) {
93
+ // 状态更新失败不影响工具执行
94
+ }
95
+ }
96
+ const tool = deviceToolRegistry.get(toolName);
97
+ if (!tool) {
98
+ return {
99
+ content: [
100
+ {
101
+ type: "text",
102
+ text: `端工具${toolName}不存在。请确保toolName为get_xxx_tool_schema返回的工具的name。`,
103
+ },
104
+ ],
105
+ };
106
+ }
107
+ try {
108
+ return await tool.execute(toolCallId, toolArgs);
109
+ }
110
+ catch (error) {
111
+ // ToolInputError (.name === "ToolInputError") 或其他参数校验错误
112
+ if (error.name === "ToolInputError") {
113
+ return {
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: `端工具参数错误:${error.message}。请确保arguments符合get_xxx_tool_schema返回的工具schema。`,
118
+ },
119
+ ],
120
+ };
121
+ }
122
+ // 非参数错误(网络超时等),直接向上抛出
123
+ throw error;
124
+ }
125
+ },
126
+ };
@@ -14,9 +14,11 @@ const DEVICE_TOOL_POLICY = {
14
14
  "send_message",
15
15
  "search_message",
16
16
  "search_contact",
17
+ "get_contact_tool_schema",
17
18
  "query_collection",
18
19
  "add_collection",
19
20
  "delete_collection",
21
+ "get_collection_tool_schema",
20
22
  ],
21
23
  },
22
24
  };
@@ -0,0 +1,16 @@
1
+ export declare const getAlarmToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,11 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { createAlarmTool } from "./create-alarm-tool.js";
3
+ import { searchAlarmTool } from "./search-alarm-tool.js";
4
+ import { modifyAlarmTool } from "./modify-alarm-tool.js";
5
+ import { deleteAlarmTool } from "./delete-alarm-tool.js";
6
+ export const getAlarmToolSchemaTool = createSchemaTool({
7
+ name: "get_alarm_tool_schema",
8
+ label: "Get Alarm Tool Schema",
9
+ description: "获取可在用户设备上创建、检索、修改、删除闹钟的相关端工具列表。",
10
+ tools: [createAlarmTool, searchAlarmTool, modifyAlarmTool, deleteAlarmTool],
11
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getCalendarToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,9 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { calendarTool } from "./calendar-tool.js";
3
+ import { searchCalendarTool } from "./search-calendar-tool.js";
4
+ export const getCalendarToolSchemaTool = createSchemaTool({
5
+ name: "get_calendar_tool_schema",
6
+ label: "Get Calendar Tool Schema",
7
+ description: "获取可在用户设备上创建、检索日程的相关端工具列表。",
8
+ tools: [calendarTool, searchCalendarTool],
9
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getCollectionToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,10 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { xiaoyiAddCollectionTool } from "./xiaoyi-add-collection-tool.js";
3
+ import { xiaoyiCollectionTool } from "./xiaoyi-collection-tool.js";
4
+ import { xiaoyiDeleteCollectionTool } from "./xiaoyi-delete-collection-tool.js";
5
+ export const getCollectionToolSchemaTool = createSchemaTool({
6
+ name: "get_collection_tool_schema",
7
+ label: "Get Collection Tool Schema",
8
+ description: "获取可在用户设备上添加、检索、删除小艺收藏中的公共知识数据的相关端工具列表。",
9
+ tools: [xiaoyiAddCollectionTool, xiaoyiCollectionTool, xiaoyiDeleteCollectionTool],
10
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getContactToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,11 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { searchContactTool } from "./search-contact-tool.js";
3
+ import { callPhoneTool } from "./call-phone-tool.js";
4
+ import { searchMessageTool } from "./search-message-tool.js";
5
+ import { sendMessageTool } from "./send-message-tool.js";
6
+ export const getContactToolSchemaTool = createSchemaTool({
7
+ name: "get_contact_tool_schema",
8
+ label: "Get Contact Tool Schema",
9
+ description: "获取可在用户设备上检索通讯录联系人信息、拨打电话、搜索短信与发送短信的相关端工具列表。",
10
+ tools: [searchContactTool, callPhoneTool, searchMessageTool, sendMessageTool],
11
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getDeviceFileToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,10 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { searchFileTool } from "./search-file-tool.js";
3
+ import { uploadFileTool } from "./upload-file-tool.js";
4
+ import { saveFileToPhoneTool } from "./save-file-to-phone-tool.js";
5
+ export const getDeviceFileToolSchemaTool = createSchemaTool({
6
+ name: "get_device_file_tool_schema",
7
+ label: "Get Device File Tool Schema",
8
+ description: "获取可在用户设备上搜索文件系统的文件、将用户设备本地文件上传到公网并获取链接、保存文件到文件管理器的相关端工具列表。",
9
+ tools: [searchFileTool, uploadFileTool, saveFileToPhoneTool],
10
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getNoteToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,10 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { noteTool } from "./note-tool.js";
3
+ import { searchNoteTool } from "./search-note-tool.js";
4
+ import { modifyNoteTool } from "./modify-note-tool.js";
5
+ export const getNoteToolSchemaTool = createSchemaTool({
6
+ name: "get_note_tool_schema",
7
+ label: "Get Note Tool Schema",
8
+ description: "获取可在用户设备上创建、搜索、追加备忘录的相关端工具列表。",
9
+ tools: [noteTool, searchNoteTool, modifyNoteTool],
10
+ });
@@ -0,0 +1,16 @@
1
+ export declare const getPhotoToolSchemaTool: {
2
+ name: string;
3
+ label: string;
4
+ description: string;
5
+ parameters: {
6
+ type: "object";
7
+ properties: {};
8
+ required: string[];
9
+ };
10
+ execute(_toolCallId: string, _params: any): Promise<{
11
+ content: {
12
+ type: "text";
13
+ text: string;
14
+ }[];
15
+ }>;
16
+ };
@@ -0,0 +1,10 @@
1
+ import { createSchemaTool } from "./schema-tool-factory.js";
2
+ import { searchPhotoGalleryTool } from "./search-photo-gallery-tool.js";
3
+ import { uploadPhotoTool } from "./upload-photo-tool.js";
4
+ import { saveMediaToGalleryTool } from "./save-media-to-gallery-tool.js";
5
+ export const getPhotoToolSchemaTool = createSchemaTool({
6
+ name: "get_photo_tool_schema",
7
+ label: "Get Photo Tool Schema",
8
+ description: "获取可在用户设备上搜索图库照片、将照片上传到公网并获取链接、保存图片或视频到图库的相关端工具列表。",
9
+ tools: [searchPhotoGalleryTool, uploadPhotoTool, saveMediaToGalleryTool],
10
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * schema-tool-factory: 创建 get_xxx_tool_schema 工具。
3
+ * 每个工具在被 LLM 调用时,返回其所包含的子工具的 name / description / parameters schema。
4
+ */
5
+ interface SchemaToolOptions {
6
+ name: string;
7
+ label: string;
8
+ description: string;
9
+ tools: any[];
10
+ }
11
+ export declare function createSchemaTool(options: SchemaToolOptions): {
12
+ name: string;
13
+ label: string;
14
+ description: string;
15
+ parameters: {
16
+ type: "object";
17
+ properties: {};
18
+ required: string[];
19
+ };
20
+ execute(_toolCallId: string, _params: any): Promise<{
21
+ content: {
22
+ type: "text";
23
+ text: string;
24
+ }[];
25
+ }>;
26
+ };
27
+ export {};
@@ -0,0 +1,32 @@
1
+ /**
2
+ * schema-tool-factory: 创建 get_xxx_tool_schema 工具。
3
+ * 每个工具在被 LLM 调用时,返回其所包含的子工具的 name / description / parameters schema。
4
+ */
5
+ export function createSchemaTool(options) {
6
+ const { name, label, description, tools } = options;
7
+ return {
8
+ name,
9
+ label,
10
+ description,
11
+ parameters: {
12
+ type: "object",
13
+ properties: {},
14
+ required: [],
15
+ },
16
+ async execute(_toolCallId, _params) {
17
+ const schemas = tools.map((t) => ({
18
+ name: t.name,
19
+ description: t.description,
20
+ parameters: t.parameters,
21
+ }));
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: JSON.stringify(schemas, null, 2),
27
+ },
28
+ ],
29
+ };
30
+ },
31
+ };
32
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * XY send email tool - sends an email via 花瓣邮箱 on user's device.
3
+ */
4
+ export declare const sendEmailTool: any;
@@ -0,0 +1,134 @@
1
+ // Send Email tool implementation
2
+ import { getXYWebSocketManager } from "../client.js";
3
+ import { sendCommand } from "../formatter.js";
4
+ import { getCurrentSessionContext } from "./session-manager.js";
5
+ class ToolInputError extends Error {
6
+ status = 400;
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = "ToolInputError";
10
+ }
11
+ }
12
+ /**
13
+ * XY send email tool - sends an email via 花瓣邮箱 on user's device.
14
+ */
15
+ export const sendEmailTool = {
16
+ name: "send_email",
17
+ label: "Send Email",
18
+ description: `在用户设备上通过花瓣邮箱发送邮件。
19
+ 注意:
20
+ a. 操作超时时间为60秒,请勿重复调用此工具
21
+ b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
22
+ c. 调用工具前需认真检查调用参数是否满足工具要求
23
+
24
+ 回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。`,
25
+ parameters: {
26
+ type: "object",
27
+ properties: {
28
+ subject: {
29
+ type: "string",
30
+ description: "邮件主题,必填",
31
+ },
32
+ to: {
33
+ type: "string",
34
+ description: "收件人邮箱地址,必填",
35
+ },
36
+ body: {
37
+ type: "string",
38
+ description: "邮件内容,必填",
39
+ },
40
+ },
41
+ required: ["subject", "to", "body"],
42
+ },
43
+ async execute(_toolCallId, params) {
44
+ if (typeof params.subject !== "string" || !params.subject.trim()) {
45
+ throw new ToolInputError("缺少必填参数 subject(邮件主题)");
46
+ }
47
+ if (typeof params.to !== "string" || !params.to.trim()) {
48
+ throw new ToolInputError("缺少必填参数 to(收件人邮箱地址)");
49
+ }
50
+ if (typeof params.body !== "string" || !params.body.trim()) {
51
+ throw new ToolInputError("缺少必填参数 body(邮件内容)");
52
+ }
53
+ const sessionContext = getCurrentSessionContext();
54
+ if (!sessionContext) {
55
+ throw new Error("No active XY session found. Send email tool can only be used during an active conversation.");
56
+ }
57
+ const { config, sessionId, taskId, messageId } = sessionContext;
58
+ const wsManager = getXYWebSocketManager(config);
59
+ const command = {
60
+ header: {
61
+ namespace: "Common",
62
+ name: "Action",
63
+ },
64
+ payload: {
65
+ cardParam: {},
66
+ executeParam: {
67
+ executeMode: "background",
68
+ intentName: "SendEmail",
69
+ bundleName: "com.huawei.hmos.email",
70
+ needUnlock: true,
71
+ actionResponse: true,
72
+ appType: "OHOS_APP",
73
+ timeOut: 5,
74
+ intentParam: {
75
+ subject: params.subject.trim(),
76
+ to: [params.to.trim()],
77
+ body: params.body.trim(),
78
+ },
79
+ permissionId: [],
80
+ achieveType: "INTENT",
81
+ },
82
+ responses: [
83
+ {
84
+ resultCode: "",
85
+ displayText: "",
86
+ ttsText: "",
87
+ },
88
+ ],
89
+ needUploadResult: true,
90
+ noHalfPage: false,
91
+ pageControlRelated: false,
92
+ },
93
+ };
94
+ return new Promise((resolve, reject) => {
95
+ const timeout = setTimeout(() => {
96
+ wsManager.off("data-event", handler);
97
+ reject(new Error("发送邮件超时(60秒)"));
98
+ }, 60000);
99
+ const handler = (event) => {
100
+ if (event.intentName === "SendEmail") {
101
+ clearTimeout(timeout);
102
+ wsManager.off("data-event", handler);
103
+ if (event.status === "success" && event.outputs) {
104
+ resolve({
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: JSON.stringify(event.outputs),
109
+ },
110
+ ],
111
+ });
112
+ }
113
+ else {
114
+ reject(new Error(`发送邮件失败: ${event.status}`));
115
+ }
116
+ }
117
+ };
118
+ wsManager.on("data-event", handler);
119
+ sendCommand({
120
+ config,
121
+ sessionId,
122
+ taskId,
123
+ messageId,
124
+ command,
125
+ })
126
+ .then(() => { })
127
+ .catch((error) => {
128
+ clearTimeout(timeout);
129
+ wsManager.off("data-event", handler);
130
+ reject(error);
131
+ });
132
+ });
133
+ },
134
+ };
@@ -18,7 +18,7 @@ export const uploadFileTool = {
18
18
  label: "Upload File",
19
19
  description: `工具能力描述:将用户本地设备文件上传并获取可公网访问的 URL。
20
20
 
21
- 前置工具调用:此工具使用前必须先调用 search_file 或者 query_collection 工具获取文件的 uri
21
+ 前置工具调用:此工具使用前必须先通过call_device_tool调用 search_file 或者 query_collection 工具获取文件的 uri
22
22
 
23
23
  工具参数说明:
24
24
  a. 入参中的fileInfos数组,每个元素必须包含mediaUri字段(对应于search_file工具或者query_collection返回结果中的uri),必须与search_file或者query_collection结果中对应的uri完全保持一致,不要自行修改。
@@ -14,7 +14,7 @@ export const uploadPhotoTool = {
14
14
  label: "Upload Photo",
15
15
  description: `工具能力描述:将用户本地设备文件回传并获取可公网访问的 URL。
16
16
 
17
- 前置工具调用:此工具使用前必须先调用 search_photo_gallery 工具获取照片的 mediaUri或者thumbnailUri
17
+ 前置工具调用:此工具使用前必须先通过call_device_tool工具调用 search_photo_gallery 工具获取照片的 mediaUri或者thumbnailUri
18
18
  工具参数说明:
19
19
  a. 入参中的mediaUris中的mediaUri必须与search_photo_gallery结果中对应的mediaUri或者thumbnailUri完全保持一致,不要自行修改,必须是file:://开头的路径。
20
20
  b. 优先使用search_photo_gallery结果中的thumbnailUri作为入参,thumbnailUri是缩略图,清晰度与文件大小都非常合适展示给用户,如果thumbnailUri不存在或者用户要求使用原图,则使用search_photo_gallery结果中对应的mediaUri
@@ -25,7 +25,7 @@ export const xiaoyiCollectionTool = {
25
25
  a. 操作超时时间为60秒,请勿重复调用此工具
26
26
  b. 如果遇到各类调用失败场景,最多只能重试一次,不可以重复调用多次。
27
27
  c. 调用工具前需认真检查调用参数是否满足工具要求
28
- d. 如果用户希望获取文件,可以使用upload_file工具完成文件上传
28
+ d. 如果用户希望获取文件,可以使用call_device_tool工具调用upload_file工具完成文件上传
29
29
 
30
30
  回复约束:如果工具返回没有授权或者其他报错,只需要完整描述没有授权或者其他报错内容即可,不需要主动给用户提供解决方案,例如告诉用户如何授权,如何解决报错等都是不需要的,请严格遵守。
31
31
  `,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynhcj/xiaoyi-channel",
3
- "version": "0.0.88-beta",
3
+ "version": "0.0.90-beta",
4
4
  "description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",