






















@@ -0,0 +1,149 @@
1+import type { AnyAgentTool } from "openclaw/plugin-sdk/plugin-entry";
2+import { Type } from "typebox";
3+4+type FileTransferToolDescriptor = Pick<
5+AnyAgentTool,
6+"label" | "name" | "description" | "parameters"
7+>;
8+9+// Stash fetched files in a non-TTL subdir so follow-up tool calls within
10+// the same turn can still reference them.
11+export const FILE_TRANSFER_SUBDIR = "file-transfer";
12+13+export const FILE_FETCH_DEFAULT_MAX_BYTES = 8 * 1024 * 1024;
14+export const FILE_FETCH_HARD_MAX_BYTES = 16 * 1024 * 1024;
15+export const DIR_LIST_DEFAULT_MAX_ENTRIES = 200;
16+export const DIR_LIST_HARD_MAX_ENTRIES = 5000;
17+export const DIR_FETCH_DEFAULT_MAX_BYTES = 8 * 1024 * 1024;
18+export const DIR_FETCH_HARD_MAX_BYTES = 16 * 1024 * 1024;
19+export const FILE_WRITE_HARD_MAX_BYTES = 16 * 1024 * 1024;
20+21+export const FileFetchToolSchema = Type.Object({
22+node: Type.String({
23+description: "Node id, name, or IP. Resolves the same way as the nodes tool.",
24+}),
25+path: Type.String({
26+description: "Absolute path to the file on the node. Canonicalized server-side.",
27+}),
28+maxBytes: Type.Optional(
29+Type.Number({
30+description: "Max bytes to fetch. Default 8 MB, hard ceiling 16 MB (single round-trip).",
31+}),
32+),
33+gatewayUrl: Type.Optional(Type.String()),
34+gatewayToken: Type.Optional(Type.String()),
35+timeoutMs: Type.Optional(Type.Number()),
36+});
37+38+export const FILE_FETCH_TOOL_DESCRIPTOR: FileTransferToolDescriptor = {
39+label: "File Fetch",
40+name: "file_fetch",
41+description:
42+"Retrieve a file from a paired node by absolute path. Returns image content blocks for image MIME types, inlines small text files (≤8 KB) as text content, and saves everything else under the gateway media store with a path you can pass to file_write or other tools. Use this for screenshots, photos, receipts, logs, source files. Pair with file_write to copy a file from one node to another (no exec/cp shell-out needed). Requires operator opt-in: gateway.nodes.allowCommands must include 'file.fetch' AND plugins.entries.file-transfer.config.nodes.<node>.allowReadPaths must match the path. Without policy configured, every call is denied.",
43+parameters: FileFetchToolSchema,
44+};
45+46+export const DirListToolSchema = Type.Object({
47+node: Type.String({
48+description: "Node id, name, or IP. Resolves the same way as the nodes tool.",
49+}),
50+path: Type.String({
51+description: "Absolute path to the directory on the node. Canonicalized server-side.",
52+}),
53+pageToken: Type.Optional(
54+Type.String({
55+description:
56+"Pagination token from a previous dir_list call. Omit to start from the beginning.",
57+}),
58+),
59+maxEntries: Type.Optional(
60+Type.Number({
61+description: `Max entries per page. Default ${DIR_LIST_DEFAULT_MAX_ENTRIES}, hard ceiling ${DIR_LIST_HARD_MAX_ENTRIES}.`,
62+}),
63+),
64+gatewayUrl: Type.Optional(Type.String()),
65+gatewayToken: Type.Optional(Type.String()),
66+timeoutMs: Type.Optional(Type.Number()),
67+});
68+69+export const DIR_LIST_TOOL_DESCRIPTOR: FileTransferToolDescriptor = {
70+label: "Directory List",
71+name: "dir_list",
72+description:
73+"Retrieve a structured directory listing from a paired node. Returns file and subdirectory metadata (name, path, size, mimeType, isDir, mtime) without transferring file content. Use this to discover what files exist before fetching them with file_fetch. Pagination is offset-based; pass nextPageToken from the previous result. Requires operator opt-in: gateway.nodes.allowCommands must include 'dir.list' AND plugins.entries.file-transfer.config.nodes.<node>.allowReadPaths must match the directory path. Without policy configured, every call is denied.",
74+parameters: DirListToolSchema,
75+};
76+77+export const DirFetchToolSchema = Type.Object({
78+node: Type.String({
79+description: "Node id, name, or IP. Resolves the same way as the nodes tool.",
80+}),
81+path: Type.String({
82+description: "Absolute path to the directory on the node to fetch. Canonicalized server-side.",
83+}),
84+maxBytes: Type.Optional(
85+Type.Number({
86+description:
87+"Max gzipped tarball bytes to fetch. Default 8 MB, hard ceiling 16 MB (single round-trip).",
88+}),
89+),
90+includeDotfiles: Type.Optional(
91+Type.Boolean({
92+description: "Reserved for v2; currently always includes dotfiles (v1 quirk in BSD tar).",
93+}),
94+),
95+gatewayUrl: Type.Optional(Type.String()),
96+gatewayToken: Type.Optional(Type.String()),
97+timeoutMs: Type.Optional(Type.Number()),
98+});
99+100+export const DIR_FETCH_TOOL_DESCRIPTOR: FileTransferToolDescriptor = {
101+label: "Directory Fetch",
102+name: "dir_fetch",
103+description:
104+"Retrieve a directory tree from a paired node as a gzipped tarball, unpack it on the gateway, and return a manifest of saved paths. Use to pull source trees, asset folders, or log directories in a single round-trip. The unpacked files live on the GATEWAY (not your local machine); pass localPath into other tools or use file_fetch on individual entries to ship them elsewhere. Rejects trees larger than 16 MB compressed. Requires operator opt-in: gateway.nodes.allowCommands must include 'dir.fetch' AND plugins.entries.file-transfer.config.nodes.<node>.allowReadPaths must match the directory path.",
105+parameters: DirFetchToolSchema,
106+};
107+108+export const FileWriteToolSchema = Type.Object({
109+node: Type.String({ description: "Node id or display name to write the file on." }),
110+path: Type.String({
111+description: "Absolute path on the node to write. Canonicalized server-side.",
112+}),
113+contentBase64: Type.Optional(
114+Type.String({
115+description: "Base64-encoded bytes to write. Maximum 16 MB after decode.",
116+}),
117+),
118+sourceMediaId: Type.Optional(
119+Type.String({
120+description:
121+"Media id returned by file_fetch. Preferred for binary copies because bytes stay in the gateway media store.",
122+}),
123+),
124+mimeType: Type.Optional(
125+Type.String({
126+description: "Content type hint. Not validated against the content.",
127+}),
128+),
129+overwrite: Type.Optional(
130+Type.Boolean({
131+description: "Allow overwriting an existing file. Default false.",
132+default: false,
133+}),
134+),
135+createParents: Type.Optional(
136+Type.Boolean({
137+description: "Create missing parent directories (mkdir -p). Default false.",
138+default: false,
139+}),
140+),
141+});
142+143+export const FILE_WRITE_TOOL_DESCRIPTOR: FileTransferToolDescriptor = {
144+label: "File Write",
145+name: "file_write",
146+description:
147+"Write file bytes to a paired node by absolute path. Atomic write (temp + rename). Refuses to overwrite by default — pass overwrite=true to replace. Refuses to write through symlink targets unless policy explicitly allows following symlinks. Pair with file_fetch by passing its mediaId as sourceMediaId for binary copy. Requires operator opt-in: gateway.nodes.allowCommands must include 'file.write' AND plugins.entries.file-transfer.config.nodes.<node>.allowWritePaths must match the destination path. Without policy configured, every call is denied.",
148+parameters: FileWriteToolSchema,
149+};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。