@wecom/wecom-openclaw-plugin 2026.4.22 → 2026.4.23

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.
@@ -341,11 +341,11 @@ async function routeAndDispatchMessage(params) {
341
341
  ctx: ctxPayload,
342
342
  cfg: config,
343
343
  replyOptions: {
344
- // 打印 LLM 返回的原始分片内容(在 openclaw 核心对 MEDIA: 指令解析之前),
345
- // 用于排查流式分片导致 MEDIA 指令被切断、识别丢失等问题
346
- onPartialReply: (payload) => {
347
- runtime.log?.(`[openclaw -> plugin][partial] payload=${JSON.stringify(payload)}`);
348
- },
344
+ // 打印 LLM 返回的原始分片内容(在 openclaw 核心对 MEDIA: 指令解析之前),
345
+ // 用于排查流式分片导致 MEDIA 指令被切断、识别丢失等问题
346
+ // onPartialReply: (payload: unknown) => {
347
+ // runtime.log?.(`[openclaw -> plugin][partial] payload=${JSON.stringify(payload)}`);
348
+ // },
349
349
  },
350
350
  dispatcherOptions: {
351
351
  onReplyStart: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wecom/wecom-openclaw-plugin",
3
- "version": "2026.4.22",
3
+ "version": "2026.4.23",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: wecom-doc-manager
3
- description: 企业微信文档管理技能。提供文档和智能主页的创建、读取和编辑能力。支持通过 docid 或文档 URL 操作企业微信文档(doc_type=3)和智能表格(doc_type=10),以及创建智能主页和导出其内容。适用场景:(1) 以 Markdown 格式导出获取文档完整内容(异步轮询) (2) 新建文档或智能表格 (3) 用 Markdown 格式覆写文档内容 (4) 将本地 Markdown 文件创建为智能主页 (5) 异步导出智能主页内容为 Markdown 文件。当用户需要查看文档内容、创建新文档、编辑文档正文、创建智能主页、或获取智能主页内容时触发此 Skill。
3
+ description: 企业微信文档管理技能。支持企业微信文档、智能表格和智能文档(原名智能主页)的管理。具体能力:(1) 获取文档或智能表格的完整内容,以 Markdown 格式导出 (2) 新建文档或智能表格 (3) 用 Markdown 覆写文档内容 (4) 创建智能文档,将本地 Markdown 文件发布为智能文档 (5) 导出智能文档内容为 Markdown 文件。
4
4
  ---
5
5
 
6
6
  # 企业微信文档管理
@@ -9,7 +9,9 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
9
9
 
10
10
  > ⚠️ **前置条件**:首次调用 `wecom_mcp` 前,必须按 `wecom-preflight` 技能执行前置条件检查,确保工具已加入白名单。
11
11
 
12
- 管理企业微信文档和智能主页的创建、读取和编辑。文档接口支持通过 `docid` 或 `url` 二选一定位文档。
12
+ 管理企业微信文档和智能文档(原名智能主页)的创建、读取和编辑。文档接口支持通过 `docid` 或 `url` 二选一定位文档。
13
+
14
+ > ⚠️ **重要触发规则**:只有当用户明确提到「**智能文档**」或「**智能主页**」时,才使用智能文档相关接口(`smartpage_*` 系列)。其他所有涉及「文档」的场景(如"创建文档"、"写个文档"、"帮我建个文档"等),一律使用企微文档接口(`create_doc` / `get_doc_content` / `edit_doc_content`)。
13
15
 
14
16
  ## URL 品类识别与接口路由
15
17
 
@@ -19,12 +21,12 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
19
21
  |---|---|---|
20
22
  | `https://doc.weixin.qq.com/doc/*` | **文档**(doc_type=3) | `get_doc_content` |
21
23
  | `https://doc.weixin.qq.com/smartsheet/*` | **智能表格**(doc_type=10) | `get_doc_content` |
22
- | `https://doc.weixin.qq.com/smartpage/*` | **智能主页** | `smartpage_export_task` → `smartpage_get_export_result` |
24
+ | `https://doc.weixin.qq.com/smartpage/*` | **智能文档**(原名智能主页) | `smartpage_export_task` → `smartpage_get_export_result` |
23
25
 
24
26
  **判断规则**:
25
27
  - URL 路径以 `/doc/*` 开头 → 文档 → 用 `get_doc_content`
26
28
  - URL 路径以 `/smartsheet/*` 开头 → 智能表格 → 用 `get_doc_content`
27
- - URL 路径以 `/smartpage/*` 开头 → 智能主页 → 用 `smartpage_export_task`
29
+ - URL 路径以 `/smartpage/*` 开头 → 智能文档(原名智能主页) → 用 `smartpage_export_task`
28
30
 
29
31
 
30
32
  ## 调用方式
@@ -48,7 +50,8 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
48
50
 
49
51
  | errcode | errmsg | 含义 | 处理方式 |
50
52
  |---------|--------|------|----------|
51
- | `851002` | `incompatible doc type` | 文档品类与所调用的接口不匹配 | 换用另一种导出方式重试:若当前使用 `get_doc_content` 则改用 `smartpage_export_task`,若当前使用 `smartpage_export_task` 则改用 `get_doc_content` |
53
+ | `851002` | `incompatible doc type` | 文档品类与所调用的接口不匹配 | 根据文档 URL 重新确认品类(参见上方「URL 品类识别与接口路由」表),然后使用该品类对应的正确接口重试 |
54
+ | `851003` | `no authority` | 无权限调用该接口,**智能表格写入场景**下通常是企业可见范围 > 10 人的规模限制 | 若发生在需要写入数据的场景,引导用户走 Webhook 兜底方案,详见 [webhook-fallback.md](../wecom-smartsheet-data/references/webhook-fallback.md);其他接口则按权限问题排查 |
52
55
 
53
56
  ## 文档
54
57
 
@@ -89,18 +92,20 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
89
92
 
90
93
  参见 [API 详情](references/api-edit-doc-content.md)。
91
94
 
92
- ## 智能主页
95
+ ## 智能文档(原名智能主页)
93
96
 
94
- 适用品类:智能主页
97
+ 适用品类:智能文档(用户说「智能文档」或「智能主页」时触发)
95
98
  适用 URL:`/smartpage/*`
96
99
 
100
+ > ⚠️ 只有当用户明确指定「智能文档」或「智能主页」时,才使用以下接口。其他「文档」场景请使用上方的企微文档接口。
101
+
97
102
  适用场景:
98
- 1. 将本地 Markdown 文件创建为智能主页
99
- 2. 异步导出智能主页内容为 Markdown 文件
103
+ 1. 将本地 Markdown 文件创建为智能文档
104
+ 2. 异步导出智能文档内容为 Markdown 文件
100
105
 
101
106
  ### smartpage_create
102
107
 
103
- 创建智能主页,支持传入标题和多个子页面。每个子页面可指定标题、内容类型和本地文件路径。响应透传 mcp 回包,返回 docid 和 url。
108
+ 创建智能文档(原名智能主页),支持传入标题和多个子页面。每个子页面可指定标题、内容类型和本地文件路径。响应透传 mcp 回包,返回 docid 和 url。
104
109
 
105
110
  - 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_create '{"title": "项目概览", "pages": [{"page_title": "需求文档", "content_type": 1, "page_filepath": "/path/to/requirements.md"}]}'`
106
111
 
@@ -113,7 +118,7 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
113
118
 
114
119
  ### smartpage_export_task
115
120
 
116
- 发起智能主页内容导出任务(异步)。传入 docid 和 content_type,返回 task_id。这是异步导出的第一步,需配合 `smartpage_get_export_result` 轮询获取导出结果。
121
+ 发起智能文档内容导出任务(异步)。传入 docid 和 content_type,返回 task_id。这是异步导出的第一步,需配合 `smartpage_get_export_result` 轮询获取导出结果。
117
122
 
118
123
  - 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_export_task '{"docid": "DOCID", "content_type": 1}'`
119
124
 
@@ -121,7 +126,7 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
121
126
 
122
127
  ### smartpage_get_export_result
123
128
 
124
- 查询智能主页导出任务进度。传入 task_id 进行轮询,当 `task_done` 为 `true` 时返回 `content_filepath`(导出内容的本地文件路径)。
129
+ 查询智能文档导出任务进度。传入 task_id 进行轮询,当 `task_done` 为 `true` 时返回 `content_filepath`(导出内容的本地文件路径)。
125
130
 
126
131
  - 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_get_export_result '{"task_id": "TASK_ID"}'`
127
132
 
@@ -131,13 +136,13 @@ description: 企业微信文档管理技能。提供文档和智能主页的创
131
136
 
132
137
  ## 典型工作流
133
138
 
134
- > **关键提示**:读取内容前先看 URL 判断品类。`/doc/` 或 `/smartsheet/` → `get_doc_content`;`/smartpage/` → `smartpage_export_task`。
139
+ > **关键提示**:读取内容前先看 URL 判断品类。`/doc/` 或 `/smartsheet/` → `get_doc_content`;`/smartpage/` → `smartpage_export_task`。只有用户明确提到「智能文档」或「智能主页」时才走 smartpage 流程,其他文档场景一律使用企微文档接口。
135
140
 
136
141
  1. **读取文档/智能表格内容**(URL 含 `/doc/` 或 `/smartsheet/`) → 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc get_doc_content '{"docid": "DOCID", "type": 2}'`,若 `task_done` 为 false 则携带 `task_id` 继续轮询
137
142
  2. **创建新文档** → 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc create_doc '{"doc_type": 3, "doc_name": "文档名"}'`,保存返回的 docid
138
143
  3. **编辑文档** → 先 get_doc_content 了解当前内容,再 edit_doc_content 覆写
139
- 4. **创建智能主页** → 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_create '{"title": "标题", "pages": [{"page_title": "子页面", "content_type": 1, "page_filepath": "/path/to/file.md"}]}'`,保存返回的 docid
140
- 5. **获取智能主页内容**(URL 含 `/smartpage/`,异步两步):
144
+ 4. **创建智能文档**(仅当用户明确要求「智能文档」或「智能主页」时) → 使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_create '{"title": "标题", "pages": [{"page_title": "子页面", "content_type": 1, "page_filepath": "/path/to/file.md"}]}'`,保存返回的 docid
145
+ 5. **获取智能文档内容**(URL 含 `/smartpage/`,异步两步):
141
146
  - **第一步**:使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_export_task '{"docid": "DOCID", "content_type": 1}'`,获取 `task_id`
142
147
  - **第二步**:使用 `wecom_mcp` tool 调用 `wecom_mcp call doc smartpage_get_export_result '{"task_id": "TASK_ID"}'`,若 `task_done` 为 `false` 则继续轮询,直到 `task_done` 为 `true`
143
148
  - **第三步**:使用 Read 工具读取 `content_filepath` 指向的本地文件,获取 Markdown 内容
@@ -51,6 +51,6 @@
51
51
 
52
52
  ## 注意事项
53
53
 
54
- - `doc_type=3` 创建普通文档
54
+ - `doc_type=3` 创建文档
55
55
  - `doc_type=10` 创建智能表格,默认包含一个子表
56
56
  - docid 仅在创建时返回,后续无法再获取,务必保存
@@ -1,17 +1,17 @@
1
1
  # smartpage_create API
2
2
 
3
- 创建智能主页。支持传入多个子页面,每个子页面可指定标题、内容类型和文件路径。创建成功后返回文档访问链接和 docid。
3
+ 创建智能文档(原智能主页)。支持传入多个子页面,每个子页面可指定标题、内容类型和文件路径。创建成功后返回文档访问链接和 docid。
4
4
 
5
5
  ## 技能定义
6
6
 
7
7
  ```json
8
8
  {
9
9
  "name": "smartpage_create",
10
- "description": "创建智能主页。支持传入标题和多个子页面配置,每个子页面可指定标题、内容类型(Text/Markdown)和本地文件路径。创建成功后返回 docid 和 url(docid 仅在创建时返回,需妥善保存)。",
10
+ "description": "创建智能文档(原智能主页)。支持传入标题和多个子页面配置,每个子页面可指定标题、内容类型(Text/Markdown)和本地文件路径。创建成功后返回 docid 和 url(docid 仅在创建时返回,需妥善保存)。",
11
11
  "inputSchema": {
12
12
  "properties": {
13
13
  "title": {
14
- "description": "智能主页标题",
14
+ "description": "智能文档标题",
15
15
  "title": "Title",
16
16
  "type": "string"
17
17
  },
@@ -54,7 +54,7 @@
54
54
 
55
55
  | 参数 | 类型 | 必填 | 说明 |
56
56
  |---|---|---|---|
57
- | title | string | 否 | 智能主页标题 |
57
+ | title | string | 否 | 智能文档标题 |
58
58
  | pages | array | 是 | 子页面列表 |
59
59
  | pages[].page_title | string | 否 | 子页面标题 |
60
60
  | pages[].content_type | integer | 否 | 内容类型:1-Markdown,0-Text(纯文本)。**默认应传 1**,仅纯文本内容才传 0 |
@@ -1,17 +1,17 @@
1
1
  # smartpage_export_task API
2
2
 
3
- 发起智能主页内容导出任务。该接口为异步操作的第一步,调用后返回 `task_id`,需配合 `smartpage_get_export_result` 轮询获取导出结果。
3
+ 发起智能文档(原智能主页)内容导出任务。该接口为异步操作的第一步,调用后返回 `task_id`,需配合 `smartpage_get_export_result` 轮询获取导出结果。
4
4
 
5
5
  ## 技能定义
6
6
 
7
7
  ```json
8
8
  {
9
9
  "name": "smartpage_export_task",
10
- "description": "发起智能主页内容导出任务(异步)。传入 docid 和 content_type,返回 task_id。需配合 smartpage_get_export_result 轮询查询导出进度,直到任务完成后获取导出文件路径。",
10
+ "description": "发起智能文档(原智能主页)内容导出任务(异步)。传入 docid 和 content_type,返回 task_id。需配合 smartpage_get_export_result 轮询查询导出进度,直到任务完成后获取导出文件路径。",
11
11
  "inputSchema": {
12
12
  "properties": {
13
13
  "docid": {
14
- "description": "智能主页的 docid,由 smartpage_create 返回",
14
+ "description": "智能文档的 docid,由 smartpage_create 返回",
15
15
  "title": "Doc ID",
16
16
  "type": "string"
17
17
  },
@@ -33,7 +33,7 @@
33
33
 
34
34
  | 参数 | 类型 | 必填 | 说明 |
35
35
  |---|---|---|---|
36
- | docid | string | 是 | 智能主页的 docid |
36
+ | docid | string | 是 | 智能文档的 docid |
37
37
  | content_type | integer | 是 | 导出内容格式:0-Text,1-Markdown |
38
38
 
39
39
  ## 请求示例
@@ -1,13 +1,13 @@
1
1
  # smartpage_get_export_result API
2
2
 
3
- 查询智能主页导出任务的执行进度。配合 `smartpage_export_task` 使用,通过轮询 `task_id` 获取导出结果。当 `task_done` 为 `true` 时,返回导出内容的本地文件路径。
3
+ 查询智能文档(原智能主页)导出任务的执行进度。配合 `smartpage_export_task` 使用,通过轮询 `task_id` 获取导出结果。当 `task_done` 为 `true` 时,返回导出内容的本地文件路径。
4
4
 
5
5
  ## 技能定义
6
6
 
7
7
  ```json
8
8
  {
9
9
  "name": "smartpage_get_export_result",
10
- "description": "查询智能主页导出任务进度。传入 task_id 轮询,当 task_done 为 true 时返回导出内容的本地文件路径 content_filepath,可通过读取该文件获取 Markdown 内容。",
10
+ "description": "查询智能文档(原智能主页)导出任务进度。传入 task_id 轮询,当 task_done 为 true 时返回导出内容的本地文件路径 content_filepath,可通过读取该文件获取 Markdown 内容。",
11
11
  "inputSchema": {
12
12
  "properties": {
13
13
  "task_id": {
@@ -47,6 +47,8 @@ description: 企业微信智能表格数据(记录)管理技能。提供智
47
47
 
48
48
  各字段类型的值格式参见 [单元格值格式参考](references/cell-value-formats.md)。
49
49
 
50
+ > ⚠️ 若返回 `errcode: 851003` 或 `errmsg` 包含 `no authority`(通常是企业可见范围 > 10 人的规模限制),切换到 Webhook 兜底方案,详见 [webhook-fallback.md](references/webhook-fallback.md)。
51
+
50
52
  ### smartsheet_update_records
51
53
 
52
54
  更新一行或多行记录,单次建议在 500 行内。需提供 record_id(通过 `smartsheet_get_records` 获取)。支持通过 `key_type` 指定 values 的 key 使用字段标题或字段 ID:
@@ -58,6 +60,8 @@ description: 企业微信智能表格数据(记录)管理技能。提供智
58
60
 
59
61
  **注意**:创建时间、最后编辑时间、创建人、最后编辑人字段不可更新。
60
62
 
63
+ > ⚠️ 若返回 `errcode: 851003` 或 `errmsg` 包含 `no authority`(通常是企业可见范围 > 10 人的规模限制),切换到 Webhook 兜底方案,详见 [webhook-fallback.md](references/webhook-fallback.md)。注意 Webhook 只能更新通过 Webhook 写入的记录,人工创建的记录无法更新。
64
+
61
65
  ### smartsheet_delete_records
62
66
 
63
67
  删除一行或多行记录,单次必须在 500 行内。**操作不可逆**。record_id 通过 `smartsheet_get_records` 获取。
@@ -70,5 +74,6 @@ description: 企业微信智能表格数据(记录)管理技能。提供智
70
74
  2. **写入数据** → 先 `smartsheet_get_fields` 了解列类型 → 若涉及成员(USER)字段,先通过 `wecom-contact-lookup` 的 `get_userlist` 查找人员 userid → `smartsheet_add_records` 写入
71
75
  3. **更新数据** → 先 `smartsheet_get_records` 获取 record_id → 若涉及成员(USER)字段,先通过 `wecom-contact-lookup` 的 `get_userlist` 查找人员 userid → `smartsheet_update_records` 更新
72
76
  4. **删除数据** → 先 `smartsheet_get_records` 确认 record_id → `smartsheet_delete_records` 删除
77
+ 5. **写入失败 fallback** → 第 2/3 步返回 `errcode: 851003` / `no authority`(通常是企业可见范围 > 10 人的规模限制)时 → 请用户临时提供目标表的 Webhook 地址 + schema 示例 JSON(不保存到本地)→ 按 [webhook-fallback.md](references/webhook-fallback.md) 构造请求体发送
73
78
 
74
79
  > **注意**:成员(USER)类型字段需要填写 `user_id`,不能直接使用姓名。必须先通过 `wecom-contact-lookup` 技能的 `get_userlist` 接口按姓名查找到对应的 `userid` 后再使用。
@@ -0,0 +1,185 @@
1
+ # 真实场景示例
2
+
3
+ ## 场景 1:记录一个 Bug(文本 + 单选 + 图片)
4
+
5
+ 用户说:“帮我记一下这个 bug,登录页在 Safari 下白屏,模块是前端,严重程度严重。”
6
+
7
+ ```json
8
+ {
9
+ "add_records": [
10
+ {
11
+ "values": {
12
+ "fABCD1": "登录页在 Safari 浏览器下加载后白屏,其他浏览器正常。复现步骤:Safari 14+ 访问 /login → 页面空白,控制台报 CSS 解析错误。",
13
+ "fABCD2": [{"text": "前端"}],
14
+ "fABCD3": [{"text": "严重"}],
15
+ "fABCD4": [{"user_id": "wangwu"}],
16
+ "fABCD5": [{"title": "safari-bug-screenshot.png", "image_base64": "iVBORw0KGgoAAAANSUhEUg...(纯base64)"}]
17
+ }
18
+ }
19
+ ]
20
+ }
21
+ ```
22
+
23
+ ## 场景 2:记录一条任务(文本 + 日期 + 成员 + 单选 + 空图片)
24
+
25
+ 用户说:“加一条任务,完成支付模块单元测试,3月20日前,负责人 lisi,状态未开始,暂无附件。”
26
+
27
+ ```json
28
+ {
29
+ "add_records": [
30
+ {
31
+ "values": {
32
+ "fTITLE": "完成支付模块单元测试,覆盖率达到 80%",
33
+ "fDUEDATE": "1742400000000",
34
+ "fOWNER": [{"user_id": "lisi"}],
35
+ "fSTATUS": [{"text": "未开始"}],
36
+ "fATTACH": []
37
+ }
38
+ }
39
+ ]
40
+ }
41
+ ```
42
+
43
+ > **关于负责人(成员字段)**:
44
+ > - 有 userid 时用 `[{"user_id": "账号名"}]`,userid 通常就是企业微信登录账号
45
+ > - 没有 userid 只知道姓名时用 `["张三"]`,但匹配不上时不会写入
46
+ > - 暂不指定负责人时传 `[]` 空数组
47
+ >
48
+ > **关于图片/附件字段**:
49
+ > - 暂无图片时传 `[]` 空数组即可,不会报错
50
+ > - 有图片时传 `[{"title": "filename.png", "image_base64": "纯base64字符串"}]`,注意不带 `data:image/...;base64,` 前缀
51
+
52
+ ## 场景 3:批量添加多条客户记录
53
+
54
+ 用户说:“帮我把这三条线索录进去:张伟/科技公司/跟进中,陈静/贸易公司/初步接触,刘洋/制造业/已成交。”
55
+
56
+ ```json
57
+ {
58
+ "add_records": [
59
+ {
60
+ "values": {
61
+ "fCUST_NAME": "张伟",
62
+ "fCOMPANY": "北京某科技有限公司",
63
+ "fSTAGE": [{"text": "跟进中"}],
64
+ "fSOURCE": [{"text": "展会"}]
65
+ }
66
+ },
67
+ {
68
+ "values": {
69
+ "fCUST_NAME": "陈静",
70
+ "fCOMPANY": "上海某贸易有限公司",
71
+ "fSTAGE": [{"text": "初步接触"}],
72
+ "fSOURCE": [{"text": "冷呼"}]
73
+ }
74
+ },
75
+ {
76
+ "values": {
77
+ "fCUST_NAME": "刘洋",
78
+ "fCOMPANY": "广州某制造有限公司",
79
+ "fSTAGE": [{"text": "已成交"}],
80
+ "fSOURCE": [{"text": "老客户转介绍"}]
81
+ }
82
+ }
83
+ ]
84
+ }
85
+ ```
86
+
87
+ ## 场景 4:更新一条已有记录
88
+
89
+ 用户说:“把 record_id 是 REC_20250301 的那条任务状态改成已完成,进度 100%。”
90
+
91
+ ```json
92
+ {
93
+ "update_records": [
94
+ {
95
+ "record_id": "REC_20250301",
96
+ "values": {
97
+ "fSTATUS": [{"text": "已完成"}],
98
+ "fPROGRESS": 100
99
+ }
100
+ }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ## 场景 5:批量更新多条记录
106
+
107
+ 用户说:“把这几条审批记录都标为已通过:REC_001、REC_002、REC_003。”
108
+
109
+ ```json
110
+ {
111
+ "update_records": [
112
+ {"record_id": "REC_001", "values": {"fSTATUS": [{"text": "已通过"}], "fAPPROVER": [{"user_id": "manager_a"}]}},
113
+ {"record_id": "REC_002", "values": {"fSTATUS": [{"text": "已通过"}], "fAPPROVER": [{"user_id": "manager_a"}]}},
114
+ {"record_id": "REC_003", "values": {"fSTATUS": [{"text": "已通过"}], "fAPPROVER": [{"user_id": "manager_a"}]}}
115
+ ]
116
+ }
117
+ ```
118
+
119
+ ## 场景 6:记录一条销售订单(多字段混合类型)
120
+
121
+ 用户说:“新增一条订单,客户是北京某科技,产品是企业版,金额 58000,签约日期今天,负责人赵六,合同链接发给你了。”
122
+
123
+ ```json
124
+ {
125
+ "add_records": [
126
+ {
127
+ "values": {
128
+ "fCUSTOMER": "北京某科技有限公司",
129
+ "fPRODUCT": [{"text": "企业版"}],
130
+ "fAMOUNT": 58000,
131
+ "fSIGN_DATE": "1741622400000",
132
+ "fSALES": [{"user_id": "zhaoliu"}],
133
+ "fCONTRACT": [{"text": "合同文件", "link": "https://doc.example.com/contract/2025-001"}]
134
+ }
135
+ }
136
+ ]
137
+ }
138
+ ```
139
+
140
+ ## 场景 7:记录一次会议纪要
141
+
142
+ 用户说:“帮我记一下今天下午的需求评审会,参会人产品+开发+测试,决议是优先做支付模块。”
143
+
144
+ ```json
145
+ {
146
+ "add_records": [
147
+ {
148
+ "values": {
149
+ "fMEETING_TITLE": "支付模块需求评审会",
150
+ "fDATE": "1741622400000",
151
+ "fPARTICIPANTS": "产品、开发、测试",
152
+ "fSUMMARY": "确定优先开发支付模块,目标 3 月底完成联调,4 月初上线。遗留问题:退款流程待产品补充文档。",
153
+ "fDOC_LINK": [{"text": "评审文档", "link": "https://doc.example.com/meeting/20250310"}]
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ ```
159
+
160
+ ## 场景 8:同一请求中同时添加和更新
161
+
162
+ 用户说:“新增一条‘用户反馈收集’的任务,同时把‘旧官网下线’那条(REC_OLD_001)标为已完成。”
163
+
164
+ ```json
165
+ {
166
+ "add_records": [
167
+ {
168
+ "values": {
169
+ "fTITLE": "用户反馈收集与分析",
170
+ "fSTATUS": [{"text": "未开始"}],
171
+ "fPRIORITY": [{"text": "高"}]
172
+ }
173
+ }
174
+ ],
175
+ "update_records": [
176
+ {
177
+ "record_id": "REC_OLD_001",
178
+ "values": {
179
+ "fSTATUS": [{"text": "已完成"}],
180
+ "fPROGRESS": 100
181
+ }
182
+ }
183
+ ]
184
+ }
185
+ ```
@@ -0,0 +1,184 @@
1
+ # 智能表格 Webhook 兜底写入
2
+
3
+ > 本文档是 `smartsheet_add_records` / `smartsheet_update_records` 的 **fallback 参考**。
4
+ > 当通过 `wecom_mcp` tool 调用因企业规模限制(可见范围 > 10 人)报错、无法写入智能表格时,切换到本方案,通过企业微信智能表格的 Webhook 接口直接写入数据。
5
+ >
6
+ > ⚠️ **格式隔离**:以下字段值格式仅适用于 Webhook 接口,与 `wecom_mcp` tool 侧 `smartsheet_add_records` / `smartsheet_update_records` 的参数结构**不同**(例如文本、URL、图片、日期的写法均有差异),请勿与 [cell-value-formats.md](cell-value-formats.md) 的格式混用。
7
+
8
+ ---
9
+
10
+ ## 一、Fallback 触发流程
11
+
12
+ ### 何时切换到 Webhook
13
+
14
+ 先走 `wecom_mcp` tool 正常链路(`smartsheet_add_records` / `smartsheet_update_records`)。仅在出现以下情况时才切换到 Webhook:
15
+
16
+ - **优先判据**:返回 `errcode: 851003`,或 `errmsg` 包含 `no authority` —— 这通常意味着企业可见范围 > 10 人,写入接口被限制
17
+ - 或 `errmsg` / 提示信息明显指向**企业规模 / 可见范围超限**(例如“超出可见范围”、“成员数超限”等相关描述)
18
+ - 其他错误(参数错误、字段 ID 错误、文档不存在等)**不应**切换到 Webhook,应按原错误排查
19
+
20
+ ### 切换时向用户索取的两样东西
21
+
22
+ 切换触发后,**每次对话内临时获取,用完即弃,不保存到本地任何位置**:
23
+
24
+ 1. **Webhook 完整 URL**
25
+ - 在智能表格右上角菜单 → 「接收外部数据」→ 选择目标工作表 → 开启 → 复制
26
+ - 格式形如 `https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key=XXXXXX`
27
+ - 该 URL 相当于该表的写入密钥,用户随时可以在智能表格里关闭「接收外部数据」使其失效
28
+ 2. **schema 示例 JSON**
29
+ - 同一「接收外部数据」页面即可复制
30
+ - 包含字段 ID → 字段名的映射(`schema`)和各字段的写入格式示例(`add_records`)
31
+
32
+ 示例:
33
+
34
+ ```json
35
+ {
36
+ "schema": {
37
+ "fABCD1": "任务名称",
38
+ "fABCD2": "状态",
39
+ "fABCD3": "负责人",
40
+ "fABCD4": "截止日期"
41
+ },
42
+ "add_records": [
43
+ {
44
+ "values": {
45
+ "fABCD1": "示例任务",
46
+ "fABCD2": [{"text": "未开始"}],
47
+ "fABCD3": [{"user_id": ""}],
48
+ "fABCD4": "1742400000000"
49
+ }
50
+ }
51
+ ]
52
+ }
53
+ ```
54
+
55
+ ### 向用户告知的话术参考
56
+
57
+ - “通过 `wecom_mcp` 写入接口返回了 `851003 no authority`(通常是企业可见范围 > 10 人的限制)。请把目标表的 Webhook 地址和「接收外部数据」页面的示例 JSON 发我,我帮你通过 Webhook 写入。该信息仅本轮使用,不会保存到本地。”
58
+
59
+ ---
60
+
61
+ ## 二、构建请求
62
+
63
+ ### 字段匹配
64
+
65
+ 用户描述通常是自然语言(“标题”“状态”“处理人”),需从用户提供的 `schema` 中找对应字段 ID:
66
+
67
+ - 模糊匹配:`标题` → 标题 / 名称 / 主题;`状态` → 状态 / 阶段;`处理人` → 负责人 / 责任人
68
+ - 不确定时先问用户确认,避免写错字段
69
+
70
+ 各字段类型的值写法见下方 [字段类型格式规范](#三字段类型格式规范);真实场景示例见 [webhook-examples.md](webhook-examples.md)。
71
+
72
+ ### 日期处理
73
+
74
+ 用户说“今天”“明天”“3 月 15 日”“2025-03-01 09:00”等自然语言日期时,**在 payload 构造阶段**根据当前日期推算为**毫秒时间戳字符串**(如 `"1742400000000"`)。Webhook 侧**不接受**可读日期字符串。
75
+
76
+ ### 请求结构
77
+
78
+ Webhook 是标准 HTTP 接口,不经过 `wecom_mcp`,请按执行环境选择合适的工具发送(`curl`、`node` 内置 `fetch`、`python` 的 `requests` / `urllib` 等均可,优先用当前环境最便捷的方式):
79
+
80
+ | 项 | 值 |
81
+ |---|---|
82
+ | Method | `POST` |
83
+ | URL | 用户提供的 Webhook 完整 URL(含 `?key=XXX`) |
84
+ | Header | `Content-Type: application/json` |
85
+ | Body | JSON 对象,包含 `add_records` 和/或 `update_records` 字段 |
86
+
87
+ ### Body 结构
88
+
89
+ - 仅新增:
90
+
91
+ ```json
92
+ {
93
+ "add_records": [
94
+ { "values": { "fABCD1": "...", "fABCD2": [{"text": "..."}] } }
95
+ ]
96
+ }
97
+ ```
98
+
99
+ - 仅更新(需提供 `record_id`,且**只能更新通过 Webhook 写入的记录**,人工创建的记录无法更新):
100
+
101
+ ```json
102
+ {
103
+ "update_records": [
104
+ { "record_id": "REC_xxx", "values": { "fABCD2": [{"text": "已完成"}] } }
105
+ ]
106
+ }
107
+ ```
108
+
109
+ - 同一请求同时新增和更新:
110
+
111
+ ```json
112
+ {
113
+ "add_records": [ { "values": { ... } } ],
114
+ "update_records": [ { "record_id": "REC_xxx", "values": { ... } } ]
115
+ }
116
+ ```
117
+
118
+ ### 成功后
119
+
120
+ 简洁告知结果,例如:
121
+
122
+ > “已通过 Webhook 写入,record_id: `REC_xxx`”
123
+
124
+ 返回非 0 `errcode` 时参考下方 [常见错误码](#六常见错误码)。
125
+
126
+ ---
127
+
128
+ ## 三、字段类型格式规范
129
+
130
+ ### 各类型写法
131
+
132
+ | 字段类型 | value 示例 | 说明 |
133
+ |---------|-----------|------|
134
+ | 文本 | `"产品登录页白屏"` 或 `[{"type":"text","text":"产品登录页白屏"}]` | 简单字符串更简洁 |
135
+ | 数字 / 货币 | `58000` | double,不要加引号 |
136
+ | 进度 / 百分数 | `30` | 传整数值,`30` = 30%;**不要传小数** `0.3`(那样会显示 0.3%) |
137
+ | 复选框 | `true` / `false` | bool |
138
+ | 日期 | `"1740806400000"` | 毫秒时间戳,字符串形式 |
139
+ | 成员 | `[{"user_id":"lisi"}]` 或 `["张三"]` 或 `[]` | userid 通常就是企业微信登录账号;不指定时传 `[]` |
140
+ | 单选 | `[{"text":"已完成"}]` | 数组,选项文本必须与表格预设完全一致 |
141
+ | 多选 | `[{"text":"前端"},{"text":"后端"}]` | 数组,每个选项一个对象 |
142
+ | 链接 | `[{"text":"需求文档","link":"https://doc.example.com"}]` | 数组 |
143
+ | 地理位置 | `[{"latitude":"31.23040","longitude":"121.47370","source_type":1,"title":"上海市徐汇区"}]` | 数组,最多 1 条 |
144
+ | 图片 | `[{"title":"screenshot.png","image_base64":"iVBORw0KGgo..."}]` | 纯 base64,**不要带 `data:image/...;base64,` 前缀**,否则报 errcode 2023033 |
145
+ | 电话 / 邮箱 / 条码 | `"13800138000"` | 字符串 |
146
+
147
+ ---
148
+
149
+ ## 四、不支持的字段
150
+
151
+ 以下字段由系统自动维护或结构特殊,Webhook 写入时**跳过即可,不要报错**:
152
+
153
+ 公式、自动编号、查找引用、关联字段、创建人、最后编辑人、创建时间、最后编辑时间、群聊、文件附件。
154
+
155
+ ---
156
+
157
+ ## 五、频率限制
158
+
159
+ - 单工作表:≤ 3000 条/分钟
160
+ - 单文档:≤ 10000 条/分钟
161
+
162
+ 数据量大时建议分批,每批不超过 500 条。
163
+
164
+ ---
165
+
166
+ ## 六、常见错误码
167
+
168
+ | errcode | 原因 | 解决方法 |
169
+ |---------|------|---------|
170
+ | 2023033 | 图片 base64 携带了 `data:image/...;base64,` 前缀 | 去掉前缀,只传纯 base64 字符串 |
171
+ | 40014 | Webhook key 无效或已过期 | 请用户重新在智能表格「接收外部数据」获取 Webhook 地址 |
172
+ | 45033 | 超出频率限制 | 降低发送速率或分批发送 |
173
+ | -100035 | testapi 域名不稳定(超时) | 改用正式域名 `qyapi.weixin.qq.com` |
174
+ | 2023001 | 字段 ID 不存在 | 核对用户提供的 `schema`,确认字段 ID 拼写正确 |
175
+ | 2023010 | 单选/多选的选项值不在预设列表 | 确认选项文本与表格设置完全一致(区分大小写) |
176
+ | 2023012 | record_id 不存在(更新时) | 只能更新通过 Webhook 写入的记录,人工创建的记录无法更新 |
177
+
178
+ ---
179
+
180
+ ## 七、参考文件
181
+
182
+ - 真实场景示例 → [webhook-examples.md](webhook-examples.md)
183
+
184
+ 按需查阅,不用每次全读。