@llmindset/hf-mcp 0.2.32 → 0.2.34
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/docs-search/docs-semantic-search.d.ts +2 -2
- package/dist/docs-search/docs-semantic-search.d.ts.map +1 -1
- package/dist/docs-search/docs-semantic-search.js +56 -21
- package/dist/docs-search/docs-semantic-search.js.map +1 -1
- package/dist/hf-api-call.d.ts.map +1 -1
- package/dist/hf-api-call.js +4 -0
- package/dist/hf-api-call.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/jobs/api-client.d.ts +19 -0
- package/dist/jobs/api-client.d.ts.map +1 -0
- package/dist/jobs/api-client.js +104 -0
- package/dist/jobs/api-client.js.map +1 -0
- package/dist/jobs/commands/inspect.d.ts +5 -0
- package/dist/jobs/commands/inspect.d.ts.map +1 -0
- package/dist/jobs/commands/inspect.js +21 -0
- package/dist/jobs/commands/inspect.js.map +1 -0
- package/dist/jobs/commands/logs.d.ts +4 -0
- package/dist/jobs/commands/logs.d.ts.map +1 -0
- package/dist/jobs/commands/logs.js +24 -0
- package/dist/jobs/commands/logs.js.map +1 -0
- package/dist/jobs/commands/ps.d.ts +4 -0
- package/dist/jobs/commands/ps.d.ts.map +1 -0
- package/dist/jobs/commands/ps.js +23 -0
- package/dist/jobs/commands/ps.js.map +1 -0
- package/dist/jobs/commands/run.d.ts +5 -0
- package/dist/jobs/commands/run.d.ts.map +1 -0
- package/dist/jobs/commands/run.js +89 -0
- package/dist/jobs/commands/run.js.map +1 -0
- package/dist/jobs/commands/scheduled.d.ts +10 -0
- package/dist/jobs/commands/scheduled.d.ts.map +1 -0
- package/dist/jobs/commands/scheduled.js +111 -0
- package/dist/jobs/commands/scheduled.js.map +1 -0
- package/dist/jobs/commands/utils.d.ts +19 -0
- package/dist/jobs/commands/utils.d.ts.map +1 -0
- package/dist/jobs/commands/utils.js +99 -0
- package/dist/jobs/commands/utils.js.map +1 -0
- package/dist/jobs/formatters.d.ts +6 -0
- package/dist/jobs/formatters.d.ts.map +1 -0
- package/dist/jobs/formatters.js +98 -0
- package/dist/jobs/formatters.js.map +1 -0
- package/dist/jobs/sse-handler.d.ts +12 -0
- package/dist/jobs/sse-handler.d.ts.map +1 -0
- package/dist/jobs/sse-handler.js +80 -0
- package/dist/jobs/sse-handler.js.map +1 -0
- package/dist/jobs/tool.d.ts +35 -0
- package/dist/jobs/tool.d.ts.map +1 -0
- package/dist/jobs/tool.js +333 -0
- package/dist/jobs/tool.js.map +1 -0
- package/dist/jobs/types.d.ts +295 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +95 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/tool-ids.d.ts +3 -2
- package/dist/tool-ids.d.ts.map +1 -1
- package/dist/tool-ids.js +10 -2
- package/dist/tool-ids.js.map +1 -1
- package/dist/types/tool-result.d.ts +1 -0
- package/dist/types/tool-result.d.ts.map +1 -1
- package/dist/use-space.d.ts +0 -1
- package/dist/use-space.d.ts.map +1 -1
- package/dist/use-space.js +0 -1
- package/dist/use-space.js.map +1 -1
- package/package.json +4 -2
- package/src/docs-search/docs-semantic-search.ts +71 -20
- package/src/hf-api-call.ts +6 -0
- package/src/index.ts +1 -0
- package/src/jobs/api-client.ts +195 -0
- package/src/jobs/commands/inspect.ts +38 -0
- package/src/jobs/commands/logs.ts +36 -0
- package/src/jobs/commands/ps.ts +40 -0
- package/src/jobs/commands/run.ts +134 -0
- package/src/jobs/commands/scheduled.ts +189 -0
- package/src/jobs/commands/utils.ts +158 -0
- package/src/jobs/formatters.ts +149 -0
- package/src/jobs/sse-handler.ts +144 -0
- package/src/jobs/tool.ts +435 -0
- package/src/jobs/types.ts +237 -0
- package/src/tool-ids.ts +11 -1
- package/src/types/tool-result.ts +6 -0
- package/src/use-space.ts +0 -1
- package/test/jobs/command-translation.spec.ts +277 -0
- package/test/jobs/formatters.spec.ts +267 -0
- package/test/jobs/uv-command.spec.ts +81 -0
- package/dist/types/mcp-ui-server-shim.d.ts +0 -37
- package/dist/types/mcp-ui-server-shim.d.ts.map +0 -1
- package/dist/types/mcp-ui-server-shim.js +0 -2
- package/dist/types/mcp-ui-server-shim.js.map +0 -1
- package/src/types/mcp-ui-server-shim.ts +0 -35
package/src/jobs/tool.ts
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { JobsApiClient } from './api-client.js';
|
|
3
|
+
import { HfApiError } from '../hf-api-call.js';
|
|
4
|
+
import { runCommand, uvCommand } from './commands/run.js';
|
|
5
|
+
import { psCommand } from './commands/ps.js';
|
|
6
|
+
import { logsCommand } from './commands/logs.js';
|
|
7
|
+
import { inspectCommand, cancelCommand } from './commands/inspect.js';
|
|
8
|
+
import {
|
|
9
|
+
scheduledRunCommand,
|
|
10
|
+
scheduledUvCommand,
|
|
11
|
+
scheduledPsCommand,
|
|
12
|
+
scheduledInspectCommand,
|
|
13
|
+
scheduledDeleteCommand,
|
|
14
|
+
scheduledSuspendCommand,
|
|
15
|
+
scheduledResumeCommand,
|
|
16
|
+
} from './commands/scheduled.js';
|
|
17
|
+
import type { ToolResult } from '../types/tool-result.js';
|
|
18
|
+
import type {
|
|
19
|
+
RunArgs,
|
|
20
|
+
UvArgs,
|
|
21
|
+
PsArgs,
|
|
22
|
+
LogsArgs,
|
|
23
|
+
InspectArgs,
|
|
24
|
+
CancelArgs,
|
|
25
|
+
ScheduledRunArgs,
|
|
26
|
+
ScheduledUvArgs,
|
|
27
|
+
ScheduledPsArgs,
|
|
28
|
+
ScheduledJobArgs,
|
|
29
|
+
} from './types.js';
|
|
30
|
+
|
|
31
|
+
// Re-export types
|
|
32
|
+
export * from './types.js';
|
|
33
|
+
export { JobsApiClient } from './api-client.js';
|
|
34
|
+
|
|
35
|
+
// Import Zod schemas for validation
|
|
36
|
+
import {
|
|
37
|
+
runArgsSchema,
|
|
38
|
+
uvArgsSchema,
|
|
39
|
+
psArgsSchema,
|
|
40
|
+
logsArgsSchema,
|
|
41
|
+
inspectArgsSchema,
|
|
42
|
+
cancelArgsSchema,
|
|
43
|
+
scheduledRunArgsSchema,
|
|
44
|
+
scheduledUvArgsSchema,
|
|
45
|
+
scheduledPsArgsSchema,
|
|
46
|
+
scheduledJobArgsSchema,
|
|
47
|
+
} from './types.js';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Map of command names to their validation schemas
|
|
51
|
+
*/
|
|
52
|
+
const COMMAND_SCHEMAS = {
|
|
53
|
+
run: runArgsSchema,
|
|
54
|
+
uv: uvArgsSchema,
|
|
55
|
+
ps: psArgsSchema,
|
|
56
|
+
logs: logsArgsSchema,
|
|
57
|
+
inspect: inspectArgsSchema,
|
|
58
|
+
cancel: cancelArgsSchema,
|
|
59
|
+
'scheduled run': scheduledRunArgsSchema,
|
|
60
|
+
'scheduled uv': scheduledUvArgsSchema,
|
|
61
|
+
'scheduled ps': scheduledPsArgsSchema,
|
|
62
|
+
'scheduled inspect': scheduledJobArgsSchema,
|
|
63
|
+
'scheduled delete': scheduledJobArgsSchema,
|
|
64
|
+
'scheduled suspend': scheduledJobArgsSchema,
|
|
65
|
+
'scheduled resume': scheduledJobArgsSchema,
|
|
66
|
+
} as const;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validate command arguments against a Zod schema
|
|
70
|
+
* Returns a ToolResult with detailed error message if validation fails
|
|
71
|
+
*/
|
|
72
|
+
function validateArgs(
|
|
73
|
+
schema: z.ZodSchema,
|
|
74
|
+
args: unknown,
|
|
75
|
+
commandName: string
|
|
76
|
+
): { success: true } | { success: false; errorResult: ToolResult } {
|
|
77
|
+
const result = schema.safeParse(args);
|
|
78
|
+
|
|
79
|
+
if (result.success) {
|
|
80
|
+
return { success: true };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Format Zod errors into a helpful message
|
|
84
|
+
const errors = result.error.errors;
|
|
85
|
+
const missingFields: string[] = [];
|
|
86
|
+
const invalidFields: string[] = [];
|
|
87
|
+
|
|
88
|
+
for (const err of errors) {
|
|
89
|
+
const field = err.path.join('.');
|
|
90
|
+
if (err.code === 'invalid_type' && err.received === 'undefined') {
|
|
91
|
+
missingFields.push(` • ${field}: ${err.message}`);
|
|
92
|
+
} else {
|
|
93
|
+
invalidFields.push(` • ${field}: ${err.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let errorMessage = `Error: Invalid parameters for '${commandName}'\n\n`;
|
|
98
|
+
|
|
99
|
+
if (missingFields.length > 0) {
|
|
100
|
+
errorMessage += `Missing required parameters:\n${missingFields.join('\n')}\n\n`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (invalidFields.length > 0) {
|
|
104
|
+
errorMessage += `Invalid parameters:\n${invalidFields.join('\n')}\n\n`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Show what was provided
|
|
108
|
+
const providedKeys = args && typeof args === 'object' ? Object.keys(args) : [];
|
|
109
|
+
if (providedKeys.length > 0) {
|
|
110
|
+
errorMessage += `You provided: ${JSON.stringify(args, null, 2)}`;
|
|
111
|
+
} else {
|
|
112
|
+
errorMessage += `You provided: {} (no parameters)`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
success: false,
|
|
117
|
+
errorResult: {
|
|
118
|
+
formatted: errorMessage,
|
|
119
|
+
totalResults: 0,
|
|
120
|
+
resultsShared: 0,
|
|
121
|
+
isError: true,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Usage instructions when tool is called with no arguments
|
|
128
|
+
*/
|
|
129
|
+
const USAGE_INSTRUCTIONS = `# HuggingFace Jobs API
|
|
130
|
+
|
|
131
|
+
Manage compute jobs on Hugging Face infrastructure.
|
|
132
|
+
|
|
133
|
+
## Available Commands
|
|
134
|
+
|
|
135
|
+
### Job Management
|
|
136
|
+
- **run** - Run a job with a Docker image
|
|
137
|
+
- **uv** - Run a Python script with UV (inline dependencies)
|
|
138
|
+
- **ps** - List jobs
|
|
139
|
+
- **logs** - Fetch job logs
|
|
140
|
+
- **inspect** - Get detailed job information
|
|
141
|
+
- **cancel** - Cancel a running job
|
|
142
|
+
|
|
143
|
+
### Scheduled Jobs
|
|
144
|
+
- **scheduled run** - Create a scheduled job
|
|
145
|
+
- **scheduled uv** - Create a scheduled UV job
|
|
146
|
+
- **scheduled ps** - List scheduled jobs
|
|
147
|
+
- **scheduled inspect** - Get scheduled job details
|
|
148
|
+
- **scheduled delete** - Delete a scheduled job
|
|
149
|
+
- **scheduled suspend** - Pause a scheduled job
|
|
150
|
+
- **scheduled resume** - Resume a suspended job
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
### Run a simple job
|
|
155
|
+
\`\`\`
|
|
156
|
+
# Command as array (recommended, especially for complex commands)
|
|
157
|
+
hf_jobs("run", {
|
|
158
|
+
"image": "python:3.12",
|
|
159
|
+
"command": ["python", "-c", "print('Hello from HF Jobs!')"],
|
|
160
|
+
"flavor": "cpu-basic"
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
# Command as string (parsed with POSIX shell semantics)
|
|
164
|
+
hf_jobs("run", {
|
|
165
|
+
"image": "python:3.12",
|
|
166
|
+
"command": "python -c \\"print('Hello world!')\\"",
|
|
167
|
+
"flavor": "cpu-basic"
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
# Use a Hugging Face Space as the image
|
|
171
|
+
hf_jobs("run", {
|
|
172
|
+
"image": "hf.co/spaces/username/spacename",
|
|
173
|
+
"command": ["python", "app.py"],
|
|
174
|
+
"flavor": "cpu-basic"
|
|
175
|
+
})
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
### Run multiline Python scripts
|
|
179
|
+
\`\`\`
|
|
180
|
+
# Use array format with newlines in the -c argument
|
|
181
|
+
hf_jobs("run", {
|
|
182
|
+
"image": "python:3.12",
|
|
183
|
+
"command": ["python", "-c", "import sys\\nprint('Line 1')\\nprint('Line 2')"],
|
|
184
|
+
"flavor": "cpu-basic"
|
|
185
|
+
})
|
|
186
|
+
\`\`\`
|
|
187
|
+
|
|
188
|
+
### Run bash/shell commands
|
|
189
|
+
\`\`\`
|
|
190
|
+
hf_jobs("run", {
|
|
191
|
+
"image": "ubuntu:22.04",
|
|
192
|
+
"command": ["bash", "-c", "apt-get update && apt-get install -y curl"],
|
|
193
|
+
"flavor": "cpu-basic"
|
|
194
|
+
})
|
|
195
|
+
\`\`\`
|
|
196
|
+
|
|
197
|
+
### List running jobs
|
|
198
|
+
\`\`\`
|
|
199
|
+
hf_jobs("ps")
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
### Get job logs
|
|
203
|
+
\`\`\`
|
|
204
|
+
hf_jobs("logs", {"job_id": "your-job-id"})
|
|
205
|
+
\`\`\`
|
|
206
|
+
|
|
207
|
+
### Run with GPU
|
|
208
|
+
\`\`\`
|
|
209
|
+
hf_jobs("run", {
|
|
210
|
+
"image": "pytorch/pytorch:2.6.0-cuda12.4-cudnn9-devel",
|
|
211
|
+
"command": ["python", "train.py"],
|
|
212
|
+
"flavor": "a10g-small"
|
|
213
|
+
})
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
### Schedule a job
|
|
217
|
+
\`\`\`
|
|
218
|
+
hf_jobs("scheduled run", {
|
|
219
|
+
"schedule": "@hourly",
|
|
220
|
+
"image": "python:3.12",
|
|
221
|
+
"command": ["python", "backup.py"]
|
|
222
|
+
})
|
|
223
|
+
\`\`\`
|
|
224
|
+
|
|
225
|
+
## Hardware Flavors
|
|
226
|
+
|
|
227
|
+
**CPU:** cpu-basic, cpu-upgrade, cpu-performance, cpu-xl
|
|
228
|
+
**GPU:** t4-small, t4-medium, l4x1, a10g-small, a10g-large, a100-large, h100
|
|
229
|
+
**Specialized:** inf2x6 (AWS Inferentia)
|
|
230
|
+
|
|
231
|
+
## Command Format Guidelines
|
|
232
|
+
|
|
233
|
+
**Array format (recommended):**
|
|
234
|
+
- Use for complex commands, multiline scripts, or commands with special characters
|
|
235
|
+
- No quoting/escaping needed: \`["python", "-c", "print('hello')"]\`
|
|
236
|
+
- Works with any language: Python, bash, npm, etc.
|
|
237
|
+
|
|
238
|
+
**String format:**
|
|
239
|
+
- Parsed with POSIX shell semantics (quotes, escaping)
|
|
240
|
+
- Good for simple commands: \`"python script.py"\`
|
|
241
|
+
- Shell operators (|, &&, >, etc.) are NOT supported - use array with \`bash -c\` instead
|
|
242
|
+
- Variable tokens like \`$HF_TOKEN\` are kept literal—the remote container expands them at runtime
|
|
243
|
+
|
|
244
|
+
**Multiline inline scripts:**
|
|
245
|
+
- Automatically wrapped in \`["/bin/sh", "-lc", "..."]\` for shell execution
|
|
246
|
+
- Paste entire Python/bash snippets—they execute as if typed in a shell
|
|
247
|
+
|
|
248
|
+
## Tips
|
|
249
|
+
|
|
250
|
+
- Jobs default to detached mode (return immediately with job ID)
|
|
251
|
+
- Use Hub resources directly: \`load_dataset('squad')\`, \`AutoModel.from_pretrained('bert-base')\`
|
|
252
|
+
- Pass HF_TOKEN via secrets for private resources
|
|
253
|
+
- Logs are time-limited (10s max) - check job page for full logs
|
|
254
|
+
- For shell pipes/operators, use: \`["bash", "-c", "cmd1 | cmd2"]\`
|
|
255
|
+
`;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Jobs tool configuration
|
|
259
|
+
*/
|
|
260
|
+
export const HF_JOBS_TOOL_CONFIG = {
|
|
261
|
+
name: 'hf_jobs',
|
|
262
|
+
description:
|
|
263
|
+
'Manage HuggingFace compute jobs. Run any command in Docker containers (Python, Node.js, bash, etc.), ' +
|
|
264
|
+
'execute Python scripts with UV package manager, manage scheduled jobs, and monitor job status and logs. ' +
|
|
265
|
+
'Supports CPU and GPU hardware. Call with no arguments for full usage instructions and examples.',
|
|
266
|
+
schema: z.object({
|
|
267
|
+
command: z
|
|
268
|
+
.string()
|
|
269
|
+
.optional()
|
|
270
|
+
.describe(
|
|
271
|
+
'Command to execute: "run", "uv", "ps", "logs", "inspect", "cancel", ' +
|
|
272
|
+
'"scheduled run", "scheduled uv", "scheduled ps", "scheduled inspect", ' +
|
|
273
|
+
'"scheduled delete", "scheduled suspend", "scheduled resume"'
|
|
274
|
+
),
|
|
275
|
+
args: z.record(z.any()).optional().describe('Command-specific arguments as a JSON object'),
|
|
276
|
+
}),
|
|
277
|
+
annotations: {
|
|
278
|
+
title: 'HuggingFace Jobs',
|
|
279
|
+
destructiveHint: false,
|
|
280
|
+
readOnlyHint: false,
|
|
281
|
+
openWorldHint: true,
|
|
282
|
+
},
|
|
283
|
+
} as const;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Jobs tool implementation
|
|
287
|
+
*/
|
|
288
|
+
export class HfJobsTool {
|
|
289
|
+
private client: JobsApiClient;
|
|
290
|
+
private hfToken?: string;
|
|
291
|
+
private isAuthenticated: boolean;
|
|
292
|
+
|
|
293
|
+
constructor(hfToken?: string, isAuthenticated?: boolean, namespace?: string) {
|
|
294
|
+
this.hfToken = hfToken;
|
|
295
|
+
this.isAuthenticated = isAuthenticated ?? !!hfToken;
|
|
296
|
+
this.client = new JobsApiClient(hfToken, namespace);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Execute a jobs command
|
|
301
|
+
*/
|
|
302
|
+
async execute(params: { command?: string; args?: Record<string, unknown> }): Promise<ToolResult> {
|
|
303
|
+
// If not authenticated, show upgrade message
|
|
304
|
+
if (!this.isAuthenticated) {
|
|
305
|
+
return {
|
|
306
|
+
formatted:
|
|
307
|
+
'Jobs are available for Pro, Team and Enterprise users. Go to https://huggingface.co/pricing to get started.',
|
|
308
|
+
totalResults: 0,
|
|
309
|
+
resultsShared: 0,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// If no command provided, return usage instructions
|
|
314
|
+
if (!params.command) {
|
|
315
|
+
return {
|
|
316
|
+
formatted: USAGE_INSTRUCTIONS,
|
|
317
|
+
totalResults: 1,
|
|
318
|
+
resultsShared: 1,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const command = params.command.toLowerCase();
|
|
323
|
+
const args = params.args || {};
|
|
324
|
+
|
|
325
|
+
// Validate command arguments if schema exists
|
|
326
|
+
const schema = COMMAND_SCHEMAS[command as keyof typeof COMMAND_SCHEMAS];
|
|
327
|
+
if (schema) {
|
|
328
|
+
const validation = validateArgs(schema, args, command);
|
|
329
|
+
if (!validation.success) {
|
|
330
|
+
return validation.errorResult;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
let result: string;
|
|
336
|
+
|
|
337
|
+
switch (command) {
|
|
338
|
+
case 'run':
|
|
339
|
+
result = await runCommand(args as RunArgs, this.client, this.hfToken);
|
|
340
|
+
break;
|
|
341
|
+
|
|
342
|
+
case 'uv':
|
|
343
|
+
result = await uvCommand(args as UvArgs, this.client, this.hfToken);
|
|
344
|
+
break;
|
|
345
|
+
|
|
346
|
+
case 'ps':
|
|
347
|
+
result = await psCommand(args as PsArgs, this.client);
|
|
348
|
+
break;
|
|
349
|
+
|
|
350
|
+
case 'logs':
|
|
351
|
+
result = await logsCommand(args as LogsArgs, this.client, this.hfToken);
|
|
352
|
+
break;
|
|
353
|
+
|
|
354
|
+
case 'inspect':
|
|
355
|
+
result = await inspectCommand(args as InspectArgs, this.client);
|
|
356
|
+
break;
|
|
357
|
+
|
|
358
|
+
case 'cancel':
|
|
359
|
+
result = await cancelCommand(args as CancelArgs, this.client);
|
|
360
|
+
break;
|
|
361
|
+
|
|
362
|
+
case 'scheduled run':
|
|
363
|
+
result = await scheduledRunCommand(args as ScheduledRunArgs, this.client);
|
|
364
|
+
break;
|
|
365
|
+
|
|
366
|
+
case 'scheduled uv':
|
|
367
|
+
result = await scheduledUvCommand(args as ScheduledUvArgs, this.client);
|
|
368
|
+
break;
|
|
369
|
+
|
|
370
|
+
case 'scheduled ps':
|
|
371
|
+
result = await scheduledPsCommand(args as ScheduledPsArgs, this.client);
|
|
372
|
+
break;
|
|
373
|
+
|
|
374
|
+
case 'scheduled inspect':
|
|
375
|
+
result = await scheduledInspectCommand(args as ScheduledJobArgs, this.client);
|
|
376
|
+
break;
|
|
377
|
+
|
|
378
|
+
case 'scheduled delete':
|
|
379
|
+
result = await scheduledDeleteCommand(args as ScheduledJobArgs, this.client);
|
|
380
|
+
break;
|
|
381
|
+
|
|
382
|
+
case 'scheduled suspend':
|
|
383
|
+
result = await scheduledSuspendCommand(args as ScheduledJobArgs, this.client);
|
|
384
|
+
break;
|
|
385
|
+
|
|
386
|
+
case 'scheduled resume':
|
|
387
|
+
result = await scheduledResumeCommand(args as ScheduledJobArgs, this.client);
|
|
388
|
+
break;
|
|
389
|
+
|
|
390
|
+
default:
|
|
391
|
+
return {
|
|
392
|
+
formatted: `Unknown command: "${params.command}"
|
|
393
|
+
|
|
394
|
+
Available commands:
|
|
395
|
+
- run, uv, ps, logs, inspect, cancel
|
|
396
|
+
- scheduled run, scheduled uv, scheduled ps, scheduled inspect, scheduled delete, scheduled suspend, scheduled resume
|
|
397
|
+
|
|
398
|
+
Call hf_jobs() with no arguments for full usage instructions.`,
|
|
399
|
+
totalResults: 0,
|
|
400
|
+
resultsShared: 0,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return {
|
|
405
|
+
formatted: result,
|
|
406
|
+
totalResults: 1,
|
|
407
|
+
resultsShared: 1,
|
|
408
|
+
};
|
|
409
|
+
} catch (error) {
|
|
410
|
+
let errorMessage = error instanceof Error ? error.message : String(error);
|
|
411
|
+
|
|
412
|
+
// If this is an HfApiError with a response body, include it
|
|
413
|
+
if (error instanceof HfApiError && error.responseBody) {
|
|
414
|
+
try {
|
|
415
|
+
// Try to parse and format the response body
|
|
416
|
+
const parsed: unknown = JSON.parse(error.responseBody);
|
|
417
|
+
const formattedBody = JSON.stringify(parsed, null, 2);
|
|
418
|
+
errorMessage += `\n\nServer response:\n${formattedBody}`;
|
|
419
|
+
} catch {
|
|
420
|
+
// If not valid JSON, include raw response (if not too long)
|
|
421
|
+
if (error.responseBody.length < 500) {
|
|
422
|
+
errorMessage += `\n\nServer response: ${error.responseBody}`;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
formatted: `Error executing ${params.command}: ${errorMessage}`,
|
|
429
|
+
totalResults: 0,
|
|
430
|
+
resultsShared: 0,
|
|
431
|
+
isError: true,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hardware flavors available for jobs
|
|
5
|
+
*/
|
|
6
|
+
export const CPU_FLAVORS = ['cpu-basic', 'cpu-upgrade', 'cpu-performance', 'cpu-xl'] as const;
|
|
7
|
+
|
|
8
|
+
export const GPU_FLAVORS = [
|
|
9
|
+
'sprx8',
|
|
10
|
+
'zero-a10g',
|
|
11
|
+
't4-small',
|
|
12
|
+
't4-medium',
|
|
13
|
+
'l4x1',
|
|
14
|
+
'l4x4',
|
|
15
|
+
'l40sx1',
|
|
16
|
+
'l40sx4',
|
|
17
|
+
'l40sx8',
|
|
18
|
+
'a10g-small',
|
|
19
|
+
'a10g-large',
|
|
20
|
+
'a10g-largex2',
|
|
21
|
+
'a10g-largex4',
|
|
22
|
+
'a100-large',
|
|
23
|
+
'h100',
|
|
24
|
+
'h100x8',
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
export const SPECIALIZED_FLAVORS = ['inf2x6'] as const;
|
|
28
|
+
|
|
29
|
+
export const ALL_FLAVORS = [...CPU_FLAVORS, ...GPU_FLAVORS, ...SPECIALIZED_FLAVORS] as const;
|
|
30
|
+
|
|
31
|
+
export type JobFlavor = (typeof ALL_FLAVORS)[number];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Job status stages (from OpenAPI spec)
|
|
35
|
+
*/
|
|
36
|
+
export type JobStage = 'RUNNING' | 'COMPLETED' | 'CANCELED' | 'ERROR' | 'DELETED';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Job status object from API
|
|
40
|
+
*/
|
|
41
|
+
export interface JobStatus {
|
|
42
|
+
stage: JobStage;
|
|
43
|
+
message?: string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Job owner information
|
|
48
|
+
*/
|
|
49
|
+
export interface JobOwner {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
type: 'user' | 'org';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Job information from API
|
|
57
|
+
* Based on OpenAPI schema
|
|
58
|
+
*/
|
|
59
|
+
export interface JobInfo {
|
|
60
|
+
id: string;
|
|
61
|
+
createdAt: string;
|
|
62
|
+
dockerImage?: string;
|
|
63
|
+
spaceId?: string;
|
|
64
|
+
command?: string[];
|
|
65
|
+
arguments?: string[];
|
|
66
|
+
environment: Record<string, string>;
|
|
67
|
+
secrets?: Record<string, string | null>;
|
|
68
|
+
flavor: string;
|
|
69
|
+
status: JobStatus;
|
|
70
|
+
owner: JobOwner;
|
|
71
|
+
createdBy?: JobOwner;
|
|
72
|
+
tags?: string[];
|
|
73
|
+
timeout?: number;
|
|
74
|
+
// Additional fields not in OpenAPI but present in responses
|
|
75
|
+
url?: string;
|
|
76
|
+
endpoint?: string;
|
|
77
|
+
finishedAt?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Job specification for creating jobs
|
|
82
|
+
*/
|
|
83
|
+
export interface JobSpec {
|
|
84
|
+
dockerImage?: string;
|
|
85
|
+
spaceId?: string;
|
|
86
|
+
command: string[];
|
|
87
|
+
arguments?: string[];
|
|
88
|
+
environment?: Record<string, string>;
|
|
89
|
+
secrets?: Record<string, string>;
|
|
90
|
+
flavor: string;
|
|
91
|
+
timeoutSeconds?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Scheduled job specification
|
|
96
|
+
*/
|
|
97
|
+
export interface ScheduledJobSpec {
|
|
98
|
+
schedule: string;
|
|
99
|
+
suspend?: boolean;
|
|
100
|
+
jobSpec: JobSpec;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Scheduled job information from API
|
|
105
|
+
*/
|
|
106
|
+
export interface ScheduledJobInfo {
|
|
107
|
+
id: string;
|
|
108
|
+
schedule: string;
|
|
109
|
+
suspend: boolean;
|
|
110
|
+
jobSpec: JobSpec;
|
|
111
|
+
lastRun?: string;
|
|
112
|
+
nextRun?: string;
|
|
113
|
+
owner: JobOwner;
|
|
114
|
+
createdAt: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Log event from SSE stream
|
|
119
|
+
*/
|
|
120
|
+
export interface LogEvent {
|
|
121
|
+
timestamp: string;
|
|
122
|
+
data: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Zod schemas for command arguments
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
// Common args shared across commands
|
|
130
|
+
const commonArgsSchema = z.object({
|
|
131
|
+
namespace: z.string().optional().describe('Target namespace (username or organization). Defaults to current user.'),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Run command args
|
|
135
|
+
export const runArgsSchema = commonArgsSchema.extend({
|
|
136
|
+
image: z.string().describe('Docker image or HF Space URL (e.g., "python:3.12" or "hf.co/spaces/user/space")'),
|
|
137
|
+
command: z
|
|
138
|
+
.union([z.string(), z.array(z.string())])
|
|
139
|
+
.describe(
|
|
140
|
+
'Command to execute. Array format recommended (e.g., ["python", "script.py"]). ' +
|
|
141
|
+
'String format is parsed with POSIX shell semantics (quotes, escaping). ' +
|
|
142
|
+
'For multiline scripts, use array with newlines in arguments.'
|
|
143
|
+
),
|
|
144
|
+
flavor: z
|
|
145
|
+
.enum(ALL_FLAVORS)
|
|
146
|
+
.optional()
|
|
147
|
+
.default('cpu-basic')
|
|
148
|
+
.describe(`Hardware flavor. Options: ${ALL_FLAVORS.join(', ')}`),
|
|
149
|
+
env: z.record(z.string()).optional().describe('Environment variables as key-value pairs'),
|
|
150
|
+
secrets: z.record(z.string()).optional().describe('Secret environment variables (encrypted server-side)'),
|
|
151
|
+
timeout: z
|
|
152
|
+
.string()
|
|
153
|
+
.optional()
|
|
154
|
+
.describe('Max duration (e.g., "5m", "2h", "30s"). Default: 30m')
|
|
155
|
+
.default('30m'),
|
|
156
|
+
detach: z
|
|
157
|
+
.boolean()
|
|
158
|
+
.optional()
|
|
159
|
+
.default(true)
|
|
160
|
+
.describe('Run in background and return immediately (default: true)'),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// UV command args
|
|
164
|
+
export const uvArgsSchema = commonArgsSchema.extend({
|
|
165
|
+
script: z
|
|
166
|
+
.string()
|
|
167
|
+
.describe('Python script: local file path, URL, or inline code. UV will handle dependencies automatically.'),
|
|
168
|
+
repo: z.string().optional().describe('Persistent repository name for script storage'),
|
|
169
|
+
with_deps: z.array(z.string()).optional().describe('Additional package dependencies'),
|
|
170
|
+
script_args: z.array(z.string()).optional().describe('Arguments to pass to the script'),
|
|
171
|
+
python: z.string().optional().describe('Python interpreter version (e.g., "3.12")'),
|
|
172
|
+
flavor: z.enum(ALL_FLAVORS).optional().default('cpu-basic').describe('Hardware flavor'),
|
|
173
|
+
env: z.record(z.string()).optional().describe('Environment variables'),
|
|
174
|
+
secrets: z.record(z.string()).optional().describe('Secret environment variables'),
|
|
175
|
+
timeout: z.string().optional().default('30m').describe('Max duration'),
|
|
176
|
+
detach: z.boolean().optional().default(true).describe('Run in background'),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// PS command args
|
|
180
|
+
export const psArgsSchema = commonArgsSchema.extend({
|
|
181
|
+
all: z.boolean().optional().default(false).describe('Show all jobs (default: only running)'),
|
|
182
|
+
status: z.string().optional().describe('Filter by status (e.g., "RUNNING", "COMPLETED")'),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Logs command args
|
|
186
|
+
export const logsArgsSchema = commonArgsSchema.extend({
|
|
187
|
+
job_id: z.string().describe('Job ID to fetch logs from'),
|
|
188
|
+
tail: z.number().optional().default(20).describe('Number of lines to return (default: 20)'),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Inspect command args
|
|
192
|
+
export const inspectArgsSchema = commonArgsSchema.extend({
|
|
193
|
+
job_id: z.union([z.string(), z.array(z.string())]).describe('Job ID(s) to inspect'),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Cancel command args
|
|
197
|
+
export const cancelArgsSchema = commonArgsSchema.extend({
|
|
198
|
+
job_id: z.string().describe('Job ID to cancel'),
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Scheduled run args
|
|
202
|
+
export const scheduledRunArgsSchema = runArgsSchema.extend({
|
|
203
|
+
schedule: z
|
|
204
|
+
.string()
|
|
205
|
+
.describe('Schedule: cron expression or shorthand (@hourly, @daily, @weekly, @monthly, @yearly)'),
|
|
206
|
+
suspend: z.boolean().optional().default(false).describe('Create in suspended state'),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Scheduled UV args
|
|
210
|
+
export const scheduledUvArgsSchema = uvArgsSchema.extend({
|
|
211
|
+
schedule: z.string().describe('Schedule: cron expression or shorthand'),
|
|
212
|
+
suspend: z.boolean().optional().default(false).describe('Create in suspended state'),
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Scheduled PS args
|
|
216
|
+
export const scheduledPsArgsSchema = commonArgsSchema.extend({
|
|
217
|
+
all: z.boolean().optional().default(false).describe('Show all scheduled jobs (default: hide suspended)'),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Scheduled inspect/delete/suspend/resume args
|
|
221
|
+
export const scheduledJobArgsSchema = commonArgsSchema.extend({
|
|
222
|
+
scheduled_job_id: z.string().describe('Scheduled job ID'),
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Export type aliases for use in commands
|
|
227
|
+
*/
|
|
228
|
+
export type RunArgs = z.infer<typeof runArgsSchema>;
|
|
229
|
+
export type UvArgs = z.infer<typeof uvArgsSchema>;
|
|
230
|
+
export type PsArgs = z.infer<typeof psArgsSchema>;
|
|
231
|
+
export type LogsArgs = z.infer<typeof logsArgsSchema>;
|
|
232
|
+
export type InspectArgs = z.infer<typeof inspectArgsSchema>;
|
|
233
|
+
export type CancelArgs = z.infer<typeof cancelArgsSchema>;
|
|
234
|
+
export type ScheduledRunArgs = z.infer<typeof scheduledRunArgsSchema>;
|
|
235
|
+
export type ScheduledUvArgs = z.infer<typeof scheduledUvArgsSchema>;
|
|
236
|
+
export type ScheduledPsArgs = z.infer<typeof scheduledPsArgsSchema>;
|
|
237
|
+
export type ScheduledJobArgs = z.infer<typeof scheduledJobArgsSchema>;
|
package/src/tool-ids.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
DOCS_SEMANTIC_SEARCH_CONFIG,
|
|
22
22
|
DOC_FETCH_CONFIG,
|
|
23
23
|
USE_SPACE_TOOL_CONFIG,
|
|
24
|
+
HF_JOBS_TOOL_CONFIG,
|
|
24
25
|
} from './index.js';
|
|
25
26
|
|
|
26
27
|
// Extract tool IDs from their configs (single source of truth)
|
|
@@ -41,6 +42,7 @@ export const USER_SUMMARY_PROMPT_ID = USER_SUMMARY_PROMPT_CONFIG.name;
|
|
|
41
42
|
export const PAPER_SUMMARY_PROMPT_ID = PAPER_SUMMARY_PROMPT_CONFIG.name;
|
|
42
43
|
export const MODEL_DETAIL_PROMPT_ID = MODEL_DETAIL_PROMPT_CONFIG.name;
|
|
43
44
|
export const DATASET_DETAIL_PROMPT_ID = DATASET_DETAIL_PROMPT_CONFIG.name;
|
|
45
|
+
export const HF_JOBS_TOOL_ID = HF_JOBS_TOOL_CONFIG.name;
|
|
44
46
|
|
|
45
47
|
// Complete list of all built-in tool IDs
|
|
46
48
|
export const ALL_BUILTIN_TOOL_IDS = [
|
|
@@ -57,6 +59,7 @@ export const ALL_BUILTIN_TOOL_IDS = [
|
|
|
57
59
|
DOCS_SEMANTIC_SEARCH_TOOL_ID,
|
|
58
60
|
DOC_FETCH_TOOL_ID,
|
|
59
61
|
USE_SPACE_TOOL_ID,
|
|
62
|
+
HF_JOBS_TOOL_ID,
|
|
60
63
|
] as const;
|
|
61
64
|
// Grouped tool IDs for bouquet configurations
|
|
62
65
|
export const TOOL_ID_GROUPS = {
|
|
@@ -67,7 +70,13 @@ export const TOOL_ID_GROUPS = {
|
|
|
67
70
|
PAPER_SEARCH_TOOL_ID,
|
|
68
71
|
DOCS_SEMANTIC_SEARCH_TOOL_ID,
|
|
69
72
|
] as const,
|
|
70
|
-
spaces: [
|
|
73
|
+
spaces: [
|
|
74
|
+
SPACE_SEARCH_TOOL_ID,
|
|
75
|
+
DUPLICATE_SPACE_TOOL_ID,
|
|
76
|
+
SPACE_INFO_TOOL_ID,
|
|
77
|
+
SPACE_FILES_TOOL_ID,
|
|
78
|
+
USE_SPACE_TOOL_ID,
|
|
79
|
+
] as const,
|
|
71
80
|
detail: [MODEL_DETAIL_TOOL_ID, DATASET_DETAIL_TOOL_ID, HUB_INSPECT_TOOL_ID] as const,
|
|
72
81
|
docs: [DOCS_SEMANTIC_SEARCH_TOOL_ID, DOC_FETCH_TOOL_ID] as const,
|
|
73
82
|
hf_api: [
|
|
@@ -77,6 +86,7 @@ export const TOOL_ID_GROUPS = {
|
|
|
77
86
|
PAPER_SEARCH_TOOL_ID,
|
|
78
87
|
HUB_INSPECT_TOOL_ID,
|
|
79
88
|
DOCS_SEMANTIC_SEARCH_TOOL_ID,
|
|
89
|
+
// HF_JOBS_TOOL_ID,
|
|
80
90
|
] as const,
|
|
81
91
|
all: [...ALL_BUILTIN_TOOL_IDS] as const,
|
|
82
92
|
} as const;
|