@yanhaidao/wecom 2.3.13 → 2.3.14

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.
@@ -0,0 +1,1165 @@
1
+ import fs from "node:fs";
2
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
3
+ import { wecomDocToolSchema } from "./schema.js";
4
+ import { WecomDocClient } from "./client.js";
5
+ import type { ResolvedAgentAccount } from "../../types/index.js";
6
+ import { resolveAgentAccountOrUndefined } from "../bot/fallback-delivery.js";
7
+
8
+ import { UpdateRequest } from "./types.js";
9
+
10
+ function readString(value: unknown): string {
11
+ const trimmed = String(value ?? "").trim();
12
+ return trimmed || "";
13
+ }
14
+
15
+ function mapDocTypeLabel(docType: number): string {
16
+ if (docType === 10) return "智能表格";
17
+ return docType === 4 ? "表格" : "文档";
18
+ }
19
+
20
+ function summarizeDocInfo(info: any = {}) {
21
+ const docName = readString(info.doc_name) || "未命名文档";
22
+ const docType = mapDocTypeLabel(Number(info.doc_type));
23
+ return `${docType}“${docName}”信息已获取`;
24
+ }
25
+
26
+ function summarizeDocAuth(result: any = {}) {
27
+ return `权限信息已获取:通知成员 ${result.docMembers?.length ?? 0},协作者 ${result.coAuthList?.length ?? 0}`;
28
+ }
29
+
30
+ function readBooleanFlag(value: unknown): boolean | null {
31
+ return typeof value === "boolean" ? value : null;
32
+ }
33
+
34
+ function formatDocMemberRef(value: any) {
35
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "";
36
+ const userid = readString(value.userid ?? value.userId);
37
+ if (userid) return `userid:${userid}`;
38
+ const partyid = readString(value.partyid);
39
+ if (partyid) return `partyid:${partyid}`;
40
+ const tagid = readString(value.tagid);
41
+ if (tagid) return `tagid:${tagid}`;
42
+ return "";
43
+ }
44
+
45
+ function mapDocMemberList(values: any) {
46
+ return Array.isArray(values)
47
+ ? values.map((item) => formatDocMemberRef(item)).filter(Boolean)
48
+ : [];
49
+ }
50
+
51
+ function describeFlagState(value: boolean | null, enabledLabel: string, disabledLabel: string, unknownLabel = "未知") {
52
+ if (value === true) return enabledLabel;
53
+ if (value === false) return disabledLabel;
54
+ return unknownLabel;
55
+ }
56
+
57
+ function buildDocAuthDiagnosis(result: any = {}, requesterSenderId = "") {
58
+ const accessRule = result.accessRule && typeof result.accessRule === "object" ? result.accessRule : {};
59
+ const viewers = mapDocMemberList(result.docMembers);
60
+ const collaborators = mapDocMemberList(result.coAuthList);
61
+ const requester = readString(requesterSenderId);
62
+ const requesterViewerRef = requester ? `userid:${requester}` : "";
63
+ const requesterIsViewer = requesterViewerRef ? viewers.includes(requesterViewerRef) : false;
64
+ const requesterIsCollaborator = requesterViewerRef ? collaborators.includes(requesterViewerRef) : false;
65
+ const internalAccessEnabled = readBooleanFlag(accessRule.enable_corp_internal);
66
+ const externalAccessEnabled = readBooleanFlag(accessRule.enable_corp_external);
67
+ const externalShareAllowed = typeof accessRule.ban_share_external === "boolean"
68
+ ? !accessRule.ban_share_external
69
+ : null;
70
+ const likelyAnonymousLinkFailure = internalAccessEnabled === true && externalAccessEnabled === false;
71
+ const findings = [
72
+ `企业内访问:${describeFlagState(internalAccessEnabled, "开启", "关闭")}`,
73
+ `企业外访问:${describeFlagState(externalAccessEnabled, "开启", "关闭")}`,
74
+ `外部分享:${describeFlagState(externalShareAllowed, "允许", "禁止")}`,
75
+ `查看成员:${viewers.length}`,
76
+ `协作者:${collaborators.length}`,
77
+ ];
78
+ const recommendations: string[] = [];
79
+ if (likelyAnonymousLinkFailure) {
80
+ recommendations.push("当前更像是仅企业内可访问;匿名浏览器或未登录企业微信环境通常会显示“文档不存在”。");
81
+ }
82
+ if (requester) {
83
+ if (requesterIsCollaborator) {
84
+ recommendations.push(`当前请求人 ${requester} 已在协作者列表中。`);
85
+ } else if (requesterIsViewer) {
86
+ recommendations.push(`当前请求人 ${requester} 已在查看成员列表中,但还不是协作者。`);
87
+ } else {
88
+ recommendations.push(`当前请求人 ${requester} 不在查看成员或协作者列表中。`);
89
+ }
90
+ }
91
+ return {
92
+ internalAccessEnabled,
93
+ externalAccessEnabled,
94
+ externalShareAllowed,
95
+ viewerCount: viewers.length,
96
+ collaboratorCount: collaborators.length,
97
+ viewers,
98
+ collaborators,
99
+ requesterSenderId: requester || undefined,
100
+ requesterRole: requesterIsCollaborator ? "collaborator" : requesterIsViewer ? "viewer" : requester ? "none" : "unknown",
101
+ likelyAnonymousLinkFailure,
102
+ findings,
103
+ recommendations,
104
+ };
105
+ }
106
+
107
+ function summarizeDocAuthDiagnosis(diagnosis: any = {}) {
108
+ const parts = Array.isArray(diagnosis.findings) ? diagnosis.findings : [];
109
+ return parts.length > 0 ? `文档权限诊断:${parts.join(",")}` : "文档权限诊断已完成";
110
+ }
111
+
112
+ function buildDocIdUsageHint(docId?: string) {
113
+ const normalizedDocId = readString(docId);
114
+ if (!normalizedDocId) return "";
115
+ return `后续权限、分享和诊断操作请使用真实 docId:${normalizedDocId};不要直接使用分享链接路径中的片段。`;
116
+ }
117
+
118
+ function safeParseJson(text: string) {
119
+ try {
120
+ return JSON.parse(text);
121
+ } catch {
122
+ return null;
123
+ }
124
+ }
125
+
126
+ function extractEmbeddedJson(html: string, variableName: string) {
127
+ const source = String(html ?? "");
128
+ if (!source) return null;
129
+ const marker = `window.${variableName}=`;
130
+ const start = source.indexOf(marker);
131
+ if (start < 0) return null;
132
+ const valueStart = start + marker.length;
133
+ const end = source.indexOf(";</script>", valueStart);
134
+ if (end < 0) return null;
135
+ return safeParseJson(source.slice(valueStart, end));
136
+ }
137
+
138
+ function buildShareLinkDiagnosis(params: { shareUrl: string; finalUrl: string; status: number; contentType: string; basicClientVars: any }) {
139
+ const { shareUrl, finalUrl, status, contentType, basicClientVars } = params;
140
+ const parsedUrl = new URL(finalUrl || shareUrl);
141
+ const pathSegments = parsedUrl.pathname.split("/").filter(Boolean);
142
+ const pathResourceType = readString(pathSegments[0]);
143
+ const pathResourceId = readString(pathSegments[1]);
144
+ const shareCode = readString(parsedUrl.searchParams.get("scode"));
145
+ const userInfo = basicClientVars?.userInfo && typeof basicClientVars.userInfo === "object"
146
+ ? basicClientVars.userInfo
147
+ : {};
148
+ const docInfo = basicClientVars?.docInfo && typeof basicClientVars.docInfo === "object"
149
+ ? basicClientVars.docInfo
150
+ : {};
151
+ const padInfo = docInfo?.padInfo && typeof docInfo.padInfo === "object"
152
+ ? docInfo.padInfo
153
+ : {};
154
+ const ownerInfo = docInfo?.ownerInfo && typeof docInfo.ownerInfo === "object"
155
+ ? docInfo.ownerInfo
156
+ : {};
157
+ const shareInfo = docInfo?.shareInfo && typeof docInfo.shareInfo === "object"
158
+ ? docInfo.shareInfo
159
+ : {};
160
+ const aclInfo = docInfo?.aclInfo && typeof docInfo.aclInfo === "object"
161
+ ? docInfo.aclInfo
162
+ : {};
163
+ const userType = readString(userInfo.userType);
164
+ const padType = readString(padInfo.padType);
165
+ const padId = readString(padInfo.padId);
166
+ const padTitle = readString(padInfo.padTitle);
167
+ const isGuest = userType === "guest" || Number(userInfo.loginType) === 0;
168
+ const isBlankPage = padType === "blankpage";
169
+ const likelyUnavailableToGuest = isGuest && isBlankPage && !padTitle;
170
+ const findings = [
171
+ `HTTP ${String(status || "")}`.trim(),
172
+ `内容类型:${readString(contentType) || "未知"}`,
173
+ `访问身份:${userType || "未知"}`,
174
+ `页面类型:${padType || "未知"}`,
175
+ `路径资源:${pathResourceType || "未知"} / ${pathResourceId || "未知"}`,
176
+ ];
177
+ const recommendations: string[] = [];
178
+ if (likelyUnavailableToGuest) {
179
+ recommendations.push("当前链接对 guest/未登录企业微信环境返回 blankpage,外部访问会表现为打不开或像“文档不存在”。");
180
+ }
181
+ if (shareCode) {
182
+ recommendations.push(`当前链接带有分享码 scode=${shareCode}。如分享码过期或未生效,外部访问会失败。`);
183
+ }
184
+ if (pathResourceId && padId && pathResourceId !== padId) {
185
+ recommendations.push(`链接路径中的资源标识与页面 padId 不一致:path=${pathResourceId},padId=${padId}。`);
186
+ }
187
+ if (pathResourceId && padId && pathResourceId === padId) {
188
+ recommendations.push("链接路径资源标识与页面 padId 一致,但这仍不等同于 Wedoc API 可用的真实 docId。");
189
+ }
190
+ return {
191
+ shareUrl,
192
+ finalUrl,
193
+ httpStatus: status,
194
+ contentType: readString(contentType) || undefined,
195
+ pathResourceType: pathResourceType || undefined,
196
+ pathResourceId: pathResourceId || undefined,
197
+ shareCode: shareCode || undefined,
198
+ userType: userType || undefined,
199
+ isGuest,
200
+ padId: padId || undefined,
201
+ padType: padType || undefined,
202
+ padTitle: padTitle || undefined,
203
+ ownerId: readString(ownerInfo.ownerId) || undefined,
204
+ hasShareInfo: Object.keys(shareInfo).length > 0,
205
+ hasAclInfo: Object.keys(aclInfo).length > 0,
206
+ likelyUnavailableToGuest,
207
+ findings,
208
+ recommendations,
209
+ };
210
+ }
211
+
212
+ async function inspectWecomShareLink(params: { shareUrl: string }) {
213
+ const { shareUrl } = params;
214
+ const normalizedUrl = readString(shareUrl);
215
+ if (!normalizedUrl) throw new Error("shareUrl required");
216
+ let parsed;
217
+ try {
218
+ parsed = new URL(normalizedUrl);
219
+ } catch {
220
+ throw new Error("shareUrl must be a valid URL");
221
+ }
222
+ // To protect URLs containing underscores from markdown italic corruption in output, we ensure we return exactly what we got or wrap it later.
223
+
224
+ const response = await fetch(parsed.toString(), {
225
+ headers: {
226
+ "user-agent": "OpenClaw-Wechat/1.0",
227
+ accept: "text/html,application/xhtml+xml",
228
+ },
229
+ });
230
+ const contentType = response.headers?.get("content-type") || "";
231
+ const html = await response.text();
232
+ const basicClientVars = extractEmbeddedJson(html, "basicClientVars");
233
+ const diagnosis = buildShareLinkDiagnosis({
234
+ shareUrl: normalizedUrl,
235
+ finalUrl: response.url || parsed.toString(),
236
+ status: response.status,
237
+ contentType,
238
+ basicClientVars,
239
+ });
240
+ return {
241
+ raw: {
242
+ httpStatus: response.status,
243
+ // Markdown italic protection for URLs
244
+ finalUrl: `\u00A0${response.url || parsed.toString()}\u00A0`.trim(),
245
+ contentType,
246
+ basicClientVars,
247
+ },
248
+ diagnosis,
249
+ };
250
+ }
251
+
252
+ function summarizeShareLinkDiagnosis(diagnosis: any = {}) {
253
+ const parts = Array.isArray(diagnosis.findings) ? diagnosis.findings : [];
254
+ return parts.length > 0 ? `分享链接校验:${parts.join(",")}` : "分享链接校验已完成";
255
+ }
256
+
257
+ function summarizeSheetProperties(result: any = {}) {
258
+ return `表格属性已获取:工作表 ${result.properties?.length ?? 0}`;
259
+ }
260
+
261
+ function summarizeDocAccess(result: any = {}) {
262
+ const parts = [];
263
+ if (result.addedViewerCount) parts.push(`新增查看成员 ${result.addedViewerCount}`);
264
+ if (result.addedCollaboratorCount) parts.push(`新增协作者 ${result.addedCollaboratorCount}`);
265
+ if (result.removedViewerCount) parts.push(`移除查看成员 ${result.removedViewerCount}`);
266
+ if (result.removedCollaboratorCount) parts.push(`移除协作者 ${result.removedCollaboratorCount}`);
267
+ return parts.length > 0 ? `文档权限已更新:${parts.join(",")}` : "文档权限已更新";
268
+ }
269
+
270
+ function summarizeFormInfo(result: any = {}) {
271
+ const title = readString(result.formInfo?.form_title) || "未命名收集表";
272
+ return `收集表“${title}”信息已获取`;
273
+ }
274
+
275
+ function summarizeFormAnswer(result: any = {}) {
276
+ return `收集表答案已获取:字段 ${result.answerList?.length ?? 0}`;
277
+ }
278
+
279
+ function summarizeFormStatistic(result: any = {}) {
280
+ return `收集表统计已获取:请求 ${result.items?.length ?? 0},成功 ${result.successCount ?? 0}`;
281
+ }
282
+
283
+ function summarizeAdvancedAccount(result: any = {}, action: string) {
284
+ if (action === "assign") return `高级功能账号分配任务已提交,jobid: ${result.jobid || "未知"}`;
285
+ if (action === "cancel") return `高级功能账号取消任务已提交,jobid: ${result.jobid || "未知"}`;
286
+ return `高级功能账号列表已获取:${result.userList?.length ?? 0} 个`;
287
+ }
288
+
289
+ function readMemberUserId(value: any) {
290
+ if (typeof value === "string" || typeof value === "number") {
291
+ return readString(value);
292
+ }
293
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "";
294
+ return readString(value.userid ?? value.userId);
295
+ }
296
+
297
+ function hasMemberUserId(values: any, requesterSenderId: string) {
298
+ const normalizedRequesterSenderId = readString(requesterSenderId);
299
+ if (!normalizedRequesterSenderId) return false;
300
+ return Array.isArray(values) && values.some((item) => readMemberUserId(item) === normalizedRequesterSenderId);
301
+ }
302
+
303
+ function resolveCreateCollaborators(params: {
304
+ toolContext: any;
305
+ requestParams: any;
306
+ }) {
307
+ const { toolContext, requestParams } = params;
308
+ const explicitCollaborators = Array.isArray(requestParams?.collaborators) ? [...requestParams.collaborators] : [];
309
+ const requesterSenderId = readString(toolContext?.senderId || toolContext?.requesterSenderId); // align with OpenClaw standard `senderId`
310
+ if (!requesterSenderId) return explicitCollaborators;
311
+ // By default, let's always auto-grant requester
312
+ if (hasMemberUserId(explicitCollaborators, requesterSenderId)) return explicitCollaborators;
313
+ if (hasMemberUserId(requestParams?.viewers, requesterSenderId)) return explicitCollaborators;
314
+ explicitCollaborators.push(requesterSenderId);
315
+ return explicitCollaborators;
316
+ }
317
+
318
+ function buildToolResult(payload: any) {
319
+ // To avoid formatting issues with URLs having underscores rendering as markdown Italics
320
+ if (payload.url) payload.url = `<${payload.url}>`;
321
+ if (payload.diagnosis?.finalUrl) payload.diagnosis.finalUrl = `<${payload.diagnosis.finalUrl}>`;
322
+ if (payload.diagnosis?.shareUrl) payload.diagnosis.shareUrl = `<${payload.diagnosis.shareUrl}>`;
323
+ return {
324
+ content: [{ type: "text" as const, text: JSON.stringify(payload, null, 2) }],
325
+ details: payload,
326
+ };
327
+ }
328
+
329
+ export function registerWecomDocTools(api: OpenClawPluginApi) {
330
+ if (typeof api?.registerTool !== "function") return;
331
+ const docClient = new WecomDocClient();
332
+
333
+ api.registerTool((toolContext: any) => ({
334
+ name: "wecom_doc",
335
+ label: "WeCom Doc",
336
+ description: "企业微信文档工具。支持文档/表格/收集表完整CRUD操作、查看/协作者权限配置、属性查询以及分享打不开可用性诊断功能。",
337
+ parameters: wecomDocToolSchema,
338
+ async execute(_toolCallId, params: any) {
339
+ try {
340
+ let accountId = params.accountId || toolContext?.accountId || "default";
341
+ const account = resolveAgentAccountOrUndefined(api.config, accountId);
342
+ if (!account || !account.configured) {
343
+ throw new Error(`WeCom account ${accountId} not configured for Doc API requirements`);
344
+ }
345
+
346
+ const action = params.action;
347
+ switch (action) {
348
+ case "create": {
349
+ const collaborators = resolveCreateCollaborators({ toolContext, requestParams: params });
350
+ const result = await docClient.createDoc({
351
+ agent: account,
352
+ docName: params.docName,
353
+ docType: params.docType,
354
+ spaceId: params.spaceId,
355
+ fatherId: params.fatherId,
356
+ adminUsers: params.adminUsers,
357
+ });
358
+
359
+ // Handle initial content (title/body separation) if provided
360
+ let contentResult: any = null;
361
+ if (Array.isArray(params.init_content) && params.init_content.length > 0) {
362
+ try {
363
+ // 1. Get initial content to find paragraph boundaries
364
+ const initContent = await docClient.getDocContent({
365
+ agent: account,
366
+ docId: result.docId,
367
+ });
368
+
369
+ // We assume a new doc has 1 empty paragraph.
370
+ // We will insert content sequentially.
371
+ // Note: WeCom API indices shift after insertion.
372
+ // Strategy:
373
+ // - Insert Para 1 (Title) at 0.
374
+ // - Insert Paragraph Break (creates new para).
375
+ // - Insert Para 2 (Content) at new index.
376
+ // To be safe and follow "Correct Flow", we will do it in a loop or calculate carefully.
377
+ // Since batch_update is atomic, indices are relative to start of batch? NO, usually sequential in batch.
378
+ // But user says "Must call get_content".
379
+ // So we will do it step-by-step for safety as per user instruction.
380
+
381
+ let currentContent = initContent;
382
+ let requests: UpdateRequest[] = [];
383
+
384
+ // If we have content, we treat the first item as "Title" (or first paragraph)
385
+ // The doc starts with one empty paragraph.
386
+
387
+ // Step 1: Insert first paragraph text at index 0
388
+ if (params.init_content[0]) {
389
+ const titleText = String(params.init_content[0]);
390
+ await docClient.updateDocContent({
391
+ agent: account,
392
+ docId: result.docId,
393
+ requests: [{
394
+ insert_text: {
395
+ text: titleText,
396
+ location: { index: 0 }
397
+ }
398
+ }]
399
+ });
400
+
401
+ // Apply Title Styling (Bold)
402
+ // We assume the title is at the start (0) and has the length of the text.
403
+ if (titleText.length > 0) {
404
+ await docClient.updateDocContent({
405
+ agent: account,
406
+ docId: result.docId,
407
+ requests: [{
408
+ update_text_property: {
409
+ text_property: { bold: true },
410
+ ranges: [{ start_index: 0, length: titleText.length }]
411
+ }
412
+ }]
413
+ });
414
+ }
415
+ }
416
+
417
+ // Step 2: For subsequent paragraphs, we need to append.
418
+ for (let i = 1; i < params.init_content.length; i++) {
419
+ const text = String(params.init_content[i]);
420
+ if (!text) continue;
421
+
422
+ // Refresh content to get latest end position
423
+ currentContent = await docClient.getDocContent({
424
+ agent: account,
425
+ docId: result.docId,
426
+ });
427
+
428
+ // Find the end of the document (or last paragraph)
429
+ // We use 'end' directly as the insertion point for appending.
430
+ // Note: WeCom 'end' is exclusive [begin, end).
431
+ // If we insert at 'end', we append after the last element.
432
+ let docEndIndex = currentContent.document.end;
433
+
434
+ // Safety adjustment: If the document has a final mandatory newline/EOF that we can't append after,
435
+ // we might need to insert *before* it.
436
+ // However, creating a NEW paragraph usually happens at the end.
437
+ // If we are unsure, we try 'end - 1' if 'end' fails, but 'end' is the standard "append" index.
438
+ // Given the user analysis "Paragraph 2 (5-117)" where 5 was the end of Para 1,
439
+ // it suggests we insert AT the boundary.
440
+
441
+ // We use insert_paragraph to create a split
442
+ await docClient.updateDocContent({
443
+ agent: account,
444
+ docId: result.docId,
445
+ requests: [{
446
+ insert_paragraph: {
447
+ location: { index: docEndIndex }
448
+ }
449
+ }]
450
+ });
451
+
452
+ // Now insert text into the new paragraph
453
+ // We need to refresh again or assume index shifted by 1
454
+ currentContent = await docClient.getDocContent({
455
+ agent: account,
456
+ docId: result.docId,
457
+ });
458
+
459
+ // The new paragraph should be at the end.
460
+ // We want to insert text *into* this new paragraph.
461
+ // The insert_paragraph likely created a new Paragraph node.
462
+ // We insert at the new end (which is inside the new paragraph).
463
+ const newParaIndex = currentContent.document.end;
464
+
465
+ await docClient.updateDocContent({
466
+ agent: account,
467
+ docId: result.docId,
468
+ requests: [{
469
+ insert_text: {
470
+ text: text,
471
+ location: { index: newParaIndex }
472
+ }
473
+ }]
474
+ });
475
+ }
476
+ contentResult = "init_content_populated";
477
+ } catch (err) {
478
+ contentResult = `content_failed: ${err instanceof Error ? err.message : String(err)}`;
479
+ }
480
+ }
481
+
482
+ let accessResult: any = null;
483
+ if ((Array.isArray(params.viewers) && params.viewers.length > 0) || collaborators.length > 0) {
484
+ try {
485
+ accessResult = await docClient.grantDocAccess({
486
+ agent: account,
487
+ docId: result.docId,
488
+ viewers: params.viewers,
489
+ collaborators,
490
+ });
491
+ } catch (err) {
492
+ return buildToolResult({
493
+ ok: false,
494
+ partial: true,
495
+ action: "create",
496
+ accountId: account.accountId,
497
+ resourceType: result.docTypeLabel,
498
+ canonicalDocId: result.docId,
499
+ docId: result.docId,
500
+ title: readString(params.docName),
501
+ url: result.url || undefined,
502
+ summary: `已创建${mapDocTypeLabel(result.docType)}“${readString(params.docName)}”(docId: ${result.docId}),但权限授予失败`,
503
+ usageHint: buildDocIdUsageHint(result.docId) || undefined,
504
+ error: err instanceof Error ? err.message : String(err),
505
+ raw: { create: result.raw },
506
+ });
507
+ }
508
+ }
509
+ return buildToolResult({
510
+ ok: true,
511
+ action: "create",
512
+ accountId: account.accountId,
513
+ resourceType: result.docTypeLabel,
514
+ canonicalDocId: result.docId,
515
+ docId: result.docId,
516
+ title: readString(params.docName),
517
+ url: result.url || undefined,
518
+ summary: accessResult
519
+ ? `已创建${mapDocTypeLabel(result.docType)}“${readString(params.docName)}”(docId: ${result.docId});${summarizeDocAccess(accessResult)}` + (contentResult ? `;内容填充: ${contentResult}` : "")
520
+ : `已创建${mapDocTypeLabel(result.docType)}“${readString(params.docName)}”(docId: ${result.docId})` + (contentResult ? `;内容填充: ${contentResult}` : ""),
521
+ usageHint: buildDocIdUsageHint(result.docId) || undefined,
522
+ raw: accessResult ? { create: result.raw, access: accessResult.raw } : result.raw,
523
+ });
524
+ }
525
+ case "rename": {
526
+ const result = await docClient.renameDoc({
527
+ agent: account,
528
+ docId: params.docId,
529
+ newName: params.newName,
530
+ });
531
+ return buildToolResult({
532
+ ok: true,
533
+ action: "rename",
534
+ accountId: account.accountId,
535
+ docId: result.docId,
536
+ title: result.newName,
537
+ summary: `文档已重命名为“${result.newName}”`,
538
+ raw: result.raw,
539
+ });
540
+ }
541
+ case "copy": {
542
+ const result = await docClient.copyDoc({
543
+ agent: account,
544
+ docId: params.docId,
545
+ newName: params.newName,
546
+ spaceId: params.spaceId,
547
+ fatherId: params.fatherId,
548
+ });
549
+ return buildToolResult({
550
+ ok: true,
551
+ action: "copy",
552
+ accountId: account.accountId,
553
+ docId: result.docId,
554
+ summary: `文档已成功复制,新 docId: ${result.docId}`,
555
+ raw: result.raw,
556
+ });
557
+ }
558
+ case "get_info": {
559
+ const result = await docClient.getDocBaseInfo({
560
+ agent: account,
561
+ docId: params.docId,
562
+ });
563
+ return buildToolResult({
564
+ ok: true,
565
+ action: "get_info",
566
+ accountId: account.accountId,
567
+ docId: params.docId,
568
+ title: readString(result.info?.doc_name) || undefined,
569
+ resourceType:
570
+ Number(result.info?.doc_type) === 10 ? "smart_table" : Number(result.info?.doc_type) === 4 ? "spreadsheet" : "doc",
571
+ summary: summarizeDocInfo(result.info),
572
+ raw: result.raw,
573
+ });
574
+ }
575
+ case "share": {
576
+ const result = await docClient.shareDoc({
577
+ agent: account,
578
+ docId: params.docId,
579
+ });
580
+ return buildToolResult({
581
+ ok: true,
582
+ action: "share",
583
+ accountId: account.accountId,
584
+ canonicalDocId: params.docId,
585
+ docId: params.docId,
586
+ url: result.shareUrl || undefined,
587
+ summary: result.shareUrl ? `文档分享链接已获取(docId: ${params.docId})` : `文档分享接口调用成功(docId: ${params.docId})`,
588
+ usageHint: buildDocIdUsageHint(params.docId) || undefined,
589
+ raw: result.raw,
590
+ });
591
+ }
592
+ case "get_auth": {
593
+ const result = await docClient.getDocAuth({
594
+ agent: account,
595
+ docId: params.docId,
596
+ });
597
+ const diagnosis = buildDocAuthDiagnosis(result, toolContext?.senderId);
598
+ return buildToolResult({
599
+ ok: true,
600
+ action: "get_auth",
601
+ accountId: account.accountId,
602
+ canonicalDocId: params.docId,
603
+ docId: params.docId,
604
+ summary: summarizeDocAuth(result),
605
+ diagnosis,
606
+ raw: result.raw,
607
+ });
608
+ }
609
+ case "diagnose_auth": {
610
+ const result = await docClient.getDocAuth({
611
+ agent: account,
612
+ docId: params.docId,
613
+ });
614
+ const diagnosis = buildDocAuthDiagnosis(result, toolContext?.senderId);
615
+ return buildToolResult({
616
+ ok: true,
617
+ action: "diagnose_auth",
618
+ accountId: account.accountId,
619
+ canonicalDocId: params.docId,
620
+ docId: params.docId,
621
+ summary: summarizeDocAuthDiagnosis(diagnosis),
622
+ diagnosis,
623
+ raw: result.raw,
624
+ });
625
+ }
626
+ case "validate_share_link": {
627
+ const result = await inspectWecomShareLink({
628
+ shareUrl: params.shareUrl,
629
+ });
630
+ return buildToolResult({
631
+ ok: true,
632
+ action: "validate_share_link",
633
+ accountId: account.accountId,
634
+ url: result.diagnosis.finalUrl || params.shareUrl,
635
+ summary: summarizeShareLinkDiagnosis(result.diagnosis),
636
+ diagnosis: result.diagnosis,
637
+ raw: result.raw,
638
+ });
639
+ }
640
+ case "delete": {
641
+ const result = await docClient.deleteDoc({
642
+ agent: account,
643
+ docId: params.docId,
644
+ formId: params.formId,
645
+ });
646
+ return buildToolResult({
647
+ ok: true,
648
+ action: "delete",
649
+ accountId: account.accountId,
650
+ docId: result.docId || undefined,
651
+ formId: result.formId || undefined,
652
+ summary: result.formId ? "收集表已删除" : "文档已删除",
653
+ raw: result.raw,
654
+ });
655
+ }
656
+ case "set_join_rule": {
657
+ const result = await docClient.setDocJoinRule({
658
+ agent: account,
659
+ docId: params.docId,
660
+ request: params.request,
661
+ });
662
+ return buildToolResult({
663
+ ok: true,
664
+ action: "set_join_rule",
665
+ accountId: account.accountId,
666
+ docId: result.docId,
667
+ summary: "文档查看规则已更新",
668
+ raw: result.raw,
669
+ });
670
+ }
671
+ case "set_member_auth": {
672
+ const result = await docClient.setDocMemberAuth({
673
+ agent: account,
674
+ docId: params.docId,
675
+ request: params.request,
676
+ });
677
+ return buildToolResult({
678
+ ok: true,
679
+ action: "set_member_auth",
680
+ accountId: account.accountId,
681
+ docId: result.docId,
682
+ summary: "文档通知范围及成员权限已更新",
683
+ raw: result.raw,
684
+ });
685
+ }
686
+ case "grant_access": {
687
+ const result = await docClient.grantDocAccess({
688
+ agent: account,
689
+ docId: params.docId,
690
+ viewers: params.viewers,
691
+ collaborators: params.collaborators,
692
+ removeViewers: params.removeViewers,
693
+ removeCollaborators: params.removeCollaborators,
694
+ authLevel: params.auth,
695
+ });
696
+ return buildToolResult({
697
+ ok: true,
698
+ action: "grant_access",
699
+ accountId: account.accountId,
700
+ docId: result.docId,
701
+ summary: summarizeDocAccess(result),
702
+ raw: result.raw,
703
+ });
704
+ }
705
+ case "add_collaborators": {
706
+ const result = await docClient.addDocCollaborators({
707
+ agent: account,
708
+ docId: params.docId,
709
+ collaborators: params.collaborators,
710
+ auth: params.auth,
711
+ });
712
+ return buildToolResult({
713
+ ok: true,
714
+ action: "add_collaborators",
715
+ accountId: account.accountId,
716
+ docId: result.docId,
717
+ summary: `协作者已添加:${result.addedCollaboratorCount ?? 0}`,
718
+ raw: result.raw,
719
+ });
720
+ }
721
+ case "get_content": {
722
+ const result = await docClient.getDocContent({
723
+ agent: account,
724
+ docId: params.docId,
725
+ });
726
+ return buildToolResult({
727
+ ok: true,
728
+ action: "get_content",
729
+ accountId: account.accountId,
730
+ docId: params.docId,
731
+ summary: "文档内容已获取",
732
+ raw: result.raw,
733
+ });
734
+ }
735
+ case "update_content": {
736
+ const result = await docClient.updateDocContent({
737
+ agent: account,
738
+ docId: params.docId,
739
+ requests: params.requests,
740
+ version: params.version,
741
+ });
742
+ return buildToolResult({
743
+ ok: true,
744
+ action: "update_content",
745
+ accountId: account.accountId,
746
+ docId: params.docId,
747
+ summary: "文档内容已更新",
748
+ raw: result.raw,
749
+ });
750
+ }
751
+ case "set_safety_setting": {
752
+ const result = await docClient.setDocSafetySetting({
753
+ agent: account,
754
+ docId: params.docId,
755
+ request: params.request,
756
+ });
757
+ return buildToolResult({
758
+ ok: true,
759
+ action: "set_safety_setting",
760
+ accountId: account.accountId,
761
+ docId: result.docId,
762
+ summary: "文档安全设置已更新",
763
+ raw: result.raw,
764
+ });
765
+ }
766
+ case "get_doc_security_setting": {
767
+ const result = await docClient.getDocAuth({
768
+ agent: account,
769
+ docId: params.docId,
770
+ });
771
+ return buildToolResult({
772
+ ok: true,
773
+ action: "get_doc_security_setting",
774
+ accountId: account.accountId,
775
+ docId: params.docId,
776
+ summary: "文档安全设置已获取",
777
+ details: result.secureSetting,
778
+ raw: result.raw,
779
+ });
780
+ }
781
+ case "mod_doc_security_setting": {
782
+ // Alias to setDocSafetySetting logic
783
+ const result = await docClient.setDocSafetySetting({
784
+ agent: account,
785
+ docId: params.docId,
786
+ request: params.setting,
787
+ });
788
+ return buildToolResult({
789
+ ok: true,
790
+ action: "mod_doc_security_setting",
791
+ accountId: account.accountId,
792
+ docId: result.docId,
793
+ summary: "文档安全设置已更新",
794
+ raw: result.raw,
795
+ });
796
+ }
797
+ case "mod_doc_member_notified_scope": {
798
+ const result = await docClient.modDocMemberNotifiedScope({
799
+ agent: account,
800
+ docId: params.docId,
801
+ notified_scope_type: params.notified_scope_type,
802
+ notified_member_list: params.notified_member_list,
803
+ });
804
+ return buildToolResult({
805
+ ok: true,
806
+ action: "mod_doc_member_notified_scope",
807
+ accountId: account.accountId,
808
+ docId: params.docId,
809
+ summary: "文档成员通知范围已更新",
810
+ raw: result,
811
+ });
812
+ }
813
+ case "create_collect": {
814
+ const result = await docClient.createCollect({
815
+ agent: account,
816
+ formInfo: params.formInfo,
817
+ spaceId: params.spaceId,
818
+ fatherId: params.fatherId,
819
+ });
820
+ const title = readString(result.title);
821
+ return buildToolResult({
822
+ ok: true,
823
+ action: "create_collect",
824
+ accountId: account.accountId,
825
+ formId: result.formId,
826
+ title: title || undefined,
827
+ summary: title ? `已创建收集表“${title}”` : "收集表已创建",
828
+ raw: result.raw,
829
+ });
830
+ }
831
+ case "modify_collect": {
832
+ const result = await docClient.modifyCollect({
833
+ agent: account,
834
+ oper: params.oper,
835
+ formId: params.formId,
836
+ formInfo: params.formInfo,
837
+ });
838
+ const title = readString(result.title);
839
+ return buildToolResult({
840
+ ok: true,
841
+ action: "modify_collect",
842
+ accountId: account.accountId,
843
+ formId: result.formId,
844
+ title: title || undefined,
845
+ summary: title
846
+ ? `收集表已更新(${result.oper}):“${title}”`
847
+ : `收集表已更新(${result.oper})`,
848
+ raw: result.raw,
849
+ });
850
+ }
851
+ case "get_form_info": {
852
+ const result = await docClient.getFormInfo({
853
+ agent: account,
854
+ formId: params.formId,
855
+ });
856
+ return buildToolResult({
857
+ ok: true,
858
+ action: "get_form_info",
859
+ accountId: account.accountId,
860
+ formId: params.formId,
861
+ title: readString(result.formInfo?.form_title) || undefined,
862
+ summary: summarizeFormInfo(result),
863
+ raw: result.raw,
864
+ });
865
+ }
866
+ case "get_form_answer": {
867
+ const result = await docClient.getFormAnswer({
868
+ agent: account,
869
+ repeatedId: params.repeatedId,
870
+ answerIds: params.answerIds,
871
+ });
872
+ return buildToolResult({
873
+ ok: true,
874
+ action: "get_form_answer",
875
+ accountId: account.accountId,
876
+ repeatedId: params.repeatedId,
877
+ summary: summarizeFormAnswer(result),
878
+ raw: result.raw,
879
+ });
880
+ }
881
+ case "get_form_statistic": {
882
+ const result = await docClient.getFormStatistic({
883
+ agent: account,
884
+ requests: params.requests,
885
+ });
886
+ return buildToolResult({
887
+ ok: true,
888
+ action: "get_form_statistic",
889
+ accountId: account.accountId,
890
+ summary: summarizeFormStatistic(result),
891
+ raw: result.raw,
892
+ });
893
+ }
894
+ case "get_sheet_properties": {
895
+ const result = await docClient.getSheetProperties({
896
+ agent: account,
897
+ docId: params.docId,
898
+ });
899
+ return buildToolResult({
900
+ ok: true,
901
+ action: "get_sheet_properties",
902
+ accountId: account.accountId,
903
+ docId: params.docId,
904
+ summary: summarizeSheetProperties(result),
905
+ raw: result.raw,
906
+ });
907
+ }
908
+ case "edit_sheet_data": {
909
+ const result = await docClient.editSheetData({
910
+ agent: account,
911
+ docId: params.docId,
912
+ request: params.request,
913
+ });
914
+ return buildToolResult({
915
+ ok: true,
916
+ action: "edit_sheet_data",
917
+ accountId: account.accountId,
918
+ docId: result.docId,
919
+ summary: "在线表格数据已编辑",
920
+ raw: result.raw,
921
+ });
922
+ }
923
+ case "get_sheet_data": {
924
+ const result = await docClient.getSheetData({
925
+ agent: account,
926
+ docId: params.docId,
927
+ sheetId: params.sheetId,
928
+ range: params.range,
929
+ });
930
+ return buildToolResult({
931
+ ok: true,
932
+ action: "get_sheet_data",
933
+ accountId: account.accountId,
934
+ docId: params.docId,
935
+ summary: "在线表格数据已读取",
936
+ data: result.data,
937
+ raw: result.raw,
938
+ });
939
+ }
940
+ case "modify_sheet_properties": {
941
+ const result = await docClient.modifySheetProperties({
942
+ agent: account,
943
+ docId: params.docId,
944
+ requests: params.requests,
945
+ });
946
+ return buildToolResult({
947
+ ok: true,
948
+ action: "modify_sheet_properties",
949
+ accountId: account.accountId,
950
+ docId: result.docId,
951
+ summary: "在线表格属性已修改",
952
+ raw: result.raw,
953
+ });
954
+ }
955
+ case "smartsheet_add_records": {
956
+ const result = await docClient.smartTableOperate({
957
+ agent: account,
958
+ docId: params.docId,
959
+ operation: "add_records",
960
+ bodyData: params,
961
+ });
962
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已添加", raw: result.raw });
963
+ }
964
+ case "smartsheet_update_records": {
965
+ const result = await docClient.smartTableOperate({
966
+ agent: account,
967
+ docId: params.docId,
968
+ operation: "update_records",
969
+ bodyData: params,
970
+ });
971
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已更新", raw: result.raw });
972
+ }
973
+ case "smartsheet_del_records": {
974
+ const result = await docClient.smartTableOperate({
975
+ agent: account,
976
+ docId: params.docId,
977
+ operation: "del_records",
978
+ bodyData: params,
979
+ });
980
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已删除", raw: result.raw });
981
+ }
982
+ case "smartsheet_get_records": {
983
+ const result = await docClient.smartTableOperate({
984
+ agent: account,
985
+ docId: params.docId,
986
+ operation: "get_records",
987
+ bodyData: params,
988
+ });
989
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已获取", raw: result.raw });
990
+ }
991
+ case "smartsheet_add_sheet": {
992
+ const result = await docClient.smartTableAddSheet({ agent: account, ...params });
993
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格子表已添加", raw: result.raw });
994
+ }
995
+ case "smartsheet_del_sheet": {
996
+ const result = await docClient.smartTableDelSheet({ agent: account, ...params });
997
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格子表已删除", raw: result.raw });
998
+ }
999
+ case "smartsheet_update_sheet": {
1000
+ const result = await docClient.smartTableUpdateSheet({ agent: account, ...params });
1001
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格子表已更新", raw: result.raw });
1002
+ }
1003
+ case "smartsheet_add_view": {
1004
+ const result = await docClient.smartTableAddView({ agent: account, ...params });
1005
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格视图已添加", raw: result.raw });
1006
+ }
1007
+ case "smartsheet_del_view": {
1008
+ const result = await docClient.smartTableDelView({ agent: account, ...params });
1009
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格视图已删除", raw: result.raw });
1010
+ }
1011
+ case "smartsheet_get_views": {
1012
+ const result = await docClient.smartTableOperate({ agent: account, docId: params.docId, operation: "get_views", bodyData: { sheet_id: params.sheetId } });
1013
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格视图列表已获取", raw: result.raw });
1014
+ }
1015
+ case "smartsheet_add_fields": {
1016
+ const result = await docClient.smartTableAddFields({ agent: account, ...params });
1017
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格字段已添加", raw: result.raw });
1018
+ }
1019
+ case "smartsheet_del_fields": {
1020
+ const result = await docClient.smartTableDelFields({ agent: account, ...params });
1021
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格字段已删除", raw: result.raw });
1022
+ }
1023
+ case "smartsheet_update_fields": {
1024
+ const result = await docClient.smartTableUpdateFields({ agent: account, ...params });
1025
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格字段已更新", raw: result.raw });
1026
+ }
1027
+ case "smartsheet_update_view": {
1028
+ const result = await docClient.smartTableUpdateView({ agent: account, ...params });
1029
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格视图已更新", raw: result.raw });
1030
+ }
1031
+ case "smartsheet_get_fields": {
1032
+ const result = await docClient.smartTableOperate({ agent: account, docId: params.docId, operation: "get_fields", bodyData: { sheet_id: params.sheetId, view_id: params.view_id } });
1033
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格字段列表已获取", raw: result.raw });
1034
+ }
1035
+ case "smartsheet_add_group": {
1036
+ const result = await docClient.smartTableAddGroup({ agent: account, ...params });
1037
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格编组已添加", raw: result.raw });
1038
+ }
1039
+ case "smartsheet_del_group": {
1040
+ const result = await docClient.smartTableDelGroup({ agent: account, ...params });
1041
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格编组已删除", raw: result.raw });
1042
+ }
1043
+ case "smartsheet_update_group": {
1044
+ const result = await docClient.smartTableUpdateGroup({ agent: account, ...params });
1045
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格编组已更新", raw: result.raw });
1046
+ }
1047
+ case "smartsheet_get_groups": {
1048
+ const result = await docClient.smartTableGetGroups({ agent: account, ...params });
1049
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格编组列表已获取", raw: result.raw });
1050
+ }
1051
+ case "smartsheet_add_external_records": {
1052
+ const result = await docClient.smartTableAddExternalRecords({ agent: account, ...params });
1053
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格外部记录已添加", raw: result.raw });
1054
+ }
1055
+ case "smartsheet_update_external_records": {
1056
+ const result = await docClient.smartTableUpdateExternalRecords({ agent: account, ...params });
1057
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格外部记录已更新", raw: result.raw });
1058
+ }
1059
+ case "smartsheet_add_records": {
1060
+ const result = await docClient.smartTableAddRecords({ agent: account, ...params });
1061
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已添加", raw: result.raw });
1062
+ }
1063
+ case "smartsheet_update_records": {
1064
+ const result = await docClient.smartTableUpdateRecords({ agent: account, ...params });
1065
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已更新", raw: result.raw });
1066
+ }
1067
+ case "smartsheet_del_records": {
1068
+ const result = await docClient.smartTableDelRecords({ agent: account, ...params });
1069
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录已删除", raw: result.raw });
1070
+ }
1071
+ case "smartsheet_get_records": {
1072
+ const result = await docClient.smartTableGetRecords({ agent: account, ...params });
1073
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格记录列表已获取", raw: result.raw });
1074
+ }
1075
+ case "smartsheet_get_sheets": {
1076
+ const result = await docClient.smartTableGetSheets({
1077
+ agent: account,
1078
+ docId: params.docId,
1079
+ });
1080
+ return buildToolResult({
1081
+ ok: true,
1082
+ action: "smartsheet_get_sheets",
1083
+ accountId: account.accountId,
1084
+ docId: params.docId,
1085
+ summary: `智能表格子表列表已获取:${result.sheets.length} 个`,
1086
+ raw: result.raw,
1087
+ });
1088
+ }
1089
+ case "smartsheet_get_sheet_priv": {
1090
+ const result = await docClient.smartTableGetSheetPriv({ agent: account, ...params });
1091
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格子表权限已获取", raw: result.raw });
1092
+ }
1093
+ case "smartsheet_update_sheet_priv": {
1094
+ const result = await docClient.smartTableUpdateSheetPriv({ agent: account, ...params });
1095
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格子表权限已更新", raw: result.raw });
1096
+ }
1097
+ case "smartsheet_create_rule": {
1098
+ const result = await docClient.smartTableCreateRule({ agent: account, ...params });
1099
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: `智能表格成员额外权限规则已创建 (rule_id: ${result.rule_id})`, raw: result.raw });
1100
+ }
1101
+ case "smartsheet_mod_rule_member": {
1102
+ const result = await docClient.smartTableModRuleMember({ agent: account, ...params });
1103
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格成员额外权限成员已更新", raw: result.raw });
1104
+ }
1105
+ case "smartsheet_delete_rule": {
1106
+ const result = await docClient.smartTableDeleteRule({ agent: account, ...params });
1107
+ return buildToolResult({ ok: true, action, accountId: account.accountId, docId: params.docId, summary: "智能表格成员额外权限规则已删除", raw: result.raw });
1108
+ }
1109
+ case "doc_assign_advanced_account": {
1110
+ const result = await docClient.assignDocAdvancedAccount({ agent: account, userid_list: params.userid_list });
1111
+ return buildToolResult({ ok: true, action, accountId: account.accountId, summary: summarizeAdvancedAccount(result.raw, "assign"), raw: result.raw });
1112
+ }
1113
+ case "doc_cancel_advanced_account": {
1114
+ const result = await docClient.cancelDocAdvancedAccount({ agent: account, userid_list: params.userid_list });
1115
+ return buildToolResult({ ok: true, action, accountId: account.accountId, summary: summarizeAdvancedAccount(result.raw, "cancel"), raw: result.raw });
1116
+ }
1117
+ case "doc_get_advanced_account_list": {
1118
+ const result = await docClient.getDocAdvancedAccountList({ agent: account, ...params });
1119
+ return buildToolResult({ ok: true, action, accountId: account.accountId, summary: summarizeAdvancedAccount(result, "list"), raw: result.raw });
1120
+ }
1121
+ case "upload_doc_image": {
1122
+ const filePath = params.file_path;
1123
+ if (!fs.existsSync(filePath)) {
1124
+ throw new Error(`File not found: ${filePath}`);
1125
+ }
1126
+ const fileContent = fs.readFileSync(filePath);
1127
+ const base64Content = fileContent.toString("base64");
1128
+
1129
+ const result = await docClient.uploadDocImage({
1130
+ agent: account,
1131
+ docId: params.docId,
1132
+ base64_content: base64Content,
1133
+ });
1134
+ return buildToolResult({
1135
+ ok: true,
1136
+ action,
1137
+ accountId: account.accountId,
1138
+ summary: "图片上传成功",
1139
+ details: {
1140
+ url: result.url,
1141
+ width: result.width,
1142
+ height: result.height,
1143
+ size: result.size,
1144
+ },
1145
+ raw: result.raw,
1146
+ });
1147
+ }
1148
+ default:
1149
+ throw new Error(`Unsupported action: ${String(action)}`);
1150
+ }
1151
+ } catch (err) {
1152
+ return {
1153
+ content: [
1154
+ {
1155
+ type: "text" as const,
1156
+ text: JSON.stringify({ ok: false, action: params?.action, error: err instanceof Error ? err.message : String(err) }, null, 2),
1157
+ },
1158
+ ],
1159
+ details: {},
1160
+ isError: true,
1161
+ };
1162
+ }
1163
+ },
1164
+ }));
1165
+ }