@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.
Files changed (91) hide show
  1. package/dist/docs-search/docs-semantic-search.d.ts +2 -2
  2. package/dist/docs-search/docs-semantic-search.d.ts.map +1 -1
  3. package/dist/docs-search/docs-semantic-search.js +56 -21
  4. package/dist/docs-search/docs-semantic-search.js.map +1 -1
  5. package/dist/hf-api-call.d.ts.map +1 -1
  6. package/dist/hf-api-call.js +4 -0
  7. package/dist/hf-api-call.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/jobs/api-client.d.ts +19 -0
  13. package/dist/jobs/api-client.d.ts.map +1 -0
  14. package/dist/jobs/api-client.js +104 -0
  15. package/dist/jobs/api-client.js.map +1 -0
  16. package/dist/jobs/commands/inspect.d.ts +5 -0
  17. package/dist/jobs/commands/inspect.d.ts.map +1 -0
  18. package/dist/jobs/commands/inspect.js +21 -0
  19. package/dist/jobs/commands/inspect.js.map +1 -0
  20. package/dist/jobs/commands/logs.d.ts +4 -0
  21. package/dist/jobs/commands/logs.d.ts.map +1 -0
  22. package/dist/jobs/commands/logs.js +24 -0
  23. package/dist/jobs/commands/logs.js.map +1 -0
  24. package/dist/jobs/commands/ps.d.ts +4 -0
  25. package/dist/jobs/commands/ps.d.ts.map +1 -0
  26. package/dist/jobs/commands/ps.js +23 -0
  27. package/dist/jobs/commands/ps.js.map +1 -0
  28. package/dist/jobs/commands/run.d.ts +5 -0
  29. package/dist/jobs/commands/run.d.ts.map +1 -0
  30. package/dist/jobs/commands/run.js +89 -0
  31. package/dist/jobs/commands/run.js.map +1 -0
  32. package/dist/jobs/commands/scheduled.d.ts +10 -0
  33. package/dist/jobs/commands/scheduled.d.ts.map +1 -0
  34. package/dist/jobs/commands/scheduled.js +111 -0
  35. package/dist/jobs/commands/scheduled.js.map +1 -0
  36. package/dist/jobs/commands/utils.d.ts +19 -0
  37. package/dist/jobs/commands/utils.d.ts.map +1 -0
  38. package/dist/jobs/commands/utils.js +99 -0
  39. package/dist/jobs/commands/utils.js.map +1 -0
  40. package/dist/jobs/formatters.d.ts +6 -0
  41. package/dist/jobs/formatters.d.ts.map +1 -0
  42. package/dist/jobs/formatters.js +98 -0
  43. package/dist/jobs/formatters.js.map +1 -0
  44. package/dist/jobs/sse-handler.d.ts +12 -0
  45. package/dist/jobs/sse-handler.d.ts.map +1 -0
  46. package/dist/jobs/sse-handler.js +80 -0
  47. package/dist/jobs/sse-handler.js.map +1 -0
  48. package/dist/jobs/tool.d.ts +35 -0
  49. package/dist/jobs/tool.d.ts.map +1 -0
  50. package/dist/jobs/tool.js +333 -0
  51. package/dist/jobs/tool.js.map +1 -0
  52. package/dist/jobs/types.d.ts +295 -0
  53. package/dist/jobs/types.d.ts.map +1 -0
  54. package/dist/jobs/types.js +95 -0
  55. package/dist/jobs/types.js.map +1 -0
  56. package/dist/tool-ids.d.ts +3 -2
  57. package/dist/tool-ids.d.ts.map +1 -1
  58. package/dist/tool-ids.js +10 -2
  59. package/dist/tool-ids.js.map +1 -1
  60. package/dist/types/tool-result.d.ts +1 -0
  61. package/dist/types/tool-result.d.ts.map +1 -1
  62. package/dist/use-space.d.ts +0 -1
  63. package/dist/use-space.d.ts.map +1 -1
  64. package/dist/use-space.js +0 -1
  65. package/dist/use-space.js.map +1 -1
  66. package/package.json +4 -2
  67. package/src/docs-search/docs-semantic-search.ts +71 -20
  68. package/src/hf-api-call.ts +6 -0
  69. package/src/index.ts +1 -0
  70. package/src/jobs/api-client.ts +195 -0
  71. package/src/jobs/commands/inspect.ts +38 -0
  72. package/src/jobs/commands/logs.ts +36 -0
  73. package/src/jobs/commands/ps.ts +40 -0
  74. package/src/jobs/commands/run.ts +134 -0
  75. package/src/jobs/commands/scheduled.ts +189 -0
  76. package/src/jobs/commands/utils.ts +158 -0
  77. package/src/jobs/formatters.ts +149 -0
  78. package/src/jobs/sse-handler.ts +144 -0
  79. package/src/jobs/tool.ts +435 -0
  80. package/src/jobs/types.ts +237 -0
  81. package/src/tool-ids.ts +11 -1
  82. package/src/types/tool-result.ts +6 -0
  83. package/src/use-space.ts +0 -1
  84. package/test/jobs/command-translation.spec.ts +277 -0
  85. package/test/jobs/formatters.spec.ts +267 -0
  86. package/test/jobs/uv-command.spec.ts +81 -0
  87. package/dist/types/mcp-ui-server-shim.d.ts +0 -37
  88. package/dist/types/mcp-ui-server-shim.d.ts.map +0 -1
  89. package/dist/types/mcp-ui-server-shim.js +0 -2
  90. package/dist/types/mcp-ui-server-shim.js.map +0 -1
  91. package/src/types/mcp-ui-server-shim.ts +0 -35
@@ -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: [SPACE_SEARCH_TOOL_ID, DUPLICATE_SPACE_TOOL_ID, SPACE_INFO_TOOL_ID, SPACE_FILES_TOOL_ID, USE_SPACE_TOOL_ID] as const,
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;