Skip to content

Commit 56fa058

Browse files
xuhao1Takhoffman
andauthored
feat(feishu): support Docx table create/write + image/file upload actions in feishu_doc (#20304)
Co-authored-by: Tak Hoffman <[email protected]>
1 parent 1725839 commit 56fa058

File tree

5 files changed

+726
-9
lines changed

5 files changed

+726
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
1111
- Android/Nodes: add `camera.list`, `device.permissions`, `device.health`, and `notifications.actions` (`open`/`dismiss`/`reply`) on Android nodes, plus first-class node-tool actions for the new device/notification commands. (#28260) Thanks @obviyus.
1212
- Android/Gateway capability refresh: add live Android capability integration coverage and node canvas capability refresh wiring, plus runtime hardening for A2UI readiness retries, scoped canvas URL normalization, debug diagnostics JSON, and JavaScript MIME delivery. (#28388) Thanks @obviyus.
1313
- Feishu/Doc permissions: support optional owner permission grant fields on `feishu_doc` create and report permission metadata only when the grant call succeeds, with regression coverage for success/failure/omitted-owner paths. (#28295) Thanks @zhoulongchao77.
14+
- Feishu/Docx tables + uploads: add `feishu_doc` actions for Docx table creation/cell writing (`create_table`, `write_table_cells`, `create_table_with_values`) and image/file uploads (`upload_image`, `upload_file`) with stricter create/upload error handling for missing `document_id` and placeholder cleanup failures. (#20304) Thanks @xuhao1.
1415

1516
### Fixes
1617

extensions/feishu/skills/feishu-doc/SKILL.md

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: |
66

77
# Feishu Document Tool
88

9-
Single tool `feishu_doc` with action parameter for all document operations.
9+
Single tool `feishu_doc` with action parameter for all document operations, including table creation for Docx.
1010

1111
## Token Extraction
1212

@@ -43,15 +43,22 @@ Appends markdown to end of document.
4343
### Create Document
4444

4545
```json
46-
{ "action": "create", "title": "New Document" }
46+
{ "action": "create", "title": "New Document", "owner_open_id": "ou_xxx" }
4747
```
4848

4949
With folder:
5050

5151
```json
52-
{ "action": "create", "title": "New Document", "folder_token": "fldcnXXX" }
52+
{
53+
"action": "create",
54+
"title": "New Document",
55+
"folder_token": "fldcnXXX",
56+
"owner_open_id": "ou_xxx"
57+
}
5358
```
5459

60+
**Important:** Always pass `owner_open_id` with the requesting user's `open_id` (from inbound metadata `sender_id`) so the user automatically gets `full_access` permission on the created document. Without this, only the bot app has access.
61+
5562
### List Blocks
5663

5764
```json
@@ -83,6 +90,105 @@ Returns full block data including tables, images. Use this to read structured co
8390
{ "action": "delete_block", "doc_token": "ABC123def", "block_id": "doxcnXXX" }
8491
```
8592

93+
### Create Table (Docx Table Block)
94+
95+
```json
96+
{
97+
"action": "create_table",
98+
"doc_token": "ABC123def",
99+
"row_size": 2,
100+
"column_size": 2,
101+
"column_width": [200, 200]
102+
}
103+
```
104+
105+
Optional: `parent_block_id` to insert under a specific block.
106+
107+
### Write Table Cells
108+
109+
```json
110+
{
111+
"action": "write_table_cells",
112+
"doc_token": "ABC123def",
113+
"table_block_id": "doxcnTABLE",
114+
"values": [
115+
["A1", "B1"],
116+
["A2", "B2"]
117+
]
118+
}
119+
```
120+
121+
### Create Table With Values (One-step)
122+
123+
```json
124+
{
125+
"action": "create_table_with_values",
126+
"doc_token": "ABC123def",
127+
"row_size": 2,
128+
"column_size": 2,
129+
"column_width": [200, 200],
130+
"values": [
131+
["A1", "B1"],
132+
["A2", "B2"]
133+
]
134+
}
135+
```
136+
137+
Optional: `parent_block_id` to insert under a specific block.
138+
139+
### Upload Image to Docx (from URL or local file)
140+
141+
```json
142+
{
143+
"action": "upload_image",
144+
"doc_token": "ABC123def",
145+
"url": "https://example.com/image.png"
146+
}
147+
```
148+
149+
Or local path with position control:
150+
151+
```json
152+
{
153+
"action": "upload_image",
154+
"doc_token": "ABC123def",
155+
"file_path": "/tmp/image.png",
156+
"parent_block_id": "doxcnParent",
157+
"index": 5
158+
}
159+
```
160+
161+
Optional `index` (0-based) inserts the image at a specific position among sibling blocks. Omit to append at end.
162+
163+
**Note:** Image display size is determined by the uploaded image's pixel dimensions. For small images (e.g. 480x270 GIFs), scale to 800px+ width before uploading to ensure proper display.
164+
165+
### Upload File Attachment to Docx (from URL or local file)
166+
167+
```json
168+
{
169+
"action": "upload_file",
170+
"doc_token": "ABC123def",
171+
"url": "https://example.com/report.pdf"
172+
}
173+
```
174+
175+
Or local path:
176+
177+
```json
178+
{
179+
"action": "upload_file",
180+
"doc_token": "ABC123def",
181+
"file_path": "/tmp/report.pdf",
182+
"filename": "Q1-report.pdf"
183+
}
184+
```
185+
186+
Rules:
187+
188+
- exactly one of `url` / `file_path`
189+
- optional `filename` override
190+
- optional `parent_block_id`
191+
86192
## Reading Workflow
87193

88194
1. Start with `action: "read"` - get plain text + statistics

extensions/feishu/src/doc-schema.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,73 @@ export const FeishuDocSchema = Type.Union([
5050
doc_token: Type.String({ description: "Document token" }),
5151
block_id: Type.String({ description: "Block ID" }),
5252
}),
53+
Type.Object({
54+
action: Type.Literal("create_table"),
55+
doc_token: Type.String({ description: "Document token" }),
56+
parent_block_id: Type.Optional(
57+
Type.String({ description: "Parent block ID (default: document root)" }),
58+
),
59+
row_size: Type.Integer({ description: "Table row count", minimum: 1 }),
60+
column_size: Type.Integer({ description: "Table column count", minimum: 1 }),
61+
column_width: Type.Optional(
62+
Type.Array(Type.Number({ minimum: 1 }), {
63+
description: "Column widths in px (length should match column_size)",
64+
}),
65+
),
66+
}),
67+
Type.Object({
68+
action: Type.Literal("write_table_cells"),
69+
doc_token: Type.String({ description: "Document token" }),
70+
table_block_id: Type.String({ description: "Table block ID" }),
71+
values: Type.Array(Type.Array(Type.String()), {
72+
description: "2D matrix values[row][col] to write into table cells",
73+
minItems: 1,
74+
}),
75+
}),
76+
Type.Object({
77+
action: Type.Literal("create_table_with_values"),
78+
doc_token: Type.String({ description: "Document token" }),
79+
parent_block_id: Type.Optional(
80+
Type.String({ description: "Parent block ID (default: document root)" }),
81+
),
82+
row_size: Type.Integer({ description: "Table row count", minimum: 1 }),
83+
column_size: Type.Integer({ description: "Table column count", minimum: 1 }),
84+
column_width: Type.Optional(
85+
Type.Array(Type.Number({ minimum: 1 }), {
86+
description: "Column widths in px (length should match column_size)",
87+
}),
88+
),
89+
values: Type.Array(Type.Array(Type.String()), {
90+
description: "2D matrix values[row][col] to write into table cells",
91+
minItems: 1,
92+
}),
93+
}),
94+
Type.Object({
95+
action: Type.Literal("upload_image"),
96+
doc_token: Type.String({ description: "Document token" }),
97+
url: Type.Optional(Type.String({ description: "Remote image URL (http/https)" })),
98+
file_path: Type.Optional(Type.String({ description: "Local image file path" })),
99+
parent_block_id: Type.Optional(
100+
Type.String({ description: "Parent block ID (default: document root)" }),
101+
),
102+
filename: Type.Optional(Type.String({ description: "Optional filename override" })),
103+
index: Type.Optional(
104+
Type.Integer({
105+
minimum: 0,
106+
description: "Insert position (0-based index among siblings). Omit to append.",
107+
}),
108+
),
109+
}),
110+
Type.Object({
111+
action: Type.Literal("upload_file"),
112+
doc_token: Type.String({ description: "Document token" }),
113+
url: Type.Optional(Type.String({ description: "Remote file URL (http/https)" })),
114+
file_path: Type.Optional(Type.String({ description: "Local file path" })),
115+
parent_block_id: Type.Optional(
116+
Type.String({ description: "Parent block ID (default: document root)" }),
117+
),
118+
filename: Type.Optional(Type.String({ description: "Optional filename override" })),
119+
}),
53120
]);
54121

55122
export type FeishuDocParams = Static<typeof FeishuDocSchema>;

0 commit comments

Comments
 (0)