@llmindset/hf-mcp 0.3.5 → 0.3.10
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/gradio-files.d.ts +21 -13
- package/dist/gradio-files.d.ts.map +1 -1
- package/dist/gradio-files.js +45 -29
- package/dist/gradio-files.js.map +1 -1
- package/dist/hub-inspect.d.ts +2 -2
- package/dist/jobs/types.d.ts +8 -8
- package/dist/repo-search.d.ts +2 -2
- package/package.json +2 -2
- package/src/gradio-files.ts +71 -42
- package/test/list-files.spec.ts +120 -0
package/dist/gradio-files.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export type FileTypeFilter = 'all' | 'image' | 'audio' | 'text';
|
|
3
|
+
export type FileListingSource = {
|
|
4
|
+
kind: 'bucket';
|
|
5
|
+
id: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'dataset';
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
2
10
|
interface FileWithUrl {
|
|
3
11
|
path: string;
|
|
4
12
|
size: number;
|
|
@@ -7,10 +15,11 @@ interface FileWithUrl {
|
|
|
7
15
|
sizeFormatted: string;
|
|
8
16
|
lastModified?: string;
|
|
9
17
|
lfs: boolean;
|
|
18
|
+
source: FileListingSource['kind'];
|
|
10
19
|
}
|
|
11
|
-
export declare const
|
|
20
|
+
export declare const LIST_FILES_TOOL_CONFIG: {
|
|
12
21
|
readonly name: "gradio_files";
|
|
13
|
-
readonly description: "List available
|
|
22
|
+
readonly description: "List files available to use as Gradio File/Image/Audio inputs. Prefer these URLs when a Space asks for a file input and the user has not provided an explicit URL.";
|
|
14
23
|
readonly schema: z.ZodObject<{
|
|
15
24
|
fileType: z.ZodDefault<z.ZodOptional<z.ZodEnum<["all", "image", "audio", "text"]>>>;
|
|
16
25
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -19,25 +28,24 @@ export declare const GRADIO_FILES_TOOL_CONFIG: {
|
|
|
19
28
|
fileType?: "all" | "image" | "audio" | "text" | undefined;
|
|
20
29
|
}>;
|
|
21
30
|
readonly annotations: {
|
|
22
|
-
readonly title: "
|
|
31
|
+
readonly title: "Available Input Files";
|
|
23
32
|
readonly destructiveHint: false;
|
|
24
33
|
readonly readOnlyHint: true;
|
|
25
34
|
readonly openWorldHint: true;
|
|
26
35
|
};
|
|
27
36
|
};
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
description: string;
|
|
31
|
-
schema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
|
|
32
|
-
};
|
|
33
|
-
export type GradioFilesParams = z.infer<typeof GRADIO_FILES_TOOL_CONFIG.schema>;
|
|
34
|
-
export declare class GradioFilesTool {
|
|
37
|
+
export type ListFilesParams = z.infer<typeof LIST_FILES_TOOL_CONFIG.schema>;
|
|
38
|
+
export declare class ListFilesTool {
|
|
35
39
|
private readonly accessToken;
|
|
36
|
-
private readonly
|
|
40
|
+
private readonly source;
|
|
41
|
+
constructor(hfToken: string, source: FileListingSource);
|
|
42
|
+
getFiles(): Promise<FileWithUrl[]>;
|
|
43
|
+
private constructFileUrl;
|
|
44
|
+
generateDetailedMarkdown(fileType?: FileTypeFilter): Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
export declare class GradioFilesTool extends ListFilesTool {
|
|
37
47
|
constructor(hfToken: string, username: string);
|
|
38
48
|
getGradioFiles(): Promise<FileWithUrl[]>;
|
|
39
|
-
private constructFileUrl;
|
|
40
|
-
generateDetailedMarkdown(fileType?: 'all' | 'image' | 'audio' | 'text'): Promise<string>;
|
|
41
49
|
}
|
|
42
50
|
export {};
|
|
43
51
|
//# sourceMappingURL=gradio-files.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gradio-files.d.ts","sourceRoot":"","sources":["../src/gradio-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"gradio-files.d.ts","sourceRoot":"","sources":["../src/gradio-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAC1B;IACA,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACV,GACD;IACA,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACV,CAAC;AAEL,UAAU,WAAW;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;CAClC;AAiFD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;CAazB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAK5E,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;gBAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB;IAQhD,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAyCxC,OAAO,CAAC,gBAAgB;IAWlB,wBAAwB,CAAC,QAAQ,GAAE,cAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;CAyCjF;AAKD,qBAAa,eAAgB,SAAQ,aAAa;gBACrC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAIvC,cAAc,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CAG9C"}
|
package/dist/gradio-files.js
CHANGED
|
@@ -34,11 +34,11 @@ const AUDIO_EXTENSIONS = new Set([
|
|
|
34
34
|
const TEXT_EXTENSIONS = new Set([
|
|
35
35
|
'.txt',
|
|
36
36
|
'.md',
|
|
37
|
-
'json',
|
|
38
|
-
'xml',
|
|
37
|
+
'.json',
|
|
38
|
+
'.xml',
|
|
39
39
|
'.csv',
|
|
40
40
|
'.tsv',
|
|
41
|
-
'yaml',
|
|
41
|
+
'.yaml',
|
|
42
42
|
'.yml',
|
|
43
43
|
'.html',
|
|
44
44
|
'.css',
|
|
@@ -72,39 +72,35 @@ function matchesFileType(file, fileType) {
|
|
|
72
72
|
return true;
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
const FILE_TYPE_SCHEMA = z.enum(['all', 'image', 'audio', 'text']).optional().default('all').describe('Filter by type');
|
|
76
|
+
export const LIST_FILES_TOOL_CONFIG = {
|
|
76
77
|
name: 'gradio_files',
|
|
77
|
-
description: 'List available
|
|
78
|
+
description: 'List files available to use as Gradio File/Image/Audio inputs. Prefer these URLs when a Space asks for a file input and the user has not provided an explicit URL.',
|
|
78
79
|
schema: z.object({
|
|
79
|
-
fileType:
|
|
80
|
+
fileType: FILE_TYPE_SCHEMA,
|
|
80
81
|
}),
|
|
81
82
|
annotations: {
|
|
82
|
-
title: '
|
|
83
|
+
title: 'Available Input Files',
|
|
83
84
|
destructiveHint: false,
|
|
84
85
|
readOnlyHint: true,
|
|
85
86
|
openWorldHint: true,
|
|
86
87
|
},
|
|
87
88
|
};
|
|
88
|
-
export
|
|
89
|
-
name: 'Available Gradio Input Files',
|
|
90
|
-
description: 'Returns a list of files and their URLs to use as Gradio File Inputs.',
|
|
91
|
-
schema: z.object({}),
|
|
92
|
-
};
|
|
93
|
-
export class GradioFilesTool {
|
|
89
|
+
export class ListFilesTool {
|
|
94
90
|
accessToken;
|
|
95
|
-
|
|
96
|
-
constructor(hfToken,
|
|
91
|
+
source;
|
|
92
|
+
constructor(hfToken, source) {
|
|
97
93
|
this.accessToken = hfToken;
|
|
98
|
-
this.
|
|
94
|
+
this.source = source;
|
|
99
95
|
}
|
|
100
|
-
async
|
|
96
|
+
async getFiles() {
|
|
101
97
|
try {
|
|
102
98
|
const files = [];
|
|
103
99
|
for await (const file of listFiles({
|
|
104
|
-
repo: { type:
|
|
105
|
-
recursive:
|
|
100
|
+
repo: { type: this.source.kind, name: this.source.id },
|
|
101
|
+
recursive: this.source.kind === 'bucket',
|
|
106
102
|
expand: true,
|
|
107
|
-
|
|
103
|
+
accessToken: this.accessToken,
|
|
108
104
|
})) {
|
|
109
105
|
if (file.type === 'file') {
|
|
110
106
|
const fileName = file.path.split('/').pop() || file.path;
|
|
@@ -117,8 +113,9 @@ export class GradioFilesTool {
|
|
|
117
113
|
type: file.type,
|
|
118
114
|
url: this.constructFileUrl(file.path),
|
|
119
115
|
sizeFormatted: formatBytes(file.size),
|
|
120
|
-
lastModified: file.lastCommit?.date,
|
|
116
|
+
lastModified: this.source.kind === 'bucket' ? file.uploadedAt : file.lastCommit?.date,
|
|
121
117
|
lfs: !!file.lfs,
|
|
118
|
+
source: this.source.kind,
|
|
122
119
|
});
|
|
123
120
|
}
|
|
124
121
|
}
|
|
@@ -126,20 +123,31 @@ export class GradioFilesTool {
|
|
|
126
123
|
}
|
|
127
124
|
catch (error) {
|
|
128
125
|
if (error instanceof HfApiError) {
|
|
129
|
-
throw explain(error, `Failed to list files for
|
|
126
|
+
throw explain(error, `Failed to list files for ${this.source.kind} "${this.source.id}"`);
|
|
130
127
|
}
|
|
131
128
|
throw error;
|
|
132
129
|
}
|
|
133
130
|
}
|
|
134
131
|
constructFileUrl(filePath) {
|
|
135
|
-
|
|
132
|
+
if (this.source.kind === 'bucket') {
|
|
133
|
+
const encodedPath = filePath.split('/').map(encodeURIComponent).join('/');
|
|
134
|
+
return `https://huggingface.co/buckets/${this.source.id}/resolve/${encodedPath}`;
|
|
135
|
+
}
|
|
136
|
+
return `https://huggingface.co/datasets/${this.source.id}/resolve/main/${filePath}`;
|
|
136
137
|
}
|
|
137
138
|
async generateDetailedMarkdown(fileType = 'all') {
|
|
138
|
-
const allFiles = await this.
|
|
139
|
+
const allFiles = await this.getFiles();
|
|
139
140
|
const files = allFiles.filter((file) => matchesFileType(file, fileType));
|
|
140
|
-
|
|
141
|
+
const sourceLabel = this.source.kind === 'bucket' ? 'Hugging Face Bucket' : 'Hugging Face Dataset fallback';
|
|
142
|
+
let markdown = `# Available files in ${this.source.kind}: ${this.source.id}\n\n`;
|
|
143
|
+
markdown += `**Source:** ${sourceLabel}\n`;
|
|
144
|
+
markdown += '**Use:** URLs below can be used as Gradio file inputs when accessible to the target Space.\n\n';
|
|
145
|
+
if (this.source.kind === 'bucket') {
|
|
146
|
+
markdown +=
|
|
147
|
+
'Note: private bucket URLs require authorization. A remote Gradio Space can only fetch these URLs directly if it has access; public buckets are safest for cross-Space file inputs.\n\n';
|
|
148
|
+
}
|
|
141
149
|
if (fileType !== 'all') {
|
|
142
|
-
markdown += `**Filter**: ${fileType} files only\n`;
|
|
150
|
+
markdown += `**Filter**: ${fileType} files only\n\n`;
|
|
143
151
|
}
|
|
144
152
|
if (files.length === 0) {
|
|
145
153
|
if (fileType !== 'all') {
|
|
@@ -151,15 +159,23 @@ export class GradioFilesTool {
|
|
|
151
159
|
return markdown;
|
|
152
160
|
}
|
|
153
161
|
markdown += `## All Files\n\n`;
|
|
154
|
-
markdown += `| Name | Size | Type | Last Modified |
|
|
155
|
-
markdown +=
|
|
162
|
+
markdown += `| Name | Path | Size | Type | Last Modified | URL |\n`;
|
|
163
|
+
markdown += `|------|------|------|------|---------------|-----|\n`;
|
|
156
164
|
for (const file of files) {
|
|
157
165
|
const fileName = file.path.split('/').pop() || file.path;
|
|
158
166
|
const icon = getFileIcon(fileName);
|
|
159
167
|
const lastMod = file.lastModified ? new Date(file.lastModified).toLocaleDateString() : '-';
|
|
160
|
-
markdown += `| ${escapeMarkdown(fileName)} | ${file.sizeFormatted} | ${icon} ${file.type} | ${lastMod} | ${file.url} |\n`;
|
|
168
|
+
markdown += `| ${escapeMarkdown(fileName)} | ${escapeMarkdown(file.path)} | ${file.sizeFormatted} | ${icon} ${file.type} | ${lastMod} | ${file.url} |\n`;
|
|
161
169
|
}
|
|
162
170
|
return markdown;
|
|
163
171
|
}
|
|
164
172
|
}
|
|
173
|
+
export class GradioFilesTool extends ListFilesTool {
|
|
174
|
+
constructor(hfToken, username) {
|
|
175
|
+
super(hfToken, { kind: 'dataset', id: `${username}/gradio-files` });
|
|
176
|
+
}
|
|
177
|
+
async getGradioFiles() {
|
|
178
|
+
return this.getFiles();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
165
181
|
//# sourceMappingURL=gradio-files.js.map
|
package/dist/gradio-files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gradio-files.js","sourceRoot":"","sources":["../src/gradio-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"gradio-files.js","sourceRoot":"","sources":["../src/gradio-files.ts"],"names":[],"mappings":"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"}
|
package/dist/hub-inspect.d.ts
CHANGED
|
@@ -10,10 +10,10 @@ export declare const HUB_REPO_DETAILS_TOOL_CONFIG: {
|
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
repo_ids: string[];
|
|
12
12
|
include_readme: boolean;
|
|
13
|
-
repo_type?: "
|
|
13
|
+
repo_type?: "dataset" | "space" | "model" | undefined;
|
|
14
14
|
}, {
|
|
15
15
|
repo_ids: string[];
|
|
16
|
-
repo_type?: "
|
|
16
|
+
repo_type?: "dataset" | "space" | "model" | undefined;
|
|
17
17
|
include_readme?: boolean | undefined;
|
|
18
18
|
}>;
|
|
19
19
|
readonly annotations: {
|
package/dist/jobs/types.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export declare const runArgsSchema: z.ZodObject<{
|
|
|
75
75
|
}, "strip", z.ZodTypeAny, {
|
|
76
76
|
image: string;
|
|
77
77
|
command: string | string[];
|
|
78
|
-
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
78
|
+
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8";
|
|
79
79
|
timeout: string;
|
|
80
80
|
detach: boolean;
|
|
81
81
|
namespace?: string | undefined;
|
|
@@ -85,7 +85,7 @@ export declare const runArgsSchema: z.ZodObject<{
|
|
|
85
85
|
command: string | string[];
|
|
86
86
|
image?: string | undefined;
|
|
87
87
|
namespace?: string | undefined;
|
|
88
|
-
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
88
|
+
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8" | undefined;
|
|
89
89
|
env?: Record<string, string> | undefined;
|
|
90
90
|
secrets?: Record<string, string> | undefined;
|
|
91
91
|
timeout?: string | undefined;
|
|
@@ -105,7 +105,7 @@ export declare const uvArgsSchema: z.ZodObject<{
|
|
|
105
105
|
detach: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
106
106
|
}, "strip", z.ZodTypeAny, {
|
|
107
107
|
script: string;
|
|
108
|
-
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
108
|
+
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8";
|
|
109
109
|
timeout: string;
|
|
110
110
|
detach: boolean;
|
|
111
111
|
namespace?: string | undefined;
|
|
@@ -117,7 +117,7 @@ export declare const uvArgsSchema: z.ZodObject<{
|
|
|
117
117
|
}, {
|
|
118
118
|
script: string;
|
|
119
119
|
namespace?: string | undefined;
|
|
120
|
-
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
120
|
+
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8" | undefined;
|
|
121
121
|
env?: Record<string, string> | undefined;
|
|
122
122
|
secrets?: Record<string, string> | undefined;
|
|
123
123
|
timeout?: string | undefined;
|
|
@@ -192,7 +192,7 @@ export declare const scheduledRunArgsSchema: z.ZodObject<{
|
|
|
192
192
|
}, "strip", z.ZodTypeAny, {
|
|
193
193
|
image: string;
|
|
194
194
|
command: string | string[];
|
|
195
|
-
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
195
|
+
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8";
|
|
196
196
|
timeout: string;
|
|
197
197
|
detach: boolean;
|
|
198
198
|
schedule: string;
|
|
@@ -205,7 +205,7 @@ export declare const scheduledRunArgsSchema: z.ZodObject<{
|
|
|
205
205
|
schedule: string;
|
|
206
206
|
image?: string | undefined;
|
|
207
207
|
namespace?: string | undefined;
|
|
208
|
-
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
208
|
+
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8" | undefined;
|
|
209
209
|
env?: Record<string, string> | undefined;
|
|
210
210
|
secrets?: Record<string, string> | undefined;
|
|
211
211
|
timeout?: string | undefined;
|
|
@@ -229,7 +229,7 @@ export declare const scheduledUvArgsSchema: z.ZodObject<{
|
|
|
229
229
|
suspend: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
230
230
|
}, "strip", z.ZodTypeAny, {
|
|
231
231
|
script: string;
|
|
232
|
-
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
232
|
+
flavor: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8";
|
|
233
233
|
timeout: string;
|
|
234
234
|
detach: boolean;
|
|
235
235
|
schedule: string;
|
|
@@ -244,7 +244,7 @@ export declare const scheduledUvArgsSchema: z.ZodObject<{
|
|
|
244
244
|
script: string;
|
|
245
245
|
schedule: string;
|
|
246
246
|
namespace?: string | undefined;
|
|
247
|
-
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "
|
|
247
|
+
flavor?: "cpu-basic" | "zero-a10g" | "cpu-upgrade" | "cpu-performance" | "cpu-xl" | "sprx8" | "inf2x6" | "t4-small" | "t4-medium" | "l4x1" | "l4x4" | "l40sx1" | "l40sx4" | "l40sx8" | "a10g-small" | "a10g-large" | "a10g-largex2" | "a10g-largex4" | "a100-large" | "h100" | "h100x8" | undefined;
|
|
248
248
|
env?: Record<string, string> | undefined;
|
|
249
249
|
secrets?: Record<string, string> | undefined;
|
|
250
250
|
timeout?: string | undefined;
|
package/dist/repo-search.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const REPO_SEARCH_TOOL_CONFIG: {
|
|
|
15
15
|
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
16
16
|
}, "strip", z.ZodTypeAny, {
|
|
17
17
|
limit: number;
|
|
18
|
-
repo_types: ("
|
|
18
|
+
repo_types: ("dataset" | "space" | "model")[];
|
|
19
19
|
sort?: "createdAt" | "downloads" | "lastModified" | "likes" | "trendingScore" | undefined;
|
|
20
20
|
author?: string | undefined;
|
|
21
21
|
query?: string | undefined;
|
|
@@ -25,7 +25,7 @@ export declare const REPO_SEARCH_TOOL_CONFIG: {
|
|
|
25
25
|
author?: string | undefined;
|
|
26
26
|
query?: string | undefined;
|
|
27
27
|
limit?: number | undefined;
|
|
28
|
-
repo_types?: ("
|
|
28
|
+
repo_types?: ("dataset" | "space" | "model")[] | undefined;
|
|
29
29
|
filters?: string[] | undefined;
|
|
30
30
|
}>;
|
|
31
31
|
readonly annotations: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmindset/hf-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@huggingface/hub": "^2.
|
|
31
|
+
"@huggingface/hub": "^2.11.0",
|
|
32
32
|
"@mcp-ui/server": "^5.12.0",
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
34
34
|
"shell-quote": "^1.8.3",
|
package/src/gradio-files.ts
CHANGED
|
@@ -5,7 +5,18 @@ import { HfApiError } from './hf-api-call.js';
|
|
|
5
5
|
import { explain } from './error-messages.js';
|
|
6
6
|
import { getFileIcon } from './file-icons.js';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
export type FileTypeFilter = 'all' | 'image' | 'audio' | 'text';
|
|
9
|
+
|
|
10
|
+
export type FileListingSource =
|
|
11
|
+
| {
|
|
12
|
+
kind: 'bucket';
|
|
13
|
+
id: string;
|
|
14
|
+
}
|
|
15
|
+
| {
|
|
16
|
+
kind: 'dataset';
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
9
20
|
interface FileWithUrl {
|
|
10
21
|
path: string;
|
|
11
22
|
size: number;
|
|
@@ -14,6 +25,7 @@ interface FileWithUrl {
|
|
|
14
25
|
sizeFormatted: string;
|
|
15
26
|
lastModified?: string;
|
|
16
27
|
lfs: boolean;
|
|
28
|
+
source: FileListingSource['kind'];
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
// File type detection helpers
|
|
@@ -49,11 +61,11 @@ const AUDIO_EXTENSIONS = new Set([
|
|
|
49
61
|
const TEXT_EXTENSIONS = new Set([
|
|
50
62
|
'.txt',
|
|
51
63
|
'.md',
|
|
52
|
-
'json',
|
|
53
|
-
'xml',
|
|
64
|
+
'.json',
|
|
65
|
+
'.xml',
|
|
54
66
|
'.csv',
|
|
55
67
|
'.tsv',
|
|
56
|
-
'yaml',
|
|
68
|
+
'.yaml',
|
|
57
69
|
'.yml',
|
|
58
70
|
'.html',
|
|
59
71
|
'.css',
|
|
@@ -78,7 +90,7 @@ function isTextFile(path: string): boolean {
|
|
|
78
90
|
return TEXT_EXTENSIONS.has(getFileExtension(path));
|
|
79
91
|
}
|
|
80
92
|
|
|
81
|
-
function matchesFileType(file: FileWithUrl, fileType:
|
|
93
|
+
function matchesFileType(file: FileWithUrl, fileType: FileTypeFilter): boolean {
|
|
82
94
|
switch (fileType) {
|
|
83
95
|
case 'all':
|
|
84
96
|
return true;
|
|
@@ -93,59 +105,51 @@ function matchesFileType(file: FileWithUrl, fileType: 'all' | 'image' | 'audio'
|
|
|
93
105
|
}
|
|
94
106
|
}
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
const FILE_TYPE_SCHEMA = z.enum(['all', 'image', 'audio', 'text']).optional().default('all').describe('Filter by type');
|
|
109
|
+
|
|
110
|
+
export const LIST_FILES_TOOL_CONFIG = {
|
|
98
111
|
name: 'gradio_files',
|
|
99
112
|
description:
|
|
100
|
-
'List available
|
|
113
|
+
'List files available to use as Gradio File/Image/Audio inputs. Prefer these URLs when a Space asks for a file input and the user has not provided an explicit URL.',
|
|
101
114
|
schema: z.object({
|
|
102
|
-
fileType:
|
|
115
|
+
fileType: FILE_TYPE_SCHEMA,
|
|
103
116
|
}),
|
|
104
117
|
annotations: {
|
|
105
|
-
title: '
|
|
118
|
+
title: 'Available Input Files',
|
|
106
119
|
destructiveHint: false,
|
|
107
120
|
readOnlyHint: true,
|
|
108
121
|
openWorldHint: true,
|
|
109
122
|
},
|
|
110
123
|
} as const;
|
|
111
124
|
|
|
112
|
-
export
|
|
113
|
-
name: 'Available Gradio Input Files',
|
|
114
|
-
description: 'Returns a list of files and their URLs to use as Gradio File Inputs.',
|
|
115
|
-
schema: z.object({}),
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// Define parameter types
|
|
119
|
-
export type GradioFilesParams = z.infer<typeof GRADIO_FILES_TOOL_CONFIG.schema>;
|
|
125
|
+
export type ListFilesParams = z.infer<typeof LIST_FILES_TOOL_CONFIG.schema>;
|
|
120
126
|
|
|
121
127
|
/**
|
|
122
|
-
* Service for listing files
|
|
128
|
+
* Service for listing files from a Hugging Face Bucket or the legacy gradio-files dataset.
|
|
123
129
|
*/
|
|
124
|
-
export class
|
|
130
|
+
export class ListFilesTool {
|
|
125
131
|
private readonly accessToken: string;
|
|
126
|
-
private readonly
|
|
132
|
+
private readonly source: FileListingSource;
|
|
127
133
|
|
|
128
|
-
constructor(hfToken: string,
|
|
134
|
+
constructor(hfToken: string, source: FileListingSource) {
|
|
129
135
|
this.accessToken = hfToken;
|
|
130
|
-
this.
|
|
136
|
+
this.source = source;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
/**
|
|
134
|
-
* Get all files
|
|
140
|
+
* Get all files with stable Hub URLs.
|
|
135
141
|
*/
|
|
136
|
-
async
|
|
142
|
+
async getFiles(): Promise<FileWithUrl[]> {
|
|
137
143
|
try {
|
|
138
144
|
const files: FileWithUrl[] = [];
|
|
139
145
|
|
|
140
|
-
// List all files recursively
|
|
141
146
|
for await (const file of listFiles({
|
|
142
|
-
repo: { type:
|
|
143
|
-
recursive:
|
|
144
|
-
expand: true,
|
|
145
|
-
|
|
147
|
+
repo: { type: this.source.kind, name: this.source.id },
|
|
148
|
+
recursive: this.source.kind === 'bucket',
|
|
149
|
+
expand: true,
|
|
150
|
+
accessToken: this.accessToken,
|
|
146
151
|
})) {
|
|
147
152
|
if (file.type === 'file') {
|
|
148
|
-
// Exclude .gitattributes and .gitignore files
|
|
149
153
|
const fileName = file.path.split('/').pop() || file.path;
|
|
150
154
|
if (fileName === '.gitattributes' || fileName === '.gitignore') {
|
|
151
155
|
continue;
|
|
@@ -157,8 +161,9 @@ export class GradioFilesTool {
|
|
|
157
161
|
type: file.type,
|
|
158
162
|
url: this.constructFileUrl(file.path),
|
|
159
163
|
sizeFormatted: formatBytes(file.size),
|
|
160
|
-
lastModified: file.lastCommit?.date,
|
|
164
|
+
lastModified: this.source.kind === 'bucket' ? file.uploadedAt : file.lastCommit?.date,
|
|
161
165
|
lfs: !!file.lfs,
|
|
166
|
+
source: this.source.kind,
|
|
162
167
|
});
|
|
163
168
|
}
|
|
164
169
|
}
|
|
@@ -166,7 +171,7 @@ export class GradioFilesTool {
|
|
|
166
171
|
return files.sort((a, b) => a.path.localeCompare(b.path));
|
|
167
172
|
} catch (error) {
|
|
168
173
|
if (error instanceof HfApiError) {
|
|
169
|
-
throw explain(error, `Failed to list files for
|
|
174
|
+
throw explain(error, `Failed to list files for ${this.source.kind} "${this.source.id}"`);
|
|
170
175
|
}
|
|
171
176
|
throw error;
|
|
172
177
|
}
|
|
@@ -176,19 +181,30 @@ export class GradioFilesTool {
|
|
|
176
181
|
* Construct the URL for a file
|
|
177
182
|
*/
|
|
178
183
|
private constructFileUrl(filePath: string): string {
|
|
179
|
-
|
|
184
|
+
if (this.source.kind === 'bucket') {
|
|
185
|
+
const encodedPath = filePath.split('/').map(encodeURIComponent).join('/');
|
|
186
|
+
return `https://huggingface.co/buckets/${this.source.id}/resolve/${encodedPath}`;
|
|
187
|
+
}
|
|
188
|
+
return `https://huggingface.co/datasets/${this.source.id}/resolve/main/${filePath}`;
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
/**
|
|
183
192
|
* Generate detailed markdown report with files grouped by directory
|
|
184
193
|
*/
|
|
185
|
-
async generateDetailedMarkdown(fileType:
|
|
186
|
-
const allFiles = await this.
|
|
194
|
+
async generateDetailedMarkdown(fileType: FileTypeFilter = 'all'): Promise<string> {
|
|
195
|
+
const allFiles = await this.getFiles();
|
|
187
196
|
const files = allFiles.filter((file) => matchesFileType(file, fileType));
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
const sourceLabel = this.source.kind === 'bucket' ? 'Hugging Face Bucket' : 'Hugging Face Dataset fallback';
|
|
198
|
+
|
|
199
|
+
let markdown = `# Available files in ${this.source.kind}: ${this.source.id}\n\n`;
|
|
200
|
+
markdown += `**Source:** ${sourceLabel}\n`;
|
|
201
|
+
markdown += '**Use:** URLs below can be used as Gradio file inputs when accessible to the target Space.\n\n';
|
|
202
|
+
if (this.source.kind === 'bucket') {
|
|
203
|
+
markdown +=
|
|
204
|
+
'Note: private bucket URLs require authorization. A remote Gradio Space can only fetch these URLs directly if it has access; public buckets are safest for cross-Space file inputs.\n\n';
|
|
205
|
+
}
|
|
190
206
|
if (fileType !== 'all') {
|
|
191
|
-
markdown += `**Filter**: ${fileType} files only\n`;
|
|
207
|
+
markdown += `**Filter**: ${fileType} files only\n\n`;
|
|
192
208
|
}
|
|
193
209
|
|
|
194
210
|
// Handle empty results
|
|
@@ -203,17 +219,30 @@ export class GradioFilesTool {
|
|
|
203
219
|
|
|
204
220
|
// Generate table
|
|
205
221
|
markdown += `## All Files\n\n`;
|
|
206
|
-
markdown += `| Name | Size | Type | Last Modified |
|
|
207
|
-
markdown +=
|
|
222
|
+
markdown += `| Name | Path | Size | Type | Last Modified | URL |\n`;
|
|
223
|
+
markdown += `|------|------|------|------|---------------|-----|\n`;
|
|
208
224
|
|
|
209
225
|
for (const file of files) {
|
|
210
226
|
const fileName = file.path.split('/').pop() || file.path;
|
|
211
227
|
const icon = getFileIcon(fileName);
|
|
212
228
|
const lastMod = file.lastModified ? new Date(file.lastModified).toLocaleDateString() : '-';
|
|
213
229
|
|
|
214
|
-
markdown += `| ${escapeMarkdown(fileName)} | ${file.sizeFormatted} | ${icon} ${file.type} | ${lastMod} | ${file.url} |\n`;
|
|
230
|
+
markdown += `| ${escapeMarkdown(fileName)} | ${escapeMarkdown(file.path)} | ${file.sizeFormatted} | ${icon} ${file.type} | ${lastMod} | ${file.url} |\n`;
|
|
215
231
|
}
|
|
216
232
|
|
|
217
233
|
return markdown;
|
|
218
234
|
}
|
|
219
235
|
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Compatibility wrapper for the legacy gradio_files dataset behavior.
|
|
239
|
+
*/
|
|
240
|
+
export class GradioFilesTool extends ListFilesTool {
|
|
241
|
+
constructor(hfToken: string, username: string) {
|
|
242
|
+
super(hfToken, { kind: 'dataset', id: `${username}/gradio-files` });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async getGradioFiles(): Promise<FileWithUrl[]> {
|
|
246
|
+
return this.getFiles();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import * as hub from '@huggingface/hub';
|
|
3
|
+
import type { ListFileEntry } from '@huggingface/hub';
|
|
4
|
+
import { LIST_FILES_TOOL_CONFIG, ListFilesTool } from '../src/gradio-files.js';
|
|
5
|
+
|
|
6
|
+
vi.mock('@huggingface/hub', () => ({
|
|
7
|
+
listFiles: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
async function* listFileEntries(entries: ListFileEntry[]): AsyncGenerator<ListFileEntry> {
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
yield entry;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function mockListFiles(entries: ListFileEntry[]): void {
|
|
17
|
+
vi.mocked(hub.listFiles).mockReturnValue(listFileEntries(entries));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('ListFilesTool', () => {
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
vi.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('lists bucket files recursively and encodes nested bucket URLs', async () => {
|
|
26
|
+
mockListFiles([
|
|
27
|
+
{ type: 'directory', path: 'images', size: 0 },
|
|
28
|
+
{ type: 'file', path: 'images/cat 1.png', size: 2048, uploadedAt: '2026-04-27T00:00:00Z' },
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const tool = new ListFilesTool('hf_token', { kind: 'bucket', id: 'alice/mcp' });
|
|
32
|
+
const files = await tool.getFiles();
|
|
33
|
+
|
|
34
|
+
expect(hub.listFiles).toHaveBeenCalledWith({
|
|
35
|
+
repo: { type: 'bucket', name: 'alice/mcp' },
|
|
36
|
+
recursive: true,
|
|
37
|
+
expand: true,
|
|
38
|
+
accessToken: 'hf_token',
|
|
39
|
+
});
|
|
40
|
+
expect(files).toEqual([
|
|
41
|
+
expect.objectContaining({
|
|
42
|
+
path: 'images/cat 1.png',
|
|
43
|
+
url: 'https://huggingface.co/buckets/alice/mcp/resolve/images/cat%201.png',
|
|
44
|
+
lastModified: '2026-04-27T00:00:00Z',
|
|
45
|
+
source: 'bucket',
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('keeps legacy dataset fallback behavior and excludes git metadata files', async () => {
|
|
51
|
+
mockListFiles([
|
|
52
|
+
{ type: 'file', path: '.gitattributes', size: 100 },
|
|
53
|
+
{ type: 'file', path: '.gitignore', size: 100 },
|
|
54
|
+
{
|
|
55
|
+
type: 'file',
|
|
56
|
+
path: 'cat.png',
|
|
57
|
+
size: 1024,
|
|
58
|
+
lastCommit: { date: '2026-04-27T00:00:00Z', id: '1', title: 'add' },
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const tool = new ListFilesTool('hf_token', { kind: 'dataset', id: 'alice/gradio-files' });
|
|
63
|
+
const files = await tool.getFiles();
|
|
64
|
+
|
|
65
|
+
expect(hub.listFiles).toHaveBeenCalledWith({
|
|
66
|
+
repo: { type: 'dataset', name: 'alice/gradio-files' },
|
|
67
|
+
recursive: false,
|
|
68
|
+
expand: true,
|
|
69
|
+
accessToken: 'hf_token',
|
|
70
|
+
});
|
|
71
|
+
expect(files).toHaveLength(1);
|
|
72
|
+
expect(files[0]).toMatchObject({
|
|
73
|
+
path: 'cat.png',
|
|
74
|
+
url: 'https://huggingface.co/datasets/alice/gradio-files/resolve/main/cat.png',
|
|
75
|
+
source: 'dataset',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('filters image, audio, and text files in markdown', async () => {
|
|
80
|
+
mockListFiles([
|
|
81
|
+
{ type: 'file', path: 'cat.png', size: 1024 },
|
|
82
|
+
{ type: 'file', path: 'sound.wav', size: 1024 },
|
|
83
|
+
{ type: 'file', path: 'notes.json', size: 1024 },
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const tool = new ListFilesTool('hf_token', { kind: 'bucket', id: 'alice/mcp' });
|
|
87
|
+
const markdown = await tool.generateDetailedMarkdown('text');
|
|
88
|
+
|
|
89
|
+
expect(markdown).toContain('notes.json');
|
|
90
|
+
expect(markdown).not.toContain('cat.png');
|
|
91
|
+
expect(markdown).not.toContain('sound.wav');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('identifies bucket source in markdown', async () => {
|
|
95
|
+
mockListFiles([{ type: 'file', path: 'hello.txt', size: 5 }]);
|
|
96
|
+
|
|
97
|
+
const tool = new ListFilesTool('hf_token', { kind: 'bucket', id: 'alice/mcp' });
|
|
98
|
+
const markdown = await tool.generateDetailedMarkdown();
|
|
99
|
+
|
|
100
|
+
expect(markdown).toContain('# Available files in bucket: alice/mcp');
|
|
101
|
+
expect(markdown).toContain('**Source:** Hugging Face Bucket');
|
|
102
|
+
expect(markdown).toContain('private bucket URLs require authorization');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('identifies dataset fallback source in markdown', async () => {
|
|
106
|
+
mockListFiles([{ type: 'file', path: 'hello.txt', size: 5 }]);
|
|
107
|
+
|
|
108
|
+
const tool = new ListFilesTool('hf_token', { kind: 'dataset', id: 'alice/gradio-files' });
|
|
109
|
+
const markdown = await tool.generateDetailedMarkdown();
|
|
110
|
+
|
|
111
|
+
expect(markdown).toContain('# Available files in dataset: alice/gradio-files');
|
|
112
|
+
expect(markdown).toContain('**Source:** Hugging Face Dataset fallback');
|
|
113
|
+
expect(markdown).not.toContain('private bucket URLs require authorization');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('exposes the gradio_files tool config', () => {
|
|
117
|
+
expect(LIST_FILES_TOOL_CONFIG.name).toBe('gradio_files');
|
|
118
|
+
expect(LIST_FILES_TOOL_CONFIG.annotations.readOnlyHint).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
});
|