@openclaw/feishu 2026.7.2-beta.1 → 2026.7.2-beta.3
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/dist/api.js +322 -176
- package/dist/{app-registration-BwQ-aGTe.js → app-registration-BzkyrVZu.js} +11 -11
- package/dist/{channel-DdPQ2HGh.js → channel-BdnXYU6g.js} +36 -50
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.runtime-DJ_B-bpG.js → channel.runtime-CVIzo2dV.js} +102 -17
- package/dist/{client-BUC-R2Wi.js → client-87BmeMpj.js} +51 -16
- package/dist/{drive-Bpe8ONK_.js → drive-BHv8WW9i.js} +2 -2
- package/dist/{monitor-M3iYtoh4.js → monitor-BVQf7-Bl.js} +2 -2
- package/dist/{monitor.account-F99J862T.js → monitor.account-Blbf2T6J.js} +752 -423
- package/dist/{monitor.startup-DpZzunQn.js → monitor.startup-Cy8NPGAX.js} +1 -1
- package/dist/{probe-CAloGqgG.js → probe-BgboTHIn.js} +1 -1
- package/dist/{secret-contract-DnlMcrn5.js → secret-contract-BCpDLdg9.js} +17 -26
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-CpnLYueT.js → send-DcrXbqqA.js} +87 -8
- package/dist/{send-result-CPS7AozW.js → send-result-DfE5Fhz6.js} +31 -16
- package/dist/setup-api.js +1 -1
- package/npm-shrinkwrap.json +3 -3
- package/openclaw.plugin.json +34 -8
- package/package.json +4 -4
package/dist/api.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { r as listEnabledFeishuAccounts } from "./accounts-BDoGHJDk.js";
|
|
2
|
-
import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-
|
|
2
|
+
import { a as setFeishuNamedAccountEnabled, i as feishuSetupAdapter, n as feishuSetupWizard, r as runFeishuLogin, t as feishuPlugin } from "./channel-BdnXYU6g.js";
|
|
3
|
+
import { p as parseFeishuMarkdown, u as chunkFeishuMarkdown } from "./send-result-DfE5Fhz6.js";
|
|
3
4
|
import { a as parseFeishuTargetId, i as parseFeishuDirectConversationId, n as buildFeishuModelOverrideParentCandidates, r as parseFeishuConversationId, t as buildFeishuConversationId } from "./conversation-id-BeJL-wq7.js";
|
|
5
|
+
import { r as createFeishuClient, s as resolveConfiguredHttpTimeoutMs } from "./client-87BmeMpj.js";
|
|
4
6
|
import { t as getFeishuRuntime } from "./runtime-C5JxBWZp.js";
|
|
5
|
-
import {
|
|
6
|
-
import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-Bpe8ONK_.js";
|
|
7
|
+
import { a as toolExecutionErrorResult, f as registerFeishuChatTools, g as resolveToolsConfig, h as resolveFeishuToolAccount, m as resolveAnyEnabledFeishuToolsConfig, n as registerFeishuDriveTools, o as unknownToolActionResult, p as createFeishuToolClient } from "./drive-BHv8WW9i.js";
|
|
7
8
|
import { n as getFeishuThreadBindingManager, r as testing, t as createFeishuThreadBindingManager } from "./thread-bindings-V0bwk0A1.js";
|
|
8
9
|
import { n as handleFeishuSubagentEnded, r as handleFeishuSubagentSpawning, t as handleFeishuSubagentDeliveryTarget } from "./subagent-hooks-BKTOxB-T.js";
|
|
9
10
|
import { optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
|
|
@@ -12,9 +13,9 @@ import { existsSync } from "node:fs";
|
|
|
12
13
|
import { homedir } from "node:os";
|
|
13
14
|
import { basename, isAbsolute, resolve } from "node:path";
|
|
14
15
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
15
|
-
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
|
|
16
16
|
import { jsonResult } from "openclaw/plugin-sdk/tool-results";
|
|
17
17
|
import { Type } from "typebox";
|
|
18
|
+
import { canonicalizeBase64, estimateBase64DecodedBytes, extensionForMime } from "openclaw/plugin-sdk/media-runtime";
|
|
18
19
|
import { readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
|
|
19
20
|
import { createClackPrompter } from "openclaw/plugin-sdk/setup-runtime";
|
|
20
21
|
//#region extensions/feishu/src/doc-schema.ts
|
|
@@ -565,6 +566,249 @@ async function updateColorText(client, docToken, blockId, content) {
|
|
|
565
566
|
};
|
|
566
567
|
}
|
|
567
568
|
//#endregion
|
|
569
|
+
//#region extensions/feishu/src/docx-markdown.ts
|
|
570
|
+
const MAX_BREAK_PROBES = 32;
|
|
571
|
+
const STABLE_LINE_CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
572
|
+
"list",
|
|
573
|
+
"blockquote",
|
|
574
|
+
"code"
|
|
575
|
+
]);
|
|
576
|
+
function visitMarkdown(root, visitor) {
|
|
577
|
+
const pending = [root];
|
|
578
|
+
while (pending.length > 0) {
|
|
579
|
+
const node = pending.pop();
|
|
580
|
+
if (!node) continue;
|
|
581
|
+
visitor(node);
|
|
582
|
+
if (!node.children) continue;
|
|
583
|
+
for (let index = node.children.length - 1; index >= 0; index -= 1) {
|
|
584
|
+
const child = node.children[index];
|
|
585
|
+
if (child) pending.push(child);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
function resolveRemoteImageUrl(value) {
|
|
590
|
+
if (!value) return;
|
|
591
|
+
try {
|
|
592
|
+
const url = new URL(value);
|
|
593
|
+
return url.protocol === "http:" || url.protocol === "https:" ? value : void 0;
|
|
594
|
+
} catch {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function collectMarkdownImages(root) {
|
|
599
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
600
|
+
visitMarkdown(root, (node) => {
|
|
601
|
+
if (node.type !== "definition" || !node.identifier || !node.url) return;
|
|
602
|
+
if (!definitions.has(node.identifier)) definitions.set(node.identifier, node.url);
|
|
603
|
+
});
|
|
604
|
+
const images = [];
|
|
605
|
+
visitMarkdown(root, (node) => {
|
|
606
|
+
if (node.type === "image") {
|
|
607
|
+
images.push({ url: resolveRemoteImageUrl(node.url) });
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (node.type === "imageReference") images.push({ url: resolveRemoteImageUrl(node.identifier ? definitions.get(node.identifier) : void 0) });
|
|
611
|
+
});
|
|
612
|
+
return images;
|
|
613
|
+
}
|
|
614
|
+
function splitSourceAtOffsets(source, offsets) {
|
|
615
|
+
const chunks = [];
|
|
616
|
+
let start = 0;
|
|
617
|
+
for (const offset of offsets) {
|
|
618
|
+
if (offset <= start || offset >= source.length) continue;
|
|
619
|
+
chunks.push(source.slice(start, offset));
|
|
620
|
+
start = offset;
|
|
621
|
+
}
|
|
622
|
+
chunks.push(source.slice(start));
|
|
623
|
+
return chunks;
|
|
624
|
+
}
|
|
625
|
+
function headingOffsets(source, root) {
|
|
626
|
+
const offsets = [];
|
|
627
|
+
for (const node of root.children ?? []) {
|
|
628
|
+
if (node.type !== "heading" || node.depth === void 0 || node.depth > 2) continue;
|
|
629
|
+
const offset = node.position?.start.offset;
|
|
630
|
+
if (offset !== void 0 && source[offset] === "#") offsets.push(offset);
|
|
631
|
+
}
|
|
632
|
+
return offsets;
|
|
633
|
+
}
|
|
634
|
+
function blockBreakOffsets(root) {
|
|
635
|
+
const offsets = [];
|
|
636
|
+
for (const block of root.children ?? []) {
|
|
637
|
+
const blockStart = block.position?.start.offset;
|
|
638
|
+
if (blockStart !== void 0 && blockStart > 0) offsets.push(blockStart);
|
|
639
|
+
}
|
|
640
|
+
return offsets;
|
|
641
|
+
}
|
|
642
|
+
function paragraphBreakOffsets(source, root) {
|
|
643
|
+
const offsets = [];
|
|
644
|
+
for (const block of root.children ?? []) {
|
|
645
|
+
if (block.type !== "paragraph") continue;
|
|
646
|
+
for (const child of block.children ?? []) {
|
|
647
|
+
if (child.type !== "text") continue;
|
|
648
|
+
const start = child.position?.start.offset;
|
|
649
|
+
const end = child.position?.end.offset;
|
|
650
|
+
if (start === void 0 || end === void 0) continue;
|
|
651
|
+
for (let offset = start; offset < end; offset += 1) {
|
|
652
|
+
const char = source[offset];
|
|
653
|
+
if (char === " " || char === " " || char === "\n" || char === "\r") offsets.push(offset + 1);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return offsets;
|
|
658
|
+
}
|
|
659
|
+
function lineBreakOffsets(source) {
|
|
660
|
+
const offsets = [];
|
|
661
|
+
for (let offset = 0; offset < source.length; offset += 1) if (source[offset] === "\n" && offset + 1 < source.length) offsets.push(offset + 1);
|
|
662
|
+
return offsets;
|
|
663
|
+
}
|
|
664
|
+
function nearestOffset(offsets, target, sourceLength) {
|
|
665
|
+
return offsets.filter((offset) => offset > 0 && offset < sourceLength).toSorted((left, right) => Math.abs(left - target) - Math.abs(right - target) || left - right);
|
|
666
|
+
}
|
|
667
|
+
function isStableParagraphBreak(source, offset) {
|
|
668
|
+
const before = parseFeishuMarkdown(source.slice(0, offset)).children?.at(-1);
|
|
669
|
+
const after = parseFeishuMarkdown(source.slice(offset)).children?.[0];
|
|
670
|
+
return before?.type === "paragraph" && after?.type === "paragraph";
|
|
671
|
+
}
|
|
672
|
+
function isStableContainerBreak(source, offset, containerType) {
|
|
673
|
+
const before = parseFeishuMarkdown(source.slice(0, offset)).children;
|
|
674
|
+
const after = parseFeishuMarkdown(source.slice(offset)).children;
|
|
675
|
+
return before?.length === 1 && after?.length === 1 && before[0]?.type === containerType && after[0]?.type === containerType;
|
|
676
|
+
}
|
|
677
|
+
function splitTableAtRow(source, root, target) {
|
|
678
|
+
const table = root.children?.length === 1 ? root.children[0] : void 0;
|
|
679
|
+
if (table?.type !== "table") return;
|
|
680
|
+
const rows = table.children ?? [];
|
|
681
|
+
const firstBodyOffset = rows[1]?.position?.start.offset;
|
|
682
|
+
const splitOffset = nearestOffset(rows.slice(2).map((row) => row.position?.start.offset).filter((offset) => offset !== void 0), target, source.length)[0];
|
|
683
|
+
if (firstBodyOffset === void 0 || splitOffset === void 0) return;
|
|
684
|
+
const tableStart = table.position?.start.offset ?? 0;
|
|
685
|
+
const repeatedHeader = source.slice(tableStart, firstBodyOffset);
|
|
686
|
+
const chunks = [source.slice(0, splitOffset), `${repeatedHeader}${source.slice(splitOffset)}`];
|
|
687
|
+
if (chunks.every((chunk) => parseFeishuMarkdown(chunk).children?.[0]?.type === "table")) return chunks;
|
|
688
|
+
}
|
|
689
|
+
function isFencedCodeSource(source) {
|
|
690
|
+
const firstLineEnd = source.indexOf("\n");
|
|
691
|
+
const firstLine = source.slice(0, firstLineEnd === -1 ? source.length : firstLineEnd);
|
|
692
|
+
let indent = 0;
|
|
693
|
+
while (indent < firstLine.length && firstLine[indent] === " ") indent += 1;
|
|
694
|
+
if (indent > 3) return false;
|
|
695
|
+
const marker = firstLine.slice(indent);
|
|
696
|
+
return marker.startsWith("```") || marker.startsWith("~~~");
|
|
697
|
+
}
|
|
698
|
+
function createDocxMarkdownChunk(markdown) {
|
|
699
|
+
return {
|
|
700
|
+
markdown,
|
|
701
|
+
images: collectMarkdownImages(parseFeishuMarkdown(markdown))
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
function createDocxMarkdownPlan(markdown) {
|
|
705
|
+
return { chunks: splitSourceAtOffsets(markdown, headingOffsets(markdown, parseFeishuMarkdown(markdown))).map(createDocxMarkdownChunk) };
|
|
706
|
+
}
|
|
707
|
+
function splitDocxMarkdownBySize(markdown, maxChars) {
|
|
708
|
+
if (markdown.length <= maxChars) return [markdown];
|
|
709
|
+
const root = parseFeishuMarkdown(markdown);
|
|
710
|
+
const target = Math.min(markdown.length - 1, Math.max(1, maxChars));
|
|
711
|
+
const splitOffset = nearestOffset(blockBreakOffsets(root), target, markdown.length)[0];
|
|
712
|
+
if (splitOffset !== void 0) return [markdown.slice(0, splitOffset), markdown.slice(splitOffset)];
|
|
713
|
+
const paragraphOffset = nearestOffset(paragraphBreakOffsets(markdown, root), target, markdown.length).slice(0, MAX_BREAK_PROBES).find((offset) => isStableParagraphBreak(markdown, offset));
|
|
714
|
+
if (paragraphOffset !== void 0) return [markdown.slice(0, paragraphOffset), markdown.slice(paragraphOffset)];
|
|
715
|
+
if (root.children?.length === 1 && root.children[0]?.type === "code" && isFencedCodeSource(markdown)) return chunkFeishuMarkdown(markdown, maxChars);
|
|
716
|
+
const tableChunks = splitTableAtRow(markdown, root, target);
|
|
717
|
+
if (tableChunks) return tableChunks;
|
|
718
|
+
const containerType = root.children?.length === 1 ? root.children[0]?.type : void 0;
|
|
719
|
+
if (containerType && STABLE_LINE_CONTAINER_TYPES.has(containerType)) {
|
|
720
|
+
const containerOffset = nearestOffset(lineBreakOffsets(markdown), target, markdown.length).slice(0, MAX_BREAK_PROBES).find((offset) => isStableContainerBreak(markdown, offset, containerType));
|
|
721
|
+
if (containerOffset !== void 0) return [markdown.slice(0, containerOffset), markdown.slice(containerOffset)];
|
|
722
|
+
}
|
|
723
|
+
return [markdown];
|
|
724
|
+
}
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region extensions/feishu/src/docx-upload-input.ts
|
|
727
|
+
function decodeBase64Image(params) {
|
|
728
|
+
const estimatedBytes = estimateBase64DecodedBytes(params.payload);
|
|
729
|
+
if (estimatedBytes > params.maxBytes) throw new Error(`${params.oversizedLabel} exceeds limit: estimated ${estimatedBytes} bytes > ${params.maxBytes} bytes`);
|
|
730
|
+
const canonical = canonicalizeBase64(params.payload);
|
|
731
|
+
if (!canonical) throw new Error(params.invalidMessage);
|
|
732
|
+
return Buffer.from(canonical, "base64");
|
|
733
|
+
}
|
|
734
|
+
function resolveDataUriImage(image, maxBytes, fileName) {
|
|
735
|
+
const commaIndex = image.indexOf(",");
|
|
736
|
+
if (commaIndex === -1) throw new Error("Invalid data URI: missing comma separator.");
|
|
737
|
+
const metadata = image.slice(5, commaIndex).split(";");
|
|
738
|
+
if (!metadata.slice(1).map((value) => value.trim().toLowerCase()).includes("base64")) throw new Error("Invalid data URI: missing ';base64' marker. Expected format: data:image/png;base64,<base64data>");
|
|
739
|
+
const buffer = decodeBase64Image({
|
|
740
|
+
payload: image.slice(commaIndex + 1),
|
|
741
|
+
maxBytes,
|
|
742
|
+
invalidMessage: "Invalid data URI: base64 payload is malformed.",
|
|
743
|
+
oversizedLabel: "Image data URI"
|
|
744
|
+
});
|
|
745
|
+
const mime = metadata[0]?.trim();
|
|
746
|
+
const extension = extensionForMime(mime)?.slice(1) ?? "png";
|
|
747
|
+
return {
|
|
748
|
+
buffer,
|
|
749
|
+
fileName: fileName ?? `image.${extension}`
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
async function resolveLocalUpload(filePath, maxBytes, localRoots, fileName) {
|
|
753
|
+
return {
|
|
754
|
+
buffer: (await getFeishuRuntime().media.loadWebMedia(resolve(filePath), {
|
|
755
|
+
maxBytes,
|
|
756
|
+
optimizeImages: false,
|
|
757
|
+
localRoots
|
|
758
|
+
})).buffer,
|
|
759
|
+
fileName: fileName ?? basename(filePath)
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
function resolveImageLocalPath(image) {
|
|
763
|
+
const candidate = image.startsWith("~") ? `${homedir()}${image.slice(1)}` : image;
|
|
764
|
+
const unambiguousPath = image.startsWith("~") || image.startsWith("./") || image.startsWith("../");
|
|
765
|
+
const absolutePath = isAbsolute(image);
|
|
766
|
+
if (unambiguousPath || absolutePath && existsSync(candidate)) return candidate;
|
|
767
|
+
if (absolutePath) throw new Error(`File not found: "${candidate}". If you intended to pass image binary data, use a data URI instead: data:image/jpeg;base64,...`);
|
|
768
|
+
}
|
|
769
|
+
async function resolveRemoteUpload(input) {
|
|
770
|
+
const fetched = await getFeishuRuntime().channel.media.readRemoteMediaBuffer({
|
|
771
|
+
url: input.url,
|
|
772
|
+
maxBytes: input.maxBytes,
|
|
773
|
+
...input.remoteReadTimeoutMs !== void 0 ? {
|
|
774
|
+
responseHeaderTimeoutMs: input.remoteReadTimeoutMs,
|
|
775
|
+
readIdleTimeoutMs: input.remoteReadTimeoutMs
|
|
776
|
+
} : {}
|
|
777
|
+
});
|
|
778
|
+
const urlFileName = new URL(input.url).pathname.split("/").pop() || "upload.bin";
|
|
779
|
+
return {
|
|
780
|
+
buffer: fetched.buffer,
|
|
781
|
+
fileName: input.fileName ?? fetched.fileName ?? urlFileName
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
async function resolveDocxUploadInput(input) {
|
|
785
|
+
const sources = [
|
|
786
|
+
input.url && "url",
|
|
787
|
+
input.filePath && "file_path",
|
|
788
|
+
input.image && "image"
|
|
789
|
+
].filter((source) => Boolean(source));
|
|
790
|
+
if (sources.length !== 1) throw new Error(sources.length === 0 ? "Either url, file_path, or image (base64/data URI) must be provided" : `Provide only one upload source; got: ${sources.join(", ")}`);
|
|
791
|
+
if (input.url) return await resolveRemoteUpload({
|
|
792
|
+
...input,
|
|
793
|
+
url: input.url
|
|
794
|
+
});
|
|
795
|
+
if (input.filePath) return await resolveLocalUpload(input.filePath, input.maxBytes, input.localRoots, input.fileName);
|
|
796
|
+
const image = input.image;
|
|
797
|
+
if (!image) throw new Error("Image input must not be empty");
|
|
798
|
+
if (image.startsWith("data:")) return resolveDataUriImage(image, input.maxBytes, input.fileName);
|
|
799
|
+
const localPath = resolveImageLocalPath(image);
|
|
800
|
+
if (localPath) return await resolveLocalUpload(localPath, input.maxBytes, input.localRoots, input.fileName);
|
|
801
|
+
return {
|
|
802
|
+
buffer: decodeBase64Image({
|
|
803
|
+
payload: image,
|
|
804
|
+
maxBytes: input.maxBytes,
|
|
805
|
+
invalidMessage: "Invalid base64: image input is malformed. Use a data URI (data:image/png;base64,...) or a local file path instead.",
|
|
806
|
+
oversizedLabel: "Base64 image"
|
|
807
|
+
}),
|
|
808
|
+
fileName: input.fileName ?? "image.png"
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
//#endregion
|
|
568
812
|
//#region extensions/feishu/src/docx.ts
|
|
569
813
|
function resolveDocToolLocalRoots(ctx) {
|
|
570
814
|
if (ctx.fsPolicy?.workspaceOnly !== true) return;
|
|
@@ -572,19 +816,6 @@ function resolveDocToolLocalRoots(ctx) {
|
|
|
572
816
|
if (!workspaceDir) return [];
|
|
573
817
|
return [resolve(workspaceDir)];
|
|
574
818
|
}
|
|
575
|
-
/** Extract image URLs from markdown content */
|
|
576
|
-
function extractImageUrls(markdown) {
|
|
577
|
-
const regex = /!\[[^\]]*\]\(([^)]+)\)/g;
|
|
578
|
-
const urls = [];
|
|
579
|
-
let match;
|
|
580
|
-
while ((match = regex.exec(markdown)) !== null) {
|
|
581
|
-
const capturedUrl = match[1];
|
|
582
|
-
if (capturedUrl === void 0) continue;
|
|
583
|
-
const url = capturedUrl.trim();
|
|
584
|
-
if (url.startsWith("http://") || url.startsWith("https://")) urls.push(url);
|
|
585
|
-
}
|
|
586
|
-
return urls;
|
|
587
|
-
}
|
|
588
819
|
const BLOCK_TYPE_NAMES = {
|
|
589
820
|
1: "Page",
|
|
590
821
|
2: "Text",
|
|
@@ -725,83 +956,49 @@ async function insertBlocks(client, docToken, blocks, parentBlockId, index) {
|
|
|
725
956
|
skipped
|
|
726
957
|
};
|
|
727
958
|
}
|
|
728
|
-
|
|
729
|
-
function splitMarkdownByHeadings(markdown) {
|
|
730
|
-
const lines = markdown.split("\n");
|
|
731
|
-
const chunks = [];
|
|
732
|
-
let current = [];
|
|
733
|
-
let inFencedBlock = false;
|
|
734
|
-
for (const line of lines) {
|
|
735
|
-
if (/^(`{3,}|~{3,})/.test(line)) inFencedBlock = !inFencedBlock;
|
|
736
|
-
if (!inFencedBlock && /^#{1,2}\s/.test(line) && current.length > 0) {
|
|
737
|
-
chunks.push(current.join("\n"));
|
|
738
|
-
current = [];
|
|
739
|
-
}
|
|
740
|
-
current.push(line);
|
|
741
|
-
}
|
|
742
|
-
if (current.length > 0) chunks.push(current.join("\n"));
|
|
743
|
-
return chunks;
|
|
744
|
-
}
|
|
745
|
-
/** Split markdown by size, preferring to break outside fenced code blocks when possible */
|
|
746
|
-
function splitMarkdownBySize(markdown, maxChars) {
|
|
747
|
-
if (markdown.length <= maxChars) return [markdown];
|
|
748
|
-
const lines = markdown.split("\n");
|
|
749
|
-
const chunks = [];
|
|
750
|
-
let current = [];
|
|
751
|
-
let currentLength = 0;
|
|
752
|
-
let inFencedBlock = false;
|
|
753
|
-
for (const line of lines) {
|
|
754
|
-
if (/^(`{3,}|~{3,})/.test(line)) inFencedBlock = !inFencedBlock;
|
|
755
|
-
const lineLength = line.length + 1;
|
|
756
|
-
const wouldExceed = currentLength + lineLength > maxChars;
|
|
757
|
-
if (current.length > 0 && wouldExceed && !inFencedBlock) {
|
|
758
|
-
chunks.push(current.join("\n"));
|
|
759
|
-
current = [];
|
|
760
|
-
currentLength = 0;
|
|
761
|
-
}
|
|
762
|
-
current.push(line);
|
|
763
|
-
currentLength += lineLength;
|
|
764
|
-
}
|
|
765
|
-
if (current.length > 0) chunks.push(current.join("\n"));
|
|
766
|
-
if (chunks.length > 1) return chunks;
|
|
767
|
-
const midpoint = Math.floor(lines.length / 2);
|
|
768
|
-
if (midpoint <= 0 || midpoint >= lines.length) return [markdown];
|
|
769
|
-
return [lines.slice(0, midpoint).join("\n"), lines.slice(midpoint).join("\n")];
|
|
770
|
-
}
|
|
771
|
-
async function convertMarkdownWithFallback(client, markdown, depth = 0) {
|
|
959
|
+
async function convertMarkdownWithFallback(client, chunk, depth = 0) {
|
|
772
960
|
try {
|
|
773
|
-
return
|
|
961
|
+
return {
|
|
962
|
+
...await convertMarkdown(client, chunk.markdown),
|
|
963
|
+
images: chunk.images
|
|
964
|
+
};
|
|
774
965
|
} catch (error) {
|
|
775
|
-
if (depth >= MAX_CONVERT_RETRY_DEPTH || markdown.length < 2) throw error;
|
|
776
|
-
const
|
|
966
|
+
if (depth >= MAX_CONVERT_RETRY_DEPTH || chunk.markdown.length < 2) throw error;
|
|
967
|
+
const splitTarget = Math.max(256, Math.floor(chunk.markdown.length / 2));
|
|
968
|
+
const chunks = splitDocxMarkdownBySize(chunk.markdown, splitTarget).map(createDocxMarkdownChunk);
|
|
777
969
|
if (chunks.length <= 1) throw error;
|
|
778
970
|
const blocks = [];
|
|
779
971
|
const firstLevelBlockIds = [];
|
|
780
|
-
|
|
781
|
-
|
|
972
|
+
const images = [];
|
|
973
|
+
for (const fallbackChunk of chunks) {
|
|
974
|
+
const converted = await convertMarkdownWithFallback(client, fallbackChunk, depth + 1);
|
|
782
975
|
blocks.push(...converted.blocks);
|
|
783
976
|
firstLevelBlockIds.push(...converted.firstLevelBlockIds);
|
|
977
|
+
images.push(...converted.images);
|
|
784
978
|
}
|
|
785
979
|
return {
|
|
786
980
|
blocks,
|
|
787
|
-
firstLevelBlockIds
|
|
981
|
+
firstLevelBlockIds,
|
|
982
|
+
images
|
|
788
983
|
};
|
|
789
984
|
}
|
|
790
985
|
}
|
|
791
986
|
/** Convert markdown in chunks to avoid document.convert content size limits */
|
|
792
|
-
async function chunkedConvertMarkdown(client,
|
|
793
|
-
const chunks = splitMarkdownByHeadings(markdown);
|
|
987
|
+
async function chunkedConvertMarkdown(client, chunks) {
|
|
794
988
|
const allBlocks = [];
|
|
795
989
|
const allRootIds = [];
|
|
990
|
+
const allImages = [];
|
|
796
991
|
for (const chunk of chunks) {
|
|
797
|
-
const { blocks, firstLevelBlockIds } = await convertMarkdownWithFallback(client, chunk);
|
|
992
|
+
const { blocks, firstLevelBlockIds, images } = await convertMarkdownWithFallback(client, chunk);
|
|
798
993
|
const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
|
|
799
994
|
allBlocks.push(...orderedBlocks);
|
|
800
995
|
allRootIds.push(...rootIds);
|
|
996
|
+
allImages.push(...images);
|
|
801
997
|
}
|
|
802
998
|
return {
|
|
803
999
|
blocks: allBlocks,
|
|
804
|
-
firstLevelBlockIds: allRootIds
|
|
1000
|
+
firstLevelBlockIds: allRootIds,
|
|
1001
|
+
images: allImages
|
|
805
1002
|
};
|
|
806
1003
|
}
|
|
807
1004
|
/**
|
|
@@ -859,98 +1056,21 @@ async function uploadImageToDocx(client, blockId, imageBuffer, fileName, docToke
|
|
|
859
1056
|
if (!fileToken) throw new Error("Image upload failed: no file_token returned");
|
|
860
1057
|
return fileToken;
|
|
861
1058
|
}
|
|
862
|
-
async function
|
|
863
|
-
|
|
864
|
-
url,
|
|
865
|
-
maxBytes
|
|
866
|
-
})).buffer;
|
|
867
|
-
}
|
|
868
|
-
async function resolveUploadInput(url, filePath, maxBytes, localRoots, explicitFileName, imageInput) {
|
|
869
|
-
const inputSources = [
|
|
870
|
-
url ? "url" : null,
|
|
871
|
-
filePath ? "file_path" : null,
|
|
872
|
-
imageInput ? "image" : null
|
|
873
|
-
].filter(Boolean);
|
|
874
|
-
if (inputSources.length > 1) throw new Error(`Provide only one image source; got: ${inputSources.join(", ")}`);
|
|
875
|
-
if (imageInput?.startsWith("data:")) {
|
|
876
|
-
const commaIdx = imageInput.indexOf(",");
|
|
877
|
-
if (commaIdx === -1) throw new Error("Invalid data URI: missing comma separator.");
|
|
878
|
-
const header = imageInput.slice(0, commaIdx);
|
|
879
|
-
const data = imageInput.slice(commaIdx + 1);
|
|
880
|
-
if (!header.includes(";base64")) throw new Error("Invalid data URI: missing ';base64' marker. Expected format: data:image/png;base64,<base64data>");
|
|
881
|
-
const trimmedData = data.trim();
|
|
882
|
-
if (trimmedData.length === 0 || !/^[A-Za-z0-9+/]+=*$/.test(trimmedData)) throw new Error(`Invalid data URI: base64 payload contains characters outside the standard alphabet.`);
|
|
883
|
-
const ext = extensionForMime(header.match(/data:([^;]+)/)?.[1])?.slice(1) ?? "png";
|
|
884
|
-
const estimatedBytes = Math.ceil(trimmedData.length * 3 / 4);
|
|
885
|
-
if (estimatedBytes > maxBytes) throw new Error(`Image data URI exceeds limit: estimated ${estimatedBytes} bytes > ${maxBytes} bytes`);
|
|
886
|
-
return {
|
|
887
|
-
buffer: Buffer.from(trimmedData, "base64"),
|
|
888
|
-
fileName: explicitFileName ?? `image.${ext}`
|
|
889
|
-
};
|
|
890
|
-
}
|
|
891
|
-
if (imageInput) {
|
|
892
|
-
const candidate = imageInput.startsWith("~") ? imageInput.replace(/^~/, homedir()) : imageInput;
|
|
893
|
-
const unambiguousPath = imageInput.startsWith("~") || imageInput.startsWith("./") || imageInput.startsWith("../");
|
|
894
|
-
const absolutePath = isAbsolute(imageInput);
|
|
895
|
-
if (unambiguousPath || absolutePath && existsSync(candidate)) {
|
|
896
|
-
const resolvedPath = resolve(candidate);
|
|
897
|
-
return {
|
|
898
|
-
buffer: (await getFeishuRuntime().media.loadWebMedia(resolvedPath, {
|
|
899
|
-
maxBytes,
|
|
900
|
-
optimizeImages: false,
|
|
901
|
-
localRoots
|
|
902
|
-
})).buffer,
|
|
903
|
-
fileName: explicitFileName ?? basename(candidate)
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
if (absolutePath && !existsSync(candidate)) throw new Error(`File not found: "${candidate}". If you intended to pass image binary data, use a data URI instead: data:image/jpeg;base64,...`);
|
|
907
|
-
}
|
|
908
|
-
if (imageInput) {
|
|
909
|
-
const trimmed = imageInput.trim();
|
|
910
|
-
if (trimmed.length === 0 || !/^[A-Za-z0-9+/]+=*$/.test(trimmed)) throw new Error("Invalid base64: image input contains characters outside the standard base64 alphabet. Use a data URI (data:image/png;base64,...) or a local file path instead.");
|
|
911
|
-
const estimatedBytes = Math.ceil(trimmed.length * 3 / 4);
|
|
912
|
-
if (estimatedBytes > maxBytes) throw new Error(`Base64 image exceeds limit: estimated ${estimatedBytes} bytes > ${maxBytes} bytes`);
|
|
913
|
-
const buffer = Buffer.from(trimmed, "base64");
|
|
914
|
-
if (buffer.length === 0) throw new Error("Base64 image decoded to empty buffer; check the input.");
|
|
915
|
-
return {
|
|
916
|
-
buffer,
|
|
917
|
-
fileName: explicitFileName ?? "image.png"
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
if (!url && !filePath) throw new Error("Either url, file_path, or image (base64/data URI) must be provided");
|
|
921
|
-
if (url && filePath) throw new Error("Provide only one of url or file_path");
|
|
922
|
-
if (url) {
|
|
923
|
-
const fetched = await getFeishuRuntime().channel.media.readRemoteMediaBuffer({
|
|
924
|
-
url,
|
|
925
|
-
maxBytes
|
|
926
|
-
});
|
|
927
|
-
const guessed = new URL(url).pathname.split("/").pop() || "upload.bin";
|
|
928
|
-
return {
|
|
929
|
-
buffer: fetched.buffer,
|
|
930
|
-
fileName: explicitFileName || guessed
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
const resolvedFilePath = resolve(filePath);
|
|
934
|
-
return {
|
|
935
|
-
buffer: (await getFeishuRuntime().media.loadWebMedia(resolvedFilePath, {
|
|
936
|
-
maxBytes,
|
|
937
|
-
optimizeImages: false,
|
|
938
|
-
localRoots
|
|
939
|
-
})).buffer,
|
|
940
|
-
fileName: explicitFileName || basename(filePath)
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
async function processImages(client, docToken, markdown, insertedBlocks, maxBytes) {
|
|
944
|
-
const imageUrls = extractImageUrls(markdown);
|
|
945
|
-
if (imageUrls.length === 0) return 0;
|
|
1059
|
+
async function processImages(client, docToken, images, insertedBlocks, maxBytes, imageReadTimeoutMs) {
|
|
1060
|
+
if (images.length === 0) return 0;
|
|
946
1061
|
const imageBlocks = insertedBlocks.filter((b) => b.block_type === 27);
|
|
947
1062
|
let processed = 0;
|
|
948
|
-
for (let i = 0; i < Math.min(
|
|
949
|
-
const url =
|
|
1063
|
+
for (let i = 0; i < Math.min(images.length, imageBlocks.length); i++) {
|
|
1064
|
+
const url = images[i]?.url;
|
|
950
1065
|
const blockId = imageBlocks[i]?.block_id;
|
|
951
1066
|
if (!url || !blockId) continue;
|
|
952
1067
|
try {
|
|
953
|
-
const
|
|
1068
|
+
const upload = await resolveDocxUploadInput({
|
|
1069
|
+
url,
|
|
1070
|
+
maxBytes,
|
|
1071
|
+
remoteReadTimeoutMs: imageReadTimeoutMs
|
|
1072
|
+
});
|
|
1073
|
+
const fileToken = await uploadImageToDocx(client, blockId, upload.buffer, upload.fileName, docToken);
|
|
954
1074
|
await client.docx.documentBlock.patch({
|
|
955
1075
|
path: {
|
|
956
1076
|
document_id: docToken,
|
|
@@ -965,7 +1085,16 @@ async function processImages(client, docToken, markdown, insertedBlocks, maxByte
|
|
|
965
1085
|
}
|
|
966
1086
|
return processed;
|
|
967
1087
|
}
|
|
968
|
-
async function uploadImageBlock(client, docToken, maxBytes, localRoots, url, filePath, parentBlockId, filename, index, imageInput) {
|
|
1088
|
+
async function uploadImageBlock(client, docToken, maxBytes, imageReadTimeoutMs, localRoots, url, filePath, parentBlockId, filename, index, imageInput) {
|
|
1089
|
+
const upload = await resolveDocxUploadInput({
|
|
1090
|
+
url,
|
|
1091
|
+
filePath,
|
|
1092
|
+
image: imageInput,
|
|
1093
|
+
maxBytes,
|
|
1094
|
+
localRoots,
|
|
1095
|
+
fileName: filename,
|
|
1096
|
+
remoteReadTimeoutMs: imageReadTimeoutMs
|
|
1097
|
+
});
|
|
969
1098
|
const insertRes = await client.docx.documentBlockChildren.create({
|
|
970
1099
|
path: {
|
|
971
1100
|
document_id: docToken,
|
|
@@ -983,7 +1112,6 @@ async function uploadImageBlock(client, docToken, maxBytes, localRoots, url, fil
|
|
|
983
1112
|
if (insertRes.code !== 0) throw new Error(`Failed to create image block: ${insertRes.msg}`);
|
|
984
1113
|
const imageBlockId = insertRes.data?.children?.find((b) => b.block_type === 27)?.block_id;
|
|
985
1114
|
if (!imageBlockId) throw new Error("Failed to create image block");
|
|
986
|
-
const upload = await resolveUploadInput(url, filePath, maxBytes, localRoots, filename, imageInput);
|
|
987
1115
|
const fileToken = await uploadImageToDocx(client, imageBlockId, upload.buffer, upload.fileName, docToken);
|
|
988
1116
|
const patchRes = await client.docx.documentBlock.patch({
|
|
989
1117
|
path: {
|
|
@@ -1003,8 +1131,14 @@ async function uploadImageBlock(client, docToken, maxBytes, localRoots, url, fil
|
|
|
1003
1131
|
}
|
|
1004
1132
|
async function uploadFileBlock(client, docToken, maxBytes, localRoots, url, filePath, parentBlockId, filename) {
|
|
1005
1133
|
const blockId = parentBlockId ?? docToken;
|
|
1006
|
-
const upload = await
|
|
1007
|
-
|
|
1134
|
+
const upload = await resolveDocxUploadInput({
|
|
1135
|
+
url,
|
|
1136
|
+
filePath,
|
|
1137
|
+
maxBytes,
|
|
1138
|
+
localRoots,
|
|
1139
|
+
fileName: filename
|
|
1140
|
+
});
|
|
1141
|
+
const converted = await convertMarkdown(client, "[file](https://example.com/placeholder)");
|
|
1008
1142
|
const { orderedBlocks } = normalizeConvertedBlockTree(converted.blocks, converted.firstLevelBlockIds);
|
|
1009
1143
|
const { children: inserted } = await insertBlocks(client, docToken, orderedBlocks, blockId);
|
|
1010
1144
|
const placeholderBlock = inserted[0];
|
|
@@ -1128,10 +1262,11 @@ async function createDoc(client, title, folderToken, options) {
|
|
|
1128
1262
|
}
|
|
1129
1263
|
};
|
|
1130
1264
|
}
|
|
1131
|
-
async function writeDoc(client, docToken, markdown, maxBytes, logger) {
|
|
1132
|
-
const
|
|
1265
|
+
async function writeDoc(client, docToken, markdown, maxBytes, imageReadTimeoutMs, logger) {
|
|
1266
|
+
const markdownPlan = createDocxMarkdownPlan(markdown);
|
|
1133
1267
|
logger?.info?.("feishu_doc: Converting markdown...");
|
|
1134
|
-
const { blocks, firstLevelBlockIds } = await chunkedConvertMarkdown(client,
|
|
1268
|
+
const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
|
|
1269
|
+
const deleted = await clearDocumentContent(client, docToken);
|
|
1135
1270
|
if (blocks.length === 0) return {
|
|
1136
1271
|
success: true,
|
|
1137
1272
|
blocks_deleted: deleted,
|
|
@@ -1141,7 +1276,7 @@ async function writeDoc(client, docToken, markdown, maxBytes, logger) {
|
|
|
1141
1276
|
logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting...`);
|
|
1142
1277
|
const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
|
|
1143
1278
|
const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds);
|
|
1144
|
-
const imagesProcessed = await processImages(client, docToken,
|
|
1279
|
+
const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
|
|
1145
1280
|
logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
|
|
1146
1281
|
return {
|
|
1147
1282
|
success: true,
|
|
@@ -1150,14 +1285,15 @@ async function writeDoc(client, docToken, markdown, maxBytes, logger) {
|
|
|
1150
1285
|
images_processed: imagesProcessed
|
|
1151
1286
|
};
|
|
1152
1287
|
}
|
|
1153
|
-
async function appendDoc(client, docToken, markdown, maxBytes, logger) {
|
|
1288
|
+
async function appendDoc(client, docToken, markdown, maxBytes, imageReadTimeoutMs, logger) {
|
|
1289
|
+
const markdownPlan = createDocxMarkdownPlan(markdown);
|
|
1154
1290
|
logger?.info?.("feishu_doc: Converting markdown...");
|
|
1155
|
-
const { blocks, firstLevelBlockIds } = await chunkedConvertMarkdown(client,
|
|
1291
|
+
const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
|
|
1156
1292
|
if (blocks.length === 0) throw new Error("Content is empty");
|
|
1157
1293
|
logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting...`);
|
|
1158
1294
|
const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
|
|
1159
1295
|
const { children: inserted } = blocks.length > 1e3 ? await insertBlocksInBatches(client, docToken, orderedBlocks, rootIds, logger) : await insertBlocksWithDescendant(client, docToken, orderedBlocks, rootIds);
|
|
1160
|
-
const imagesProcessed = await processImages(client, docToken,
|
|
1296
|
+
const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
|
|
1161
1297
|
logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
|
|
1162
1298
|
return {
|
|
1163
1299
|
success: true,
|
|
@@ -1166,7 +1302,8 @@ async function appendDoc(client, docToken, markdown, maxBytes, logger) {
|
|
|
1166
1302
|
block_ids: inserted.map((b) => b.block_id)
|
|
1167
1303
|
};
|
|
1168
1304
|
}
|
|
1169
|
-
async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, logger) {
|
|
1305
|
+
async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, imageReadTimeoutMs, logger) {
|
|
1306
|
+
const markdownPlan = createDocxMarkdownPlan(markdown);
|
|
1170
1307
|
const blockInfo = await client.docx.documentBlock.get({ path: {
|
|
1171
1308
|
document_id: docToken,
|
|
1172
1309
|
block_id: afterBlockId
|
|
@@ -1191,7 +1328,7 @@ async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, log
|
|
|
1191
1328
|
if (blockIndex === -1) throw new Error(`after_block_id "${afterBlockId}" was not found among the children of parent block "${parentId}". Use list_blocks to verify the block ID.`);
|
|
1192
1329
|
const insertIndex = blockIndex + 1;
|
|
1193
1330
|
logger?.info?.("feishu_doc: Converting markdown...");
|
|
1194
|
-
const { blocks, firstLevelBlockIds } = await chunkedConvertMarkdown(client,
|
|
1331
|
+
const { blocks, firstLevelBlockIds, images } = await chunkedConvertMarkdown(client, markdownPlan.chunks);
|
|
1195
1332
|
if (blocks.length === 0) throw new Error("Content is empty");
|
|
1196
1333
|
const { orderedBlocks, rootIds } = normalizeConvertedBlockTree(blocks, firstLevelBlockIds);
|
|
1197
1334
|
logger?.info?.(`feishu_doc: Converted to ${blocks.length} blocks, inserting at index ${insertIndex}...`);
|
|
@@ -1199,7 +1336,7 @@ async function insertDoc(client, docToken, markdown, afterBlockId, maxBytes, log
|
|
|
1199
1336
|
parentBlockId: parentId,
|
|
1200
1337
|
index: insertIndex
|
|
1201
1338
|
});
|
|
1202
|
-
const imagesProcessed = await processImages(client, docToken,
|
|
1339
|
+
const imagesProcessed = await processImages(client, docToken, images, inserted, maxBytes, imageReadTimeoutMs);
|
|
1203
1340
|
logger?.info?.(`feishu_doc: Done (${blocks.length} blocks, ${imagesProcessed} images)`);
|
|
1204
1341
|
return {
|
|
1205
1342
|
success: true,
|
|
@@ -1409,6 +1546,15 @@ function registerFeishuDocTools(api) {
|
|
|
1409
1546
|
label: "Doc"
|
|
1410
1547
|
}
|
|
1411
1548
|
}).config?.mediaMaxMb ?? 30) * 1024 * 1024;
|
|
1549
|
+
const getImageReadTimeoutMs = (params, defaultAccountId) => resolveConfiguredHttpTimeoutMs(resolveFeishuToolAccount({
|
|
1550
|
+
api,
|
|
1551
|
+
executeParams: params,
|
|
1552
|
+
defaultAccountId,
|
|
1553
|
+
requiredTool: {
|
|
1554
|
+
family: "doc",
|
|
1555
|
+
label: "Doc"
|
|
1556
|
+
}
|
|
1557
|
+
}));
|
|
1412
1558
|
if (toolsCfg.doc) {
|
|
1413
1559
|
api.registerTool((ctx) => {
|
|
1414
1560
|
const defaultAccountId = ctx.agentAccountId;
|
|
@@ -1425,9 +1571,9 @@ function registerFeishuDocTools(api) {
|
|
|
1425
1571
|
const client = getClient(p, defaultAccountId);
|
|
1426
1572
|
switch (p.action) {
|
|
1427
1573
|
case "read": return jsonResult(await readDoc(client, p.doc_token));
|
|
1428
|
-
case "write": return jsonResult(await writeDoc(client, p.doc_token, p.content, getMediaMaxBytes(p, defaultAccountId), api.logger));
|
|
1429
|
-
case "append": return jsonResult(await appendDoc(client, p.doc_token, p.content, getMediaMaxBytes(p, defaultAccountId), api.logger));
|
|
1430
|
-
case "insert": return jsonResult(await insertDoc(client, p.doc_token, p.content, p.after_block_id, getMediaMaxBytes(p, defaultAccountId), api.logger));
|
|
1574
|
+
case "write": return jsonResult(await writeDoc(client, p.doc_token, p.content, getMediaMaxBytes(p, defaultAccountId), getImageReadTimeoutMs(p, defaultAccountId), api.logger));
|
|
1575
|
+
case "append": return jsonResult(await appendDoc(client, p.doc_token, p.content, getMediaMaxBytes(p, defaultAccountId), getImageReadTimeoutMs(p, defaultAccountId), api.logger));
|
|
1576
|
+
case "insert": return jsonResult(await insertDoc(client, p.doc_token, p.content, p.after_block_id, getMediaMaxBytes(p, defaultAccountId), getImageReadTimeoutMs(p, defaultAccountId), api.logger));
|
|
1431
1577
|
case "create": return jsonResult(await createDoc(client, p.title, p.folder_token, {
|
|
1432
1578
|
grantToRequester: p.grant_to_requester,
|
|
1433
1579
|
requesterOpenId: trustedRequesterOpenId
|
|
@@ -1439,7 +1585,7 @@ function registerFeishuDocTools(api) {
|
|
|
1439
1585
|
case "create_table": return jsonResult(await createTable(client, p.doc_token, p.row_size, p.column_size, p.parent_block_id, p.column_width));
|
|
1440
1586
|
case "write_table_cells": return jsonResult(await writeTableCells(client, p.doc_token, p.table_block_id, p.values));
|
|
1441
1587
|
case "create_table_with_values": return jsonResult(await createTableWithValues(client, p.doc_token, p.row_size, p.column_size, p.values, p.parent_block_id, p.column_width));
|
|
1442
|
-
case "upload_image": return jsonResult(await uploadImageBlock(client, p.doc_token, getMediaMaxBytes(p, defaultAccountId), mediaLocalRoots, p.url, p.file_path, p.parent_block_id, p.filename, p.index, p.image));
|
|
1588
|
+
case "upload_image": return jsonResult(await uploadImageBlock(client, p.doc_token, getMediaMaxBytes(p, defaultAccountId), getImageReadTimeoutMs(p, defaultAccountId), mediaLocalRoots, p.url, p.file_path, p.parent_block_id, p.filename, p.index, p.image));
|
|
1443
1589
|
case "upload_file": return jsonResult(await uploadFileBlock(client, p.doc_token, getMediaMaxBytes(p, defaultAccountId), mediaLocalRoots, p.url, p.file_path, p.parent_block_id, p.filename));
|
|
1444
1590
|
case "color_text": return jsonResult(await updateColorText(client, p.doc_token, p.block_id, p.content));
|
|
1445
1591
|
case "insert_table_row": return jsonResult(await insertTableRow(client, p.doc_token, p.block_id, p.row_index));
|