@wecom/wecom-openclaw-plugin 2026.7.2 → 2026.8.17-beta.1
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 +33 -4
- package/dist/index.js +14 -21
- package/dist/src/cli/argv.d.ts +36 -0
- package/dist/src/cli/argv.js +155 -0
- package/dist/src/cli/const.d.ts +94 -0
- package/dist/src/cli/const.js +107 -0
- package/dist/src/cli/credentials.d.ts +54 -0
- package/dist/src/cli/credentials.js +342 -0
- package/dist/src/cli/index.d.ts +5 -0
- package/dist/src/cli/index.js +5 -0
- package/dist/src/cli/legacy-tool-warning.d.ts +12 -0
- package/dist/src/cli/legacy-tool-warning.js +20 -0
- package/dist/src/cli/locate.d.ts +32 -0
- package/dist/src/cli/locate.js +196 -0
- package/dist/src/cli/process-launcher.d.ts +1 -0
- package/dist/src/cli/process-launcher.js +1 -0
- package/dist/src/cli/process-output.d.ts +14 -0
- package/dist/src/cli/process-output.js +43 -0
- package/dist/src/cli/tool.d.ts +46 -0
- package/dist/src/cli/tool.js +363 -0
- package/dist/src/const.d.ts +0 -8
- package/dist/src/const.js +0 -14
- package/dist/src/monitor.js +1 -12
- package/dist/src/state-manager.d.ts +0 -19
- package/dist/src/state-manager.js +1 -34
- package/dist/src/utils.d.ts +27 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/skills/wecom-send-media/SKILL.md +2 -0
- package/skills/wecom-send-template-card/SKILL.md +1 -1
- package/skills/wecomcli-calendar/SKILL.md +302 -0
- package/skills/wecomcli-calendar/references/calendar-agenda.md +228 -0
- package/skills/wecomcli-calendar/references/calendar-cancel.md +110 -0
- package/skills/wecomcli-calendar/references/calendar-create.md +240 -0
- package/skills/wecomcli-calendar/references/calendar-freebusy.md +209 -0
- package/skills/wecomcli-calendar/references/calendar-meeting-room.md +172 -0
- package/skills/wecomcli-calendar/references/calendar-search.md +208 -0
- package/skills/wecomcli-calendar/references/calendar-update.md +274 -0
- package/skills/wecomcli-contact/SKILL.md +59 -0
- package/skills/wecomcli-disk/SKILL.md +401 -0
- package/skills/wecomcli-doc/SKILL.md +140 -0
- package/skills/wecomcli-doc/references/doc-contents-append.md +22 -0
- package/skills/wecomcli-doc/references/doc-contents-overwrite.md +29 -0
- package/skills/wecomcli-doc/references/doc-create.md +161 -0
- package/skills/wecomcli-doc/scripts/build_docx.py +1375 -0
- package/skills/wecomcli-doc-manage/SKILL.md +135 -0
- package/skills/wecomcli-doc-manage/references/doc-members-update.md +26 -0
- package/skills/wecomcli-doc-manage/references/doc-names-update.md +22 -0
- package/skills/wecomcli-doc-manage/references/doc-rules-update.md +24 -0
- package/skills/wecomcli-email/SKILL.md +216 -0
- package/skills/wecomcli-email/references/forward-mail.md +131 -0
- package/skills/wecomcli-email/references/get-mail.md +168 -0
- package/skills/wecomcli-email/references/reply-mail.md +140 -0
- package/skills/wecomcli-email/references/search-mail.md +113 -0
- package/skills/wecomcli-email/references/security.md +53 -0
- package/skills/wecomcli-email/references/send-mail.md +186 -0
- package/skills/wecomcli-email/references/send-schedule.md +83 -0
- package/skills/wecomcli-media/SKILL.md +100 -0
- package/skills/wecomcli-meeting/SKILL.md +374 -0
- package/skills/wecomcli-meeting/references/meeting-cancel.md +115 -0
- package/skills/wecomcli-meeting/references/meeting-create.md +169 -0
- package/skills/wecomcli-meeting/references/meeting-list.md +228 -0
- package/skills/wecomcli-meeting/references/meeting-original-get.md +100 -0
- package/skills/wecomcli-meeting/references/meeting-search.md +175 -0
- package/skills/wecomcli-meeting/references/meeting-update.md +219 -0
- package/skills/wecomcli-message/SKILL.md +213 -0
- package/skills/wecomcli-preflight/SKILL.md +147 -0
- package/skills/wecomcli-sheet/SKILL.md +177 -0
- package/skills/wecomcli-sheet/references/sheet-contents-update.md +49 -0
- package/skills/wecomcli-sheet/references/sheet-ranges-get.md +47 -0
- package/skills/wecomcli-sheet/references/sheet-rows-append.md +47 -0
- package/skills/wecomcli-sheet/references/sheet-subsheets-add.md +28 -0
- package/skills/wecomcli-sheet/references/sheet-subsheets-delete.md +22 -0
- package/skills/wecomcli-smartpage/SKILL.md +172 -0
- package/skills/wecomcli-smartpage/references/data-driven-pages.md +50 -0
- package/skills/wecomcli-smartpage/references/formula/arraylist.md +369 -0
- package/skills/wecomcli-smartpage/references/formula/datetime.md +283 -0
- package/skills/wecomcli-smartpage/references/formula/logic.md +247 -0
- package/skills/wecomcli-smartpage/references/formula/math.md +362 -0
- package/skills/wecomcli-smartpage/references/formula/operators.md +246 -0
- package/skills/wecomcli-smartpage/references/formula/pageblock.md +76 -0
- package/skills/wecomcli-smartpage/references/formula/templates.md +410 -0
- package/skills/wecomcli-smartpage/references/formula/text.md +377 -0
- package/skills/wecomcli-smartpage/references/formula/user.md +22 -0
- package/skills/wecomcli-smartpage/references/formula-reference.md +192 -0
- package/skills/wecomcli-smartpage/references/mdx-syntax.md +739 -0
- package/skills/wecomcli-smartpage/references/smartpage-edit.md +519 -0
- package/skills/wecomcli-smartsheet/SKILL.md +153 -0
- package/skills/wecomcli-smartsheet/assets/templates/README.md +53 -0
- package/skills/wecomcli-smartsheet/assets/templates/ai_efficiency.md +709 -0
- package/skills/wecomcli-smartsheet/assets/templates/connect_to_app.md +380 -0
- package/skills/wecomcli-smartsheet/assets/templates/financial_accounting.md +369 -0
- package/skills/wecomcli-smartsheet/assets/templates/hr_and_administration.md +475 -0
- package/skills/wecomcli-smartsheet/assets/templates/ledger_records.md +156 -0
- package/skills/wecomcli-smartsheet/assets/templates/manufacturing.md +395 -0
- package/skills/wecomcli-smartsheet/assets/templates/marketing.md +186 -0
- package/skills/wecomcli-smartsheet/assets/templates/office_essentials.md +299 -0
- package/skills/wecomcli-smartsheet/assets/templates/personal_efficiency.md +70 -0
- package/skills/wecomcli-smartsheet/assets/templates/procurement_logistics.md +325 -0
- package/skills/wecomcli-smartsheet/assets/templates/project_management.md +564 -0
- package/skills/wecomcli-smartsheet/assets/templates/rd_process_customer.md +222 -0
- package/skills/wecomcli-smartsheet/assets/templates/rd_process_ops.md +105 -0
- package/skills/wecomcli-smartsheet/assets/templates/rd_process_project.md +109 -0
- package/skills/wecomcli-smartsheet/assets/templates/rd_process_research.md +92 -0
- package/skills/wecomcli-smartsheet/assets/templates/sales_and_operations.md +446 -0
- package/skills/wecomcli-smartsheet/assets/templates/store_management.md +431 -0
- package/skills/wecomcli-smartsheet/assets/templates/team_tasks.md +274 -0
- package/skills/wecomcli-smartsheet/assets/templates/wechat_customer.md +384 -0
- package/skills/wecomcli-smartsheet/assets/templates/work_report.md +100 -0
- package/skills/wecomcli-smartsheet/references/common.md +145 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-chart-types.md +95 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-edit.md +611 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-field-types.md +438 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-formula.md +845 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-read.md +411 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-record-values.md +203 -0
- package/skills/wecomcli-smartsheet/references/smart-sheet-view-types.md +356 -0
- package/skills/{wecom-smartsheet/references/webhook-examples.md → wecomcli-smartsheet/references/smart-sheet-webhook-examples.md} +23 -32
- package/skills/wecomcli-smartsheet/references/smart-sheet-webhook.md +169 -0
- package/skills/wecomcli-todo/SKILL.md +75 -0
- package/skills/wecomcli-todo/references/todo-create.md +139 -0
- package/skills/wecomcli-todo/references/todo-delete.md +65 -0
- package/skills/wecomcli-todo/references/todo-finish.md +74 -0
- package/skills/wecomcli-todo/references/todo-get.md +68 -0
- package/skills/wecomcli-todo/references/todo-list.md +135 -0
- package/skills/wecomcli-todo/references/todo-update.md +114 -0
- package/dist/src/mcp/index.d.ts +0 -6
- package/dist/src/mcp/index.js +0 -10
- package/dist/src/mcp/interceptors/biz-error.d.ts +0 -11
- package/dist/src/mcp/interceptors/biz-error.js +0 -69
- package/dist/src/mcp/interceptors/doc-auth-error.d.ts +0 -10
- package/dist/src/mcp/interceptors/doc-auth-error.js +0 -171
- package/dist/src/mcp/interceptors/index.d.ts +0 -35
- package/dist/src/mcp/interceptors/index.js +0 -70
- package/dist/src/mcp/interceptors/msg-media.d.ts +0 -11
- package/dist/src/mcp/interceptors/msg-media.js +0 -133
- package/dist/src/mcp/interceptors/smartpage-create.d.ts +0 -30
- package/dist/src/mcp/interceptors/smartpage-create.js +0 -132
- package/dist/src/mcp/interceptors/smartpage-export.d.ts +0 -17
- package/dist/src/mcp/interceptors/smartpage-export.js +0 -87
- package/dist/src/mcp/interceptors/smartsheet-upload.d.ts +0 -22
- package/dist/src/mcp/interceptors/smartsheet-upload.js +0 -263
- package/dist/src/mcp/interceptors/types.d.ts +0 -64
- package/dist/src/mcp/interceptors/types.js +0 -7
- package/dist/src/mcp/schema.d.ts +0 -11
- package/dist/src/mcp/schema.js +0 -99
- package/dist/src/mcp/tool.d.ts +0 -63
- package/dist/src/mcp/tool.js +0 -224
- package/dist/src/mcp/transport.d.ts +0 -94
- package/dist/src/mcp/transport.js +0 -549
- package/skills/wecom-contact/SKILL.md +0 -162
- package/skills/wecom-doc/SKILL.md +0 -127
- package/skills/wecom-meeting/SKILL.md +0 -441
- package/skills/wecom-meeting/references/example-full.md +0 -30
- package/skills/wecom-meeting/references/example-reminder.md +0 -46
- package/skills/wecom-meeting/references/example-security.md +0 -22
- package/skills/wecom-meeting/references/response-get-meeting-info.md +0 -148
- package/skills/wecom-msg/SKILL.md +0 -157
- package/skills/wecom-msg/references/api-get-messages.md +0 -93
- package/skills/wecom-msg/references/api-get-msg-chat-list.md +0 -58
- package/skills/wecom-msg/references/api-get-msg-media.md +0 -44
- package/skills/wecom-msg/references/api-send-message.md +0 -39
- package/skills/wecom-preflight/SKILL.md +0 -141
- package/skills/wecom-schedule/SKILL.md +0 -161
- package/skills/wecom-schedule/references/api-check-availability.md +0 -56
- package/skills/wecom-schedule/references/api-create-schedule.md +0 -38
- package/skills/wecom-schedule/references/api-get-schedule-detail.md +0 -81
- package/skills/wecom-schedule/references/api-update-schedule.md +0 -32
- package/skills/wecom-schedule/references/ref-reminders.md +0 -24
- package/skills/wecom-sheet/SKILL.md +0 -131
- package/skills/wecom-sheet/references/sheet-add-sub.md +0 -54
- package/skills/wecom-sheet/references/sheet-append-data.md +0 -64
- package/skills/wecom-sheet/references/sheet-delete-sub.md +0 -38
- package/skills/wecom-sheet/references/sheet-update-range-data.md +0 -95
- package/skills/wecom-smartpage/SKILL.md +0 -119
- package/skills/wecom-smartpage/references/smartpage-create.md +0 -130
- package/skills/wecom-smartpage/references/smartpage-export.md +0 -168
- package/skills/wecom-smartsheet/SKILL.md +0 -241
- package/skills/wecom-smartsheet/references/smartsheet-cell-value-formats.md +0 -163
- package/skills/wecom-smartsheet/references/smartsheet-field-types.md +0 -44
- package/skills/wecom-smartsheet/references/smartsheet-get-records.md +0 -187
- package/skills/wecom-smartsheet/references/webhook-fallback.md +0 -183
- package/skills/wecom-todo/SKILL.md +0 -392
- package/skills/wecom-todo/examples/workflows.md +0 -163
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartpage_create 请求拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* smartpage_create 的 pages 数组中,每个 page 可能包含 page_filepath 字段
|
|
6
|
-
* (指向本地 markdown 文件),用于避免在命令行传递大段文本内容。
|
|
7
|
-
* 本拦截器在 beforeCall 阶段遍历 pages 数组,逐个读取 page_filepath
|
|
8
|
-
* 指向的本地文件内容,填入 page_content 字段,并移除 page_filepath。
|
|
9
|
-
*
|
|
10
|
-
* 入参约定:
|
|
11
|
-
* wecom_mcp call doc smartpage_create '{
|
|
12
|
-
* "title": "主页标题",
|
|
13
|
-
* "pages": [
|
|
14
|
-
* {"page_title": "页面1", "page_filepath": "/tmp/page1.md", "content_type": "markdown"},
|
|
15
|
-
* {"page_title": "页面2", "page_filepath": "/tmp/page2.md", "content_type": "markdown"}
|
|
16
|
-
* ]
|
|
17
|
-
* }'
|
|
18
|
-
*
|
|
19
|
-
* 拦截器行为:
|
|
20
|
-
* 1. 检测 args.pages 数组
|
|
21
|
-
* 2. 校验文件大小:单文件不超过 10MB,所有文件总计不超过 20MB
|
|
22
|
-
* 3. 遍历每个 page,若存在 page_filepath 则读取本地文件内容
|
|
23
|
-
* 4. 将文件内容填入 page_content 字段,移除 page_filepath
|
|
24
|
-
* 5. 返回修改后的完整 args
|
|
25
|
-
*
|
|
26
|
-
* 传给 MCP Server 的格式:
|
|
27
|
-
* { "title": "...", "pages": [{"page_title": "...", "page_content": "...", "content_type": "..."}] }
|
|
28
|
-
*/
|
|
29
|
-
import type { CallInterceptor } from "./types.js";
|
|
30
|
-
export declare const smartpageCreateInterceptor: CallInterceptor;
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartpage_create 请求拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* smartpage_create 的 pages 数组中,每个 page 可能包含 page_filepath 字段
|
|
6
|
-
* (指向本地 markdown 文件),用于避免在命令行传递大段文本内容。
|
|
7
|
-
* 本拦截器在 beforeCall 阶段遍历 pages 数组,逐个读取 page_filepath
|
|
8
|
-
* 指向的本地文件内容,填入 page_content 字段,并移除 page_filepath。
|
|
9
|
-
*
|
|
10
|
-
* 入参约定:
|
|
11
|
-
* wecom_mcp call doc smartpage_create '{
|
|
12
|
-
* "title": "主页标题",
|
|
13
|
-
* "pages": [
|
|
14
|
-
* {"page_title": "页面1", "page_filepath": "/tmp/page1.md", "content_type": "markdown"},
|
|
15
|
-
* {"page_title": "页面2", "page_filepath": "/tmp/page2.md", "content_type": "markdown"}
|
|
16
|
-
* ]
|
|
17
|
-
* }'
|
|
18
|
-
*
|
|
19
|
-
* 拦截器行为:
|
|
20
|
-
* 1. 检测 args.pages 数组
|
|
21
|
-
* 2. 校验文件大小:单文件不超过 10MB,所有文件总计不超过 20MB
|
|
22
|
-
* 3. 遍历每个 page,若存在 page_filepath 则读取本地文件内容
|
|
23
|
-
* 4. 将文件内容填入 page_content 字段,移除 page_filepath
|
|
24
|
-
* 5. 返回修改后的完整 args
|
|
25
|
-
*
|
|
26
|
-
* 传给 MCP Server 的格式:
|
|
27
|
-
* { "title": "...", "pages": [{"page_title": "...", "page_content": "...", "content_type": "..."}] }
|
|
28
|
-
*/
|
|
29
|
-
import * as fs from "node:fs/promises";
|
|
30
|
-
// ============================================================================
|
|
31
|
-
// 常量
|
|
32
|
-
// ============================================================================
|
|
33
|
-
/** 单个 page_filepath 文件大小上限:10MB */
|
|
34
|
-
const MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024;
|
|
35
|
-
/** 所有 page_filepath 文件总大小上限:20MB */
|
|
36
|
-
const MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024;
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// 内部辅助函数
|
|
39
|
-
// ============================================================================
|
|
40
|
-
/**
|
|
41
|
-
* 校验所有 page_filepath 的文件大小
|
|
42
|
-
*
|
|
43
|
-
* 使用 fs.stat 在读取文件内容之前检查大小,避免超大文件被加载到内存。
|
|
44
|
-
* - 单文件 > 10MB → 报错
|
|
45
|
-
* - 所有文件累计 > 20MB → 报错
|
|
46
|
-
*/
|
|
47
|
-
async function validateFileSize(pages) {
|
|
48
|
-
let totalSize = 0;
|
|
49
|
-
for (let i = 0; i < pages.length; i++) {
|
|
50
|
-
const filePath = pages[i].page_filepath;
|
|
51
|
-
if (typeof filePath !== "string" || !filePath)
|
|
52
|
-
continue;
|
|
53
|
-
let stat;
|
|
54
|
-
try {
|
|
55
|
-
stat = await fs.stat(filePath);
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
// stat 失败不在这里处理,留给后续 readFile 阶段抛出更详细的错误
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (stat.size > MAX_SINGLE_FILE_SIZE) {
|
|
62
|
-
console.error(`[mcp] smartpage_create: pages[${i}] 文件 "${filePath}" ` +
|
|
63
|
-
`大小 ${(stat.size / 1024 / 1024).toFixed(1)}MB 超过单文件上限 10MB`);
|
|
64
|
-
throw new Error("内容大小超出限制,无法创建");
|
|
65
|
-
}
|
|
66
|
-
totalSize += stat.size;
|
|
67
|
-
if (totalSize > MAX_TOTAL_FILE_SIZE) {
|
|
68
|
-
console.error(`[mcp] smartpage_create: 累计文件大小 ${(totalSize / 1024 / 1024).toFixed(1)}MB ` +
|
|
69
|
-
`超过总上限 20MB(在 pages[${i}] "${filePath}" 处超出)`);
|
|
70
|
-
throw new Error("内容大小超出限制,无法创建");
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (totalSize > 0) {
|
|
74
|
-
console.log(`[mcp] smartpage_create: 文件大小校验通过,总计 ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/** 异步解析 pages 中的 page_filepath,返回 BeforeCallOptions */
|
|
78
|
-
async function resolvePages(ctx, pages) {
|
|
79
|
-
console.log(`[mcp] smartpage_create: 开始解析 ${pages.length} 个 page 的 page_filepath`);
|
|
80
|
-
// 阶段 1:文件大小校验(stat 阶段,不读内容)
|
|
81
|
-
await validateFileSize(pages);
|
|
82
|
-
// 阶段 2:读取文件内容
|
|
83
|
-
const resolvedPages = await Promise.all(pages.map(async (page, index) => {
|
|
84
|
-
const filePath = page.page_filepath;
|
|
85
|
-
if (typeof filePath !== "string" || !filePath) {
|
|
86
|
-
// 该 page 没有 page_filepath,保留原样(可能已有 page_content)
|
|
87
|
-
return page;
|
|
88
|
-
}
|
|
89
|
-
let fileContent;
|
|
90
|
-
try {
|
|
91
|
-
fileContent = await fs.readFile(filePath, "utf-8");
|
|
92
|
-
}
|
|
93
|
-
catch (err) {
|
|
94
|
-
throw new Error(`smartpage_create: pages[${index}] 无法读取文件 "${filePath}": ${err instanceof Error ? err.message : String(err)}`);
|
|
95
|
-
}
|
|
96
|
-
console.log(`[mcp] smartpage_create: pages[${index}] 读取成功 "${filePath}" (${fileContent.length} chars)`);
|
|
97
|
-
// 构造新的 page 对象:填入 page_content,移除 page_filepath
|
|
98
|
-
const { page_filepath: _, ...rest } = page;
|
|
99
|
-
return { ...rest, page_content: fileContent };
|
|
100
|
-
}));
|
|
101
|
-
console.log(`[mcp] smartpage_create: 所有 page_filepath 解析完成`);
|
|
102
|
-
// 返回修改后的完整 args
|
|
103
|
-
return {
|
|
104
|
-
args: {
|
|
105
|
-
...ctx.args,
|
|
106
|
-
pages: resolvedPages,
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
// ============================================================================
|
|
111
|
-
// 拦截器实现
|
|
112
|
-
// ============================================================================
|
|
113
|
-
export const smartpageCreateInterceptor = {
|
|
114
|
-
name: "smartpage-create",
|
|
115
|
-
/** 仅对 doc 品类的 smartpage_create 方法生效 */
|
|
116
|
-
match: (ctx) => ctx.category === "doc" && ctx.method === "smartpage_create",
|
|
117
|
-
/** 遍历 pages 数组,逐个读取 page_filepath 填入 page_content */
|
|
118
|
-
beforeCall(ctx) {
|
|
119
|
-
const pages = ctx.args.pages;
|
|
120
|
-
if (!Array.isArray(pages) || pages.length === 0) {
|
|
121
|
-
// 没有 pages 数组,不做拦截
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
// 检查是否有任何 page 包含 page_filepath
|
|
125
|
-
const hasFilePath = pages.some((p) => typeof p.page_filepath === "string" && p.page_filepath);
|
|
126
|
-
if (!hasFilePath) {
|
|
127
|
-
// 所有 page 都没有 page_filepath(可能直接传了 page_content),不做拦截
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
return resolvePages(ctx, pages);
|
|
131
|
-
},
|
|
132
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartpage_get_export_result 响应拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* MCP Server 返回的 smartpage_get_export_result 响应中,当 task_done=true 时
|
|
6
|
-
* 会包含 content 字段(markdown 文本内容)。该内容可能很大,直接返回给 LLM
|
|
7
|
-
* 会消耗大量 token。
|
|
8
|
-
*
|
|
9
|
-
* 本拦截器在 afterCall 阶段:
|
|
10
|
-
* 1. 检测 task_done=true 且存在 content 字段
|
|
11
|
-
* 2. 将 content 保存到本地文件(使用与 msg-media 一致的媒体目录)
|
|
12
|
-
* 3. 用 content_path(文件路径)替换 content 字段
|
|
13
|
-
*
|
|
14
|
-
* 这样 LLM 只看到轻量的文件路径信息,Skill 可通过文件路径读取完整内容。
|
|
15
|
-
*/
|
|
16
|
-
import type { CallInterceptor } from "./types.js";
|
|
17
|
-
export declare const smartpageExportInterceptor: CallInterceptor;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartpage_get_export_result 响应拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* MCP Server 返回的 smartpage_get_export_result 响应中,当 task_done=true 时
|
|
6
|
-
* 会包含 content 字段(markdown 文本内容)。该内容可能很大,直接返回给 LLM
|
|
7
|
-
* 会消耗大量 token。
|
|
8
|
-
*
|
|
9
|
-
* 本拦截器在 afterCall 阶段:
|
|
10
|
-
* 1. 检测 task_done=true 且存在 content 字段
|
|
11
|
-
* 2. 将 content 保存到本地文件(使用与 msg-media 一致的媒体目录)
|
|
12
|
-
* 3. 用 content_path(文件路径)替换 content 字段
|
|
13
|
-
*
|
|
14
|
-
* 这样 LLM 只看到轻量的文件路径信息,Skill 可通过文件路径读取完整内容。
|
|
15
|
-
*/
|
|
16
|
-
import { getWeComRuntime } from "../../runtime.js";
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// 拦截器实现
|
|
19
|
-
// ============================================================================
|
|
20
|
-
export const smartpageExportInterceptor = {
|
|
21
|
-
name: "smartpage-export",
|
|
22
|
-
/** 仅对 doc 品类的 smartpage_get_export_result 方法生效 */
|
|
23
|
-
match: (ctx) => ctx.category === "doc" && ctx.method === "smartpage_get_export_result",
|
|
24
|
-
/** 拦截响应:将 markdown content 保存为本地文件 */
|
|
25
|
-
async afterCall(_ctx, result) {
|
|
26
|
-
return interceptExportResponse(result);
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
// ============================================================================
|
|
30
|
-
// 内部实现
|
|
31
|
-
// ============================================================================
|
|
32
|
-
/**
|
|
33
|
-
* 拦截 smartpage_get_export_result 的 MCP 响应
|
|
34
|
-
*
|
|
35
|
-
* 1. 从 MCP result 的 content[].text 中提取业务 JSON
|
|
36
|
-
* 2. 检测 task_done=true 且存在 content 字段
|
|
37
|
-
* 3. 将 content(markdown 文本)通过 saveMediaBuffer 保存到本地媒体目录
|
|
38
|
-
* 4. 构造新响应:移除 content,添加 content_path
|
|
39
|
-
*/
|
|
40
|
-
async function interceptExportResponse(result) {
|
|
41
|
-
// 1. 提取 MCP result 中的 content 数组
|
|
42
|
-
const content = result?.content;
|
|
43
|
-
if (!Array.isArray(content))
|
|
44
|
-
return result;
|
|
45
|
-
const textItem = content.find((c) => c.type === "text" && typeof c.text === "string");
|
|
46
|
-
if (!textItem)
|
|
47
|
-
return result;
|
|
48
|
-
// 2. 解析业务 JSON
|
|
49
|
-
let bizData;
|
|
50
|
-
try {
|
|
51
|
-
bizData = JSON.parse(textItem.text);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
// 非 JSON 格式,原样返回
|
|
55
|
-
return result;
|
|
56
|
-
}
|
|
57
|
-
// 3. 校验:errcode !== 0 或 task_done 不为 true 或无 content 时原样返回
|
|
58
|
-
if (bizData.errcode !== 0)
|
|
59
|
-
return result;
|
|
60
|
-
if (bizData.task_done !== true)
|
|
61
|
-
return result;
|
|
62
|
-
if (typeof bizData.content !== "string")
|
|
63
|
-
return result;
|
|
64
|
-
const markdownContent = bizData.content;
|
|
65
|
-
console.log(`[mcp] smartpage_get_export_result: 拦截 content (${markdownContent.length} chars),保存到本地文件`);
|
|
66
|
-
// 4. 将 markdown 内容通过 saveMediaBuffer 保存到本地媒体目录
|
|
67
|
-
// 使用 text/markdown 类型,与 msg-media 拦截器保持一致的路径管理
|
|
68
|
-
const buffer = Buffer.from(markdownContent, "utf-8");
|
|
69
|
-
const core = getWeComRuntime();
|
|
70
|
-
const saved = await core.channel.media.saveMediaBuffer(buffer, "text/markdown", "inbound", undefined, // maxBytes: markdown 文本通常不大,使用默认限制
|
|
71
|
-
"smartpage_export.md");
|
|
72
|
-
console.log(`[mcp] smartpage_get_export_result: 已保存到 ${saved.path}`);
|
|
73
|
-
// 5. 构造新响应:移除 content,添加 content_path
|
|
74
|
-
const newBizData = {
|
|
75
|
-
errcode: bizData.errcode,
|
|
76
|
-
errmsg: bizData.errmsg ?? "ok",
|
|
77
|
-
task_done: true,
|
|
78
|
-
content_path: saved.path,
|
|
79
|
-
};
|
|
80
|
-
// 6. 返回修改后的 MCP result 结构
|
|
81
|
-
return {
|
|
82
|
-
content: [{
|
|
83
|
-
type: "text",
|
|
84
|
-
text: JSON.stringify(newBizData),
|
|
85
|
-
}],
|
|
86
|
-
};
|
|
87
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartsheet_add_records / smartsheet_update_records 本地文件上传拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* 大模型在调用 smartsheet_add_records / smartsheet_update_records 时,
|
|
6
|
-
* 可在 CellImageValue 中传入 image_path(本地图片路径)代替 image_url/title,
|
|
7
|
-
* 或在 CellAttachmentValue 中传入 file_path(本地文件路径)代替 file_id。
|
|
8
|
-
*
|
|
9
|
-
* 本拦截器在 beforeCall 阶段:
|
|
10
|
-
* 1. 深度扫描 records[].values 中的所有字段值,收集含 image_path / file_path 的单元格
|
|
11
|
-
* 2. 校验文件大小:单文件不超过 10MB,所有文件总计不超过 20MB
|
|
12
|
-
* 3. 并行读取本地文件 → base64 编码 → 调用 MCP 上传接口
|
|
13
|
-
* - image_path → upload_doc_image → 获取 image_url
|
|
14
|
-
* - file_path → upload_doc_file → 获取 file_id
|
|
15
|
-
* 4. 用上传结果替换原字段,移除 image_path / file_path
|
|
16
|
-
* 5. 返回修改后的完整 args
|
|
17
|
-
*
|
|
18
|
-
* 传给 MCP Server 的始终是标准协议格式(image_url / file_id),
|
|
19
|
-
* MCP Server 不需要感知 image_path / file_path 的存在。
|
|
20
|
-
*/
|
|
21
|
-
import type { CallInterceptor } from "./types.js";
|
|
22
|
-
export declare const smartsheetUploadInterceptor: CallInterceptor;
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* smartsheet_add_records / smartsheet_update_records 本地文件上传拦截器
|
|
3
|
-
*
|
|
4
|
-
* 核心逻辑:
|
|
5
|
-
* 大模型在调用 smartsheet_add_records / smartsheet_update_records 时,
|
|
6
|
-
* 可在 CellImageValue 中传入 image_path(本地图片路径)代替 image_url/title,
|
|
7
|
-
* 或在 CellAttachmentValue 中传入 file_path(本地文件路径)代替 file_id。
|
|
8
|
-
*
|
|
9
|
-
* 本拦截器在 beforeCall 阶段:
|
|
10
|
-
* 1. 深度扫描 records[].values 中的所有字段值,收集含 image_path / file_path 的单元格
|
|
11
|
-
* 2. 校验文件大小:单文件不超过 10MB,所有文件总计不超过 20MB
|
|
12
|
-
* 3. 并行读取本地文件 → base64 编码 → 调用 MCP 上传接口
|
|
13
|
-
* - image_path → upload_doc_image → 获取 image_url
|
|
14
|
-
* - file_path → upload_doc_file → 获取 file_id
|
|
15
|
-
* 4. 用上传结果替换原字段,移除 image_path / file_path
|
|
16
|
-
* 5. 返回修改后的完整 args
|
|
17
|
-
*
|
|
18
|
-
* 传给 MCP Server 的始终是标准协议格式(image_url / file_id),
|
|
19
|
-
* MCP Server 不需要感知 image_path / file_path 的存在。
|
|
20
|
-
*/
|
|
21
|
-
import * as fs from "node:fs/promises";
|
|
22
|
-
import * as path from "node:path";
|
|
23
|
-
import { sendJsonRpc } from "../transport.js";
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// 常量
|
|
26
|
-
// ============================================================================
|
|
27
|
-
/** 单个文件大小上限:10MB */
|
|
28
|
-
const MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024;
|
|
29
|
-
/** 所有文件总大小上限:20MB */
|
|
30
|
-
const MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024;
|
|
31
|
-
/** 上传请求超时时间(毫秒):单次上传最大 10MB base64,给足时间 */
|
|
32
|
-
const UPLOAD_TIMEOUT_MS = 60_000;
|
|
33
|
-
/** beforeCall 整体超时延长到 120s(可能有多个文件并行上传) */
|
|
34
|
-
const INTERCEPTOR_TIMEOUT_MS = 120_000;
|
|
35
|
-
/** 日志前缀 */
|
|
36
|
-
const LOG_TAG = "[mcp] smartsheet-upload:";
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// 内部辅助函数
|
|
39
|
-
// ============================================================================
|
|
40
|
-
/**
|
|
41
|
-
* 深度扫描 records 中所有含 image_path / file_path 的单元格值对象,
|
|
42
|
-
* 返回待上传任务列表。
|
|
43
|
-
*
|
|
44
|
-
* records 结构:
|
|
45
|
-
* [{ values: { "字段A": [{ image_path: "..." }], "字段B": [{ file_path: "..." }] } }]
|
|
46
|
-
*
|
|
47
|
-
* 字段值可能是数组(图片/附件/文本等)或标量(数字/布尔等),
|
|
48
|
-
* 仅对数组中的对象元素进行扫描。
|
|
49
|
-
*/
|
|
50
|
-
function collectUploadTasks(records) {
|
|
51
|
-
const tasks = [];
|
|
52
|
-
for (const record of records) {
|
|
53
|
-
const values = record.values;
|
|
54
|
-
if (!values || typeof values !== "object")
|
|
55
|
-
continue;
|
|
56
|
-
for (const fieldKey of Object.keys(values)) {
|
|
57
|
-
const fieldValue = values[fieldKey];
|
|
58
|
-
if (!Array.isArray(fieldValue))
|
|
59
|
-
continue;
|
|
60
|
-
for (const cellValue of fieldValue) {
|
|
61
|
-
if (!cellValue || typeof cellValue !== "object")
|
|
62
|
-
continue;
|
|
63
|
-
const cell = cellValue;
|
|
64
|
-
if (typeof cell.image_path === "string" && cell.image_path) {
|
|
65
|
-
tasks.push({
|
|
66
|
-
kind: "image",
|
|
67
|
-
filePath: cell.image_path,
|
|
68
|
-
title: typeof cell.title === "string" ? cell.title : undefined,
|
|
69
|
-
cellValue: cell,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
else if (typeof cell.file_path === "string" && cell.file_path) {
|
|
73
|
-
tasks.push({
|
|
74
|
-
kind: "file",
|
|
75
|
-
filePath: cell.file_path,
|
|
76
|
-
cellValue: cell,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return tasks;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* 校验所有待上传文件的大小
|
|
86
|
-
*
|
|
87
|
-
* - 单文件 > 10MB → 报错
|
|
88
|
-
* - 所有文件累计 > 20MB → 报错
|
|
89
|
-
*/
|
|
90
|
-
async function validateFileSizes(tasks) {
|
|
91
|
-
let totalSize = 0;
|
|
92
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
93
|
-
const task = tasks[i];
|
|
94
|
-
let stat;
|
|
95
|
-
try {
|
|
96
|
-
stat = await fs.stat(task.filePath);
|
|
97
|
-
}
|
|
98
|
-
catch (err) {
|
|
99
|
-
throw new Error(`${LOG_TAG} 无法访问文件 "${task.filePath}": ${err instanceof Error ? err.message : String(err)}`);
|
|
100
|
-
}
|
|
101
|
-
if (!stat.isFile()) {
|
|
102
|
-
throw new Error(`${LOG_TAG} "${task.filePath}" 不是一个文件`);
|
|
103
|
-
}
|
|
104
|
-
if (stat.size > MAX_SINGLE_FILE_SIZE) {
|
|
105
|
-
throw new Error(`${LOG_TAG} 文件 "${task.filePath}" 大小 ${(stat.size / 1024 / 1024).toFixed(1)}MB 超过单文件上限 10MB`);
|
|
106
|
-
}
|
|
107
|
-
totalSize += stat.size;
|
|
108
|
-
if (totalSize > MAX_TOTAL_FILE_SIZE) {
|
|
109
|
-
throw new Error(`${LOG_TAG} 累计文件大小 ${(totalSize / 1024 / 1024).toFixed(1)}MB 超过总上限 20MB(在文件 "${task.filePath}" 处超出)`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (totalSize > 0) {
|
|
113
|
-
console.log(`${LOG_TAG} 文件大小校验通过,共 ${tasks.length} 个文件,总计 ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* 执行单个图片上传任务
|
|
118
|
-
*
|
|
119
|
-
* 读取本地文件 → base64 → 调用 upload_doc_image → 替换 cellValue
|
|
120
|
-
*/
|
|
121
|
-
async function executeImageUpload(task, docLocator) {
|
|
122
|
-
const buffer = await fs.readFile(task.filePath);
|
|
123
|
-
const base64Content = buffer.toString("base64");
|
|
124
|
-
const fileName = path.basename(task.filePath);
|
|
125
|
-
console.log(`${LOG_TAG} 上传图片: "${task.filePath}" (${(buffer.length / 1024).toFixed(0)}KB)`);
|
|
126
|
-
const result = await sendJsonRpc("doc", "tools/call", {
|
|
127
|
-
name: "upload_doc_image",
|
|
128
|
-
arguments: {
|
|
129
|
-
...docLocator,
|
|
130
|
-
base64_content: base64Content,
|
|
131
|
-
},
|
|
132
|
-
}, { timeoutMs: UPLOAD_TIMEOUT_MS });
|
|
133
|
-
// 从 MCP result 中提取业务响应
|
|
134
|
-
const bizData = extractBizData(result, "upload_doc_image");
|
|
135
|
-
const imageUrl = bizData.url;
|
|
136
|
-
if (!imageUrl) {
|
|
137
|
-
throw new Error(`${LOG_TAG} upload_doc_image 未返回 url,文件: "${task.filePath}"`);
|
|
138
|
-
}
|
|
139
|
-
// 替换 cellValue:设置 image_url + title,移除 image_path
|
|
140
|
-
task.cellValue.image_url = imageUrl;
|
|
141
|
-
task.cellValue.title = task.title || fileName;
|
|
142
|
-
delete task.cellValue.image_path;
|
|
143
|
-
console.log(`${LOG_TAG} 图片上传成功: "${task.filePath}" → image_url="${imageUrl}"`);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* 执行单个文件上传任务
|
|
147
|
-
*
|
|
148
|
-
* 读取本地文件 → base64 → 调用 upload_doc_file → 替换 cellValue
|
|
149
|
-
*/
|
|
150
|
-
async function executeFileUpload(task) {
|
|
151
|
-
const buffer = await fs.readFile(task.filePath);
|
|
152
|
-
const base64Content = buffer.toString("base64");
|
|
153
|
-
const fileName = path.basename(task.filePath);
|
|
154
|
-
console.log(`${LOG_TAG} 上传文件: "${task.filePath}" (${(buffer.length / 1024).toFixed(0)}KB)`);
|
|
155
|
-
const result = await sendJsonRpc("doc", "tools/call", {
|
|
156
|
-
name: "upload_doc_file",
|
|
157
|
-
arguments: {
|
|
158
|
-
file_name: fileName,
|
|
159
|
-
file_base64_content: base64Content,
|
|
160
|
-
},
|
|
161
|
-
}, { timeoutMs: UPLOAD_TIMEOUT_MS });
|
|
162
|
-
// 从 MCP result 中提取业务响应
|
|
163
|
-
const bizData = extractBizData(result, "upload_doc_file");
|
|
164
|
-
const fileId = bizData.fileid;
|
|
165
|
-
if (!fileId) {
|
|
166
|
-
throw new Error(`${LOG_TAG} upload_doc_file 未返回 fileid,文件: "${task.filePath}"`);
|
|
167
|
-
}
|
|
168
|
-
// 替换 cellValue:设置 file_id,移除 file_path
|
|
169
|
-
task.cellValue.file_id = fileId;
|
|
170
|
-
delete task.cellValue.file_path;
|
|
171
|
-
console.log(`${LOG_TAG} 文件上传成功: "${task.filePath}" → file_id="${fileId}"`);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* 从 MCP tools/call 返回结构中提取业务 JSON 数据
|
|
175
|
-
*
|
|
176
|
-
* MCP result 格式:{ content: [{ type: "text", text: "{...json...}" }] }
|
|
177
|
-
*/
|
|
178
|
-
function extractBizData(result, interfaceName) {
|
|
179
|
-
const content = result?.content;
|
|
180
|
-
if (!Array.isArray(content)) {
|
|
181
|
-
throw new Error(`${LOG_TAG} ${interfaceName} 响应格式异常:缺少 content 数组`);
|
|
182
|
-
}
|
|
183
|
-
const textItem = content.find((c) => c.type === "text" && typeof c.text === "string");
|
|
184
|
-
if (!textItem) {
|
|
185
|
-
throw new Error(`${LOG_TAG} ${interfaceName} 响应格式异常:content 中无 text 类型条目`);
|
|
186
|
-
}
|
|
187
|
-
let bizData;
|
|
188
|
-
try {
|
|
189
|
-
bizData = JSON.parse(textItem.text);
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
throw new Error(`${LOG_TAG} ${interfaceName} 响应非 JSON: ${textItem.text.slice(0, 200)}`);
|
|
193
|
-
}
|
|
194
|
-
if (bizData.errcode !== 0) {
|
|
195
|
-
throw new Error(`${LOG_TAG} ${interfaceName} 业务错误: errcode=${bizData.errcode}, errmsg=${bizData.errmsg ?? "unknown"}`);
|
|
196
|
-
}
|
|
197
|
-
return bizData;
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* 从 args 中提取文档定位参数(docid 或 url),用于 upload_doc_image
|
|
201
|
-
*/
|
|
202
|
-
function extractDocLocator(args) {
|
|
203
|
-
if (typeof args.docid === "string" && args.docid) {
|
|
204
|
-
return { docid: args.docid };
|
|
205
|
-
}
|
|
206
|
-
if (typeof args.url === "string" && args.url) {
|
|
207
|
-
return { url: args.url };
|
|
208
|
-
}
|
|
209
|
-
throw new Error(`${LOG_TAG} args 中缺少 docid 或 url,无法调用 upload_doc_image`);
|
|
210
|
-
}
|
|
211
|
-
// ============================================================================
|
|
212
|
-
// 拦截器实现
|
|
213
|
-
// ============================================================================
|
|
214
|
-
export const smartsheetUploadInterceptor = {
|
|
215
|
-
name: "smartsheet-upload",
|
|
216
|
-
/** 对 doc 品类的 smartsheet_add_records / smartsheet_update_records 生效 */
|
|
217
|
-
match: (ctx) => ctx.category === "doc" &&
|
|
218
|
-
(ctx.method === "smartsheet_add_records" || ctx.method === "smartsheet_update_records"),
|
|
219
|
-
/** 扫描 records 中的 image_path / file_path,上传后替换为 image_url / file_id */
|
|
220
|
-
beforeCall(ctx) {
|
|
221
|
-
const records = ctx.args.records;
|
|
222
|
-
if (!Array.isArray(records) || records.length === 0) {
|
|
223
|
-
return undefined;
|
|
224
|
-
}
|
|
225
|
-
// 收集所有待上传任务
|
|
226
|
-
const tasks = collectUploadTasks(records);
|
|
227
|
-
if (tasks.length === 0) {
|
|
228
|
-
return undefined;
|
|
229
|
-
}
|
|
230
|
-
console.log(`${LOG_TAG} 检测到 ${tasks.length} 个本地文件待上传`);
|
|
231
|
-
// 异步执行上传流程
|
|
232
|
-
return resolveUploads(ctx, tasks);
|
|
233
|
-
},
|
|
234
|
-
};
|
|
235
|
-
/**
|
|
236
|
-
* 执行文件校验和并行上传,返回替换后的 args
|
|
237
|
-
*/
|
|
238
|
-
async function resolveUploads(ctx, tasks) {
|
|
239
|
-
// 阶段 1:文件大小校验
|
|
240
|
-
await validateFileSizes(tasks);
|
|
241
|
-
// 提取文档定位参数(仅图片上传需要)
|
|
242
|
-
const hasImageTasks = tasks.some((t) => t.kind === "image");
|
|
243
|
-
let docLocator = {};
|
|
244
|
-
if (hasImageTasks) {
|
|
245
|
-
docLocator = extractDocLocator(ctx.args);
|
|
246
|
-
}
|
|
247
|
-
// 阶段 2:并行执行所有上传任务
|
|
248
|
-
// 上传完毕后 task.cellValue 已被原地修改(image_path/file_path 已替换为 image_url/file_id)
|
|
249
|
-
const uploadStart = performance.now();
|
|
250
|
-
await Promise.all(tasks.map((task) => {
|
|
251
|
-
if (task.kind === "image") {
|
|
252
|
-
return executeImageUpload(task, docLocator);
|
|
253
|
-
}
|
|
254
|
-
return executeFileUpload(task);
|
|
255
|
-
}));
|
|
256
|
-
const uploadMs = (performance.now() - uploadStart).toFixed(1);
|
|
257
|
-
console.log(`${LOG_TAG} 全部上传完成,共 ${tasks.length} 个文件,耗时 ${uploadMs}ms`);
|
|
258
|
-
// args 中的 records 已被原地修改,返回完整 args + 延长超时
|
|
259
|
-
return {
|
|
260
|
-
args: { ...ctx.args },
|
|
261
|
-
timeoutMs: INTERCEPTOR_TIMEOUT_MS,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP call 拦截器类型定义
|
|
3
|
-
*
|
|
4
|
-
* 拦截器用于在 tools/call 调用前后注入特殊逻辑,
|
|
5
|
-
* 如修改超时配置、变换响应结果等,避免在 tool.ts 中堆积 if/else。
|
|
6
|
-
*/
|
|
7
|
-
import type { SendJsonRpcOptions } from "../transport.js";
|
|
8
|
-
/** MCP call 调用的上下文 */
|
|
9
|
-
export interface CallContext {
|
|
10
|
-
/** MCP 品类,对应 mcpConfig 中的 key,如 doc、contact */
|
|
11
|
-
category: string;
|
|
12
|
-
/** 调用的 MCP 方法名 */
|
|
13
|
-
method: string;
|
|
14
|
-
/** 调用 MCP 方法的参数 */
|
|
15
|
-
args: Record<string, unknown>;
|
|
16
|
-
/** 当前会话对应的账户 ID(由工具工厂透传,用于精确清理缓存等场景) */
|
|
17
|
-
accountId?: string;
|
|
18
|
-
/** 当前会话的 chatId(群组 ID 或用户 ID),用于 aibot_send_biz_msg 等命令 */
|
|
19
|
-
chatId?: string;
|
|
20
|
-
/** 当前会话的聊天类型:single(单聊)或 group(群聊) */
|
|
21
|
-
chatType?: "single" | "group";
|
|
22
|
-
/** 当前会话可信的企业微信 userid */
|
|
23
|
-
requesterUserId?: string;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* beforeCall 返回的选项
|
|
27
|
-
*
|
|
28
|
-
* 扩展 SendJsonRpcOptions,允许拦截器在调用前替换 args(如从本地文件读取请求体)。
|
|
29
|
-
*/
|
|
30
|
-
export interface BeforeCallOptions extends SendJsonRpcOptions {
|
|
31
|
-
/** 替换后的 args(可选,不返回则使用原 args) */
|
|
32
|
-
args?: Record<string, unknown>;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* call 拦截器接口
|
|
36
|
-
*
|
|
37
|
-
* 每个拦截器通过 match 判断是否对当前调用生效,
|
|
38
|
-
* 生效时可在调用前(beforeCall)和调用后(afterCall)注入逻辑。
|
|
39
|
-
*/
|
|
40
|
-
export interface CallInterceptor {
|
|
41
|
-
/** 拦截器名称(用于日志) */
|
|
42
|
-
name: string;
|
|
43
|
-
/**
|
|
44
|
-
* 判断是否对当前调用生效
|
|
45
|
-
*
|
|
46
|
-
* 返回 true 时才会执行 beforeCall / afterCall
|
|
47
|
-
*/
|
|
48
|
-
match(ctx: CallContext): boolean;
|
|
49
|
-
/**
|
|
50
|
-
* 在 sendJsonRpc 调用前修改请求选项和参数(可选)
|
|
51
|
-
*
|
|
52
|
-
* 如 get_msg_media 需要延长超时时间,
|
|
53
|
-
* 如 smartpage_create 需要从本地文件读取请求体替换 args。
|
|
54
|
-
* 返回的选项会与其他拦截器的结果合并(timeoutMs 取最大值,args 后者覆盖前者)。
|
|
55
|
-
*/
|
|
56
|
-
beforeCall?(ctx: CallContext): BeforeCallOptions | Promise<BeforeCallOptions> | undefined;
|
|
57
|
-
/**
|
|
58
|
-
* 在 sendJsonRpc 返回后处理/变换结果(可选)
|
|
59
|
-
*
|
|
60
|
-
* 多个拦截器的 afterCall 按注册顺序管道式执行,
|
|
61
|
-
* 前一个的返回值作为下一个的输入。
|
|
62
|
-
*/
|
|
63
|
-
afterCall?(ctx: CallContext, result: unknown): Promise<unknown> | unknown;
|
|
64
|
-
}
|
package/dist/src/mcp/schema.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Schema 清洗模块
|
|
3
|
-
*
|
|
4
|
-
* 负责内联 $ref/$defs 引用并移除 Gemini 不支持的 JSON Schema 关键词,
|
|
5
|
-
* 防止 Gemini 模型解析 function response 时报 400 错误。
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* 清洗 JSON Schema,内联 $ref 引用并移除 Gemini 不支持的关键词,
|
|
9
|
-
* 防止 Gemini 模型解析 function response 时报 400 错误。
|
|
10
|
-
*/
|
|
11
|
-
export declare function cleanSchemaForGemini(schema: unknown): unknown;
|