@runpod/mcp-server 4.2.0 → 4.4.0
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/CHANGELOG.md +60 -0
- package/README.md +29 -2
- package/dist/{chunk-DDX42UTT.mjs → chunk-4GF3CMSH.mjs} +6 -2
- package/dist/{chunk-DDX42UTT.mjs.map → chunk-4GF3CMSH.mjs.map} +1 -1
- package/dist/http.cjs +1330 -255
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +22 -6
- package/dist/http.d.ts +22 -6
- package/dist/http.mjs +1328 -254
- package/dist/http.mjs.map +1 -1
- package/dist/stdio.cjs +1296 -236
- package/dist/stdio.cjs.map +1 -1
- package/dist/stdio.mjs +1084 -229
- package/dist/stdio.mjs.map +1 -1
- package/dist/{wizard-YYU3OXFW.mjs → wizard-KKTBTVXE.mjs} +204 -5
- package/dist/wizard-KKTBTVXE.mjs.map +1 -0
- package/package.json +6 -3
- package/dist/wizard-YYU3OXFW.mjs.map +0 -1
package/dist/http.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
// src/http.ts
|
|
2
2
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
|
+
import {
|
|
4
|
+
CallToolRequestSchema as CallToolRequestSchema2,
|
|
5
|
+
InitializeRequestSchema,
|
|
6
|
+
JSONRPCMessageSchema
|
|
7
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
3
8
|
|
|
4
9
|
// src/specgen/server.ts
|
|
5
10
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -87,11 +92,11 @@ function readParams(params) {
|
|
|
87
92
|
}
|
|
88
93
|
return { values, unreadable };
|
|
89
94
|
}
|
|
90
|
-
function parseExhaustedWindows(
|
|
91
|
-
if (!
|
|
95
|
+
function parseExhaustedWindows(header2) {
|
|
96
|
+
if (!header2) return { windows: [], dropped: false };
|
|
92
97
|
const windows = [];
|
|
93
98
|
let dropped = false;
|
|
94
|
-
for (const item of splitOutsideStrings(
|
|
99
|
+
for (const item of splitOutsideStrings(header2, ",")) {
|
|
95
100
|
if (item.trim() === "") continue;
|
|
96
101
|
const [rawName, ...params] = splitOutsideStrings(item, ";");
|
|
97
102
|
if (!params.every(isWellFormedParam)) {
|
|
@@ -209,10 +214,13 @@ function validateArguments(inputSchema, args) {
|
|
|
209
214
|
async function dispatchGeneratedTool(client, tool, args) {
|
|
210
215
|
const rejected = validateArguments(tool.inputSchema, args);
|
|
211
216
|
if (rejected) return rejected;
|
|
217
|
+
const required = new Set(tool.inputSchema.required ?? []);
|
|
212
218
|
const pathParams = {};
|
|
213
219
|
const query = {};
|
|
214
220
|
for (const param of tool.params) {
|
|
215
221
|
if (args[param.name] === void 0) continue;
|
|
222
|
+
if (param.location === "query" && !required.has(param.name) && isEmptyValue(args[param.name]))
|
|
223
|
+
continue;
|
|
216
224
|
if (param.location === "path") {
|
|
217
225
|
pathParams[param.name] = args[param.name];
|
|
218
226
|
continue;
|
|
@@ -234,6 +242,11 @@ async function dispatchGeneratedTool(client, tool, args) {
|
|
|
234
242
|
};
|
|
235
243
|
}
|
|
236
244
|
}
|
|
245
|
+
if (tool.hasBody && requestBody !== void 0) {
|
|
246
|
+
const properties = tool.inputSchema.properties ?? {};
|
|
247
|
+
const defs = tool.inputSchema.$defs ?? {};
|
|
248
|
+
requestBody = coerceScalars(requestBody, properties.body, defs);
|
|
249
|
+
}
|
|
237
250
|
const verbs = client;
|
|
238
251
|
const { data, error, response } = await verbs[tool.method](tool.path, {
|
|
239
252
|
params: { path: pathParams, query },
|
|
@@ -246,6 +259,79 @@ async function dispatchGeneratedTool(client, tool, args) {
|
|
|
246
259
|
payload: data ?? { status: response.status }
|
|
247
260
|
};
|
|
248
261
|
}
|
|
262
|
+
function isEmptyValue(value) {
|
|
263
|
+
return value === null || value === "" || Array.isArray(value) && !value.length;
|
|
264
|
+
}
|
|
265
|
+
function asSchema(value) {
|
|
266
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
267
|
+
}
|
|
268
|
+
function resolveSchema(schema, defs, depth = 0) {
|
|
269
|
+
const node = asSchema(schema);
|
|
270
|
+
if (!node || depth > 16) return node;
|
|
271
|
+
const ref = node.$ref;
|
|
272
|
+
if (typeof ref === "string" && ref.startsWith("#/$defs/"))
|
|
273
|
+
return resolveSchema(defs[ref.slice("#/$defs/".length)], defs, depth + 1);
|
|
274
|
+
return node;
|
|
275
|
+
}
|
|
276
|
+
function branches(schema, defs, depth = 0) {
|
|
277
|
+
const node = resolveSchema(schema, defs);
|
|
278
|
+
if (!node || depth > 16) return [];
|
|
279
|
+
const out = [node];
|
|
280
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
281
|
+
const list = node[key];
|
|
282
|
+
if (Array.isArray(list))
|
|
283
|
+
for (const sub of list) out.push(...branches(sub, defs, depth + 1));
|
|
284
|
+
}
|
|
285
|
+
return out;
|
|
286
|
+
}
|
|
287
|
+
function types(schemas) {
|
|
288
|
+
const out = /* @__PURE__ */ new Set();
|
|
289
|
+
for (const s of schemas) {
|
|
290
|
+
if (typeof s.type === "string") out.add(s.type);
|
|
291
|
+
else if (Array.isArray(s.type)) {
|
|
292
|
+
for (const t of s.type) if (typeof t === "string") out.add(t);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return out;
|
|
296
|
+
}
|
|
297
|
+
var NUMERIC = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
298
|
+
function coerceScalars(value, schema, defs, depth = 0) {
|
|
299
|
+
if (depth > 32) return value;
|
|
300
|
+
const applicable = branches(schema, defs);
|
|
301
|
+
if (!applicable.length) return value;
|
|
302
|
+
const allowed = types(applicable);
|
|
303
|
+
if (typeof value === "string") {
|
|
304
|
+
if (allowed.has("string")) return value;
|
|
305
|
+
if ((allowed.has("integer") || allowed.has("number")) && NUMERIC.test(value)) {
|
|
306
|
+
const n = Number(value);
|
|
307
|
+
if (allowed.has("number") || Number.isInteger(n)) return n;
|
|
308
|
+
}
|
|
309
|
+
if (allowed.has("boolean") && (value === "true" || value === "false"))
|
|
310
|
+
return value === "true";
|
|
311
|
+
return value;
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray(value)) {
|
|
314
|
+
const items = applicable.map((s) => s.items).filter(Boolean);
|
|
315
|
+
if (!items.length) return value;
|
|
316
|
+
return value.map(
|
|
317
|
+
(item) => coerceScalars(item, { anyOf: items }, defs, depth + 1)
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const object = asSchema(value);
|
|
321
|
+
if (!object) return value;
|
|
322
|
+
const out = {};
|
|
323
|
+
for (const [key, child] of Object.entries(object)) {
|
|
324
|
+
const childSchemas = [];
|
|
325
|
+
for (const s of applicable) {
|
|
326
|
+
const props = asSchema(s.properties);
|
|
327
|
+
if (props && key in props) childSchemas.push(props[key]);
|
|
328
|
+
else if (asSchema(s.additionalProperties))
|
|
329
|
+
childSchemas.push(s.additionalProperties);
|
|
330
|
+
}
|
|
331
|
+
out[key] = childSchemas.length ? coerceScalars(child, { anyOf: childSchemas }, defs, depth + 1) : child;
|
|
332
|
+
}
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
249
335
|
|
|
250
336
|
// src/specgen/generated/tools.gen.ts
|
|
251
337
|
var generatedTools = [
|
|
@@ -263,6 +349,7 @@ var generatedTools = [
|
|
|
263
349
|
idempotentHint: false,
|
|
264
350
|
openWorldHint: true
|
|
265
351
|
},
|
|
352
|
+
schemaOnDemand: true,
|
|
266
353
|
inputSchema: {
|
|
267
354
|
type: "object",
|
|
268
355
|
properties: {
|
|
@@ -274,11 +361,10 @@ var generatedTools = [
|
|
|
274
361
|
$defs: {
|
|
275
362
|
BaseContainerConfig: {
|
|
276
363
|
type: "object",
|
|
277
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
278
364
|
properties: {
|
|
279
365
|
args: {
|
|
280
366
|
type: "string",
|
|
281
|
-
description: 'The container\'s command
|
|
367
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
282
368
|
examples: [
|
|
283
369
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
284
370
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -290,7 +376,7 @@ var generatedTools = [
|
|
|
290
376
|
items: {
|
|
291
377
|
type: "string"
|
|
292
378
|
},
|
|
293
|
-
description: "Container CMD in exec form
|
|
379
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
294
380
|
examples: [
|
|
295
381
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
296
382
|
]
|
|
@@ -300,7 +386,7 @@ var generatedTools = [
|
|
|
300
386
|
items: {
|
|
301
387
|
type: "string"
|
|
302
388
|
},
|
|
303
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
389
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
304
390
|
examples: [["/bin/bash", "-c"]]
|
|
305
391
|
},
|
|
306
392
|
disk: {
|
|
@@ -336,6 +422,21 @@ var generatedTools = [
|
|
|
336
422
|
}
|
|
337
423
|
}
|
|
338
424
|
},
|
|
425
|
+
BaseMounts: {
|
|
426
|
+
type: "object",
|
|
427
|
+
properties: {
|
|
428
|
+
persistent: {
|
|
429
|
+
$ref: "#/$defs/PersistentMount"
|
|
430
|
+
},
|
|
431
|
+
network: {
|
|
432
|
+
type: "array",
|
|
433
|
+
maxItems: 1,
|
|
434
|
+
items: {
|
|
435
|
+
$ref: "#/$defs/NetworkMount"
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
},
|
|
339
440
|
ClusterCompute: {
|
|
340
441
|
type: "object",
|
|
341
442
|
additionalProperties: false,
|
|
@@ -363,6 +464,15 @@ var generatedTools = [
|
|
|
363
464
|
}
|
|
364
465
|
}
|
|
365
466
|
},
|
|
467
|
+
ClusterMounts: {
|
|
468
|
+
description: "Storage mounts for a cluster create: `persistent` or `network`, not both. Clusters cannot mount global volumes, so `global` is rejected.",
|
|
469
|
+
allOf: [
|
|
470
|
+
{
|
|
471
|
+
$ref: "#/$defs/BaseMounts"
|
|
472
|
+
}
|
|
473
|
+
],
|
|
474
|
+
unevaluatedProperties: false
|
|
475
|
+
},
|
|
366
476
|
ClusterType: {
|
|
367
477
|
type: "string",
|
|
368
478
|
description: "Cluster type. TRAINING is the generic distributed-training cluster; SLURM provisions a managed Slurm controller/compute topology; RAY provisions a managed Ray head/worker topology; APPLICATION is a general multi-node application cluster.",
|
|
@@ -377,7 +487,7 @@ var generatedTools = [
|
|
|
377
487
|
{
|
|
378
488
|
type: "object",
|
|
379
489
|
required: ["name", "type", "compute"],
|
|
380
|
-
description: "Request body for creating a cluster. `compute` defines the
|
|
490
|
+
description: "Request body for creating a cluster. `compute` defines the homogeneous pod shape; the container configuration (image, env, ports, \u2026) applies to every pod.",
|
|
381
491
|
properties: {
|
|
382
492
|
compute: {
|
|
383
493
|
$ref: "#/$defs/ClusterCompute"
|
|
@@ -393,7 +503,7 @@ var generatedTools = [
|
|
|
393
503
|
templateId: {
|
|
394
504
|
type: "string",
|
|
395
505
|
minLength: 1,
|
|
396
|
-
description: "ID of a pod template to provision every member pod from
|
|
506
|
+
description: "ID of a pod template to provision every member pod from: it supplies the container settings (image, args, disk, env, ports) and the registry credential for private images \u2014 the only private-image path for clusters. Mutually exclusive with the inline container fields (`image`, `args`, `entrypoint`, `cmd`, `disk`, `env`, `ports`, `mounts`). Must be a non-serverless template you can access.",
|
|
397
507
|
examples: ["30zmvf89kd"]
|
|
398
508
|
},
|
|
399
509
|
dataCenterIds: {
|
|
@@ -401,11 +511,11 @@ var generatedTools = [
|
|
|
401
511
|
items: {
|
|
402
512
|
type: "string"
|
|
403
513
|
},
|
|
404
|
-
description: "Preferred data centers for placement. Omit or pass an empty
|
|
514
|
+
description: "Preferred data centers for placement. Omit or pass an empty array to let the scheduler choose. A cluster is always placed within a single data center.",
|
|
405
515
|
example: ["US-TX-3"]
|
|
406
516
|
},
|
|
407
517
|
mounts: {
|
|
408
|
-
$ref: "#/$defs/
|
|
518
|
+
$ref: "#/$defs/ClusterMounts"
|
|
409
519
|
},
|
|
410
520
|
startJupyter: {
|
|
411
521
|
type: "boolean",
|
|
@@ -422,28 +532,11 @@ var generatedTools = [
|
|
|
422
532
|
],
|
|
423
533
|
unevaluatedProperties: false
|
|
424
534
|
},
|
|
425
|
-
Mounts: {
|
|
426
|
-
type: "object",
|
|
427
|
-
additionalProperties: false,
|
|
428
|
-
description: "Storage mounts attached to a pod. At-most-one of `persistent` or\n`network` may be set today (mutually exclusive, enforced at the\nhandler with 400 if both are present). The `network` field is an\narray for forward compatibility with eventual multi-network-volume\nsupport, but `maxItems` is 1 today.\n\nPATCH semantics:\n- Omitting `mounts` or sending `{}` leaves the existing mount\n unchanged.\n- An explicit `network: []` is rejected with 400 (clearing mounts\n is not supported).\n- Mount kind is fixed at create \u2014 a PATCH that introduces a kind\n not present at create (persistent on a network pod, network on\n a persistent pod, or any mount on a previously-mountless pod)\n is rejected with 400.\n- The `volumeId` of a network mount is immutable; a PATCH that\n names a different `volumeId` is rejected with 400.\n- Partial mounts are not supported \u2014 every mount entry must\n include the full schema (`size` + `path` for persistent,\n `volumeId` + `path` for network). Missing required fields \u2192 422.\n",
|
|
429
|
-
properties: {
|
|
430
|
-
persistent: {
|
|
431
|
-
$ref: "#/$defs/PersistentMount"
|
|
432
|
-
},
|
|
433
|
-
network: {
|
|
434
|
-
type: "array",
|
|
435
|
-
maxItems: 1,
|
|
436
|
-
items: {
|
|
437
|
-
$ref: "#/$defs/NetworkMount"
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
},
|
|
442
535
|
NetworkMount: {
|
|
443
536
|
type: "object",
|
|
444
537
|
required: ["volumeId", "path"],
|
|
445
538
|
additionalProperties: false,
|
|
446
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
539
|
+
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on both GPU and CPU pods. The underlying `volumeId` is immutable post-create; the mount `path` may be changed via PATCH.",
|
|
447
540
|
properties: {
|
|
448
541
|
volumeId: {
|
|
449
542
|
type: "string",
|
|
@@ -461,7 +554,7 @@ var generatedTools = [
|
|
|
461
554
|
type: "object",
|
|
462
555
|
required: ["size", "path"],
|
|
463
556
|
additionalProperties: false,
|
|
464
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
557
|
+
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data does not survive a host failure. Disallowed on CPU pods. Mutually exclusive with NetworkMount. Deprecated: prefer NetworkMount for any data you cannot recreate.",
|
|
465
558
|
properties: {
|
|
466
559
|
size: {
|
|
467
560
|
type: "integer",
|
|
@@ -538,6 +631,7 @@ var generatedTools = [
|
|
|
538
631
|
idempotentHint: false,
|
|
539
632
|
openWorldHint: true
|
|
540
633
|
},
|
|
634
|
+
schemaOnDemand: true,
|
|
541
635
|
inputSchema: {
|
|
542
636
|
type: "object",
|
|
543
637
|
properties: {
|
|
@@ -549,11 +643,10 @@ var generatedTools = [
|
|
|
549
643
|
$defs: {
|
|
550
644
|
BaseContainerConfig: {
|
|
551
645
|
type: "object",
|
|
552
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
553
646
|
properties: {
|
|
554
647
|
args: {
|
|
555
648
|
type: "string",
|
|
556
|
-
description: 'The container\'s command
|
|
649
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
557
650
|
examples: [
|
|
558
651
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
559
652
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -565,7 +658,7 @@ var generatedTools = [
|
|
|
565
658
|
items: {
|
|
566
659
|
type: "string"
|
|
567
660
|
},
|
|
568
|
-
description: "Container CMD in exec form
|
|
661
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
569
662
|
examples: [
|
|
570
663
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
571
664
|
]
|
|
@@ -575,7 +668,7 @@ var generatedTools = [
|
|
|
575
668
|
items: {
|
|
576
669
|
type: "string"
|
|
577
670
|
},
|
|
578
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
671
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
579
672
|
examples: [["/bin/bash", "-c"]]
|
|
580
673
|
},
|
|
581
674
|
disk: {
|
|
@@ -635,7 +728,7 @@ var generatedTools = [
|
|
|
635
728
|
pools: {
|
|
636
729
|
type: "array",
|
|
637
730
|
minItems: 1,
|
|
638
|
-
description:
|
|
731
|
+
description: "Serverless GPU pool IDs (the `pool` field of `list-gpu-types`). Workers are placed on whichever listed pool has capacity; narrow to specific cards with `excludedTypes`. On update, `pools` and `excludedTypes` are replaced together, so sending `pools` alone clears the exclusions.",
|
|
639
732
|
items: {
|
|
640
733
|
type: "string"
|
|
641
734
|
},
|
|
@@ -644,7 +737,7 @@ var generatedTools = [
|
|
|
644
737
|
excludedTypes: {
|
|
645
738
|
type: "array",
|
|
646
739
|
uniqueItems: true,
|
|
647
|
-
description:
|
|
740
|
+
description: "GPU type IDs to subtract from the selected pools \u2014 the `id` field of `list-gpu-types`, the same identifiers pods take in `gpu.id`. Workers run on every type in `pools` except these; omit to use the whole pool. A value outside `pools` is rejected. On update, restate them whenever you send `pools`, or they are cleared.",
|
|
648
741
|
items: {
|
|
649
742
|
type: "string",
|
|
650
743
|
pattern: "^\\s*[^-\\s]"
|
|
@@ -661,7 +754,6 @@ var generatedTools = [
|
|
|
661
754
|
}
|
|
662
755
|
},
|
|
663
756
|
ContainerConfig: {
|
|
664
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
665
757
|
allOf: [
|
|
666
758
|
{
|
|
667
759
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -687,7 +779,7 @@ var generatedTools = [
|
|
|
687
779
|
unevaluatedProperties: false
|
|
688
780
|
},
|
|
689
781
|
CreateEndpointGpuConfig: {
|
|
690
|
-
description: "GPU request for an endpoint create. Carries the CUDA constraints, which
|
|
782
|
+
description: "GPU request for an endpoint create. Carries the CUDA constraints, which live here rather than at the body's top level so they are unrepresentable on a CPU endpoint.",
|
|
691
783
|
allOf: [
|
|
692
784
|
{
|
|
693
785
|
$ref: "#/$defs/BaseEndpointGpuConfig"
|
|
@@ -702,13 +794,13 @@ var generatedTools = [
|
|
|
702
794
|
type: "string",
|
|
703
795
|
pattern: "^\\d+\\.\\d+$"
|
|
704
796
|
},
|
|
705
|
-
description: "Acceptable CUDA versions for worker placement, as
|
|
797
|
+
description: "Acceptable CUDA versions for worker placement, as `major.minor`. Omit to accept any version (or inherit the template's constraint when creating from `templateId`).",
|
|
706
798
|
examples: [["12.8", "12.6"]]
|
|
707
799
|
},
|
|
708
800
|
minCudaVersion: {
|
|
709
801
|
type: "string",
|
|
710
802
|
pattern: "^\\d+\\.\\d+$",
|
|
711
|
-
description: "Lowest acceptable CUDA version for worker placement, as
|
|
803
|
+
description: "Lowest acceptable CUDA version for worker placement, as `major.minor`, compared numerically rather than as a decimal \u2014 so 12.11 is above 12.2. Use this for an open-ended floor and allowedCudaVersions for an exact set.",
|
|
712
804
|
examples: ["12.1"]
|
|
713
805
|
}
|
|
714
806
|
}
|
|
@@ -752,13 +844,13 @@ var generatedTools = [
|
|
|
752
844
|
$ref: "#/$defs/EndpointType"
|
|
753
845
|
}
|
|
754
846
|
],
|
|
755
|
-
description: "Request-routing model. Required \u2014 it determines the valid scaler
|
|
847
|
+
description: "Request-routing model. Required \u2014 it determines the valid scaler and request URLs, so it must be chosen explicitly on every create."
|
|
756
848
|
},
|
|
757
849
|
cpu: {
|
|
758
850
|
type: "array",
|
|
759
851
|
minItems: 1,
|
|
760
852
|
uniqueItems: true,
|
|
761
|
-
description: "Eligible CPU configurations for each worker. Memory is derived from the
|
|
853
|
+
description: "Eligible CPU configurations for each worker. Memory is derived from the selected flavor's catalog RAM multiplier. Exact duplicate configurations are rejected; the same flavor may be listed at different vCPU counts.",
|
|
762
854
|
items: {
|
|
763
855
|
$ref: "#/$defs/CreateCpuConfig"
|
|
764
856
|
}
|
|
@@ -782,12 +874,17 @@ var generatedTools = [
|
|
|
782
874
|
type: "array",
|
|
783
875
|
items: {
|
|
784
876
|
type: "string"
|
|
785
|
-
}
|
|
877
|
+
},
|
|
878
|
+
description: "Network volume IDs.",
|
|
879
|
+
deprecated: true
|
|
880
|
+
},
|
|
881
|
+
mounts: {
|
|
882
|
+
$ref: "#/$defs/EndpointMountsInput"
|
|
786
883
|
},
|
|
787
884
|
templateId: {
|
|
788
885
|
type: "string",
|
|
789
886
|
minLength: 1,
|
|
790
|
-
description: "ID of a serverless template to base this endpoint on
|
|
887
|
+
description: "ID of a serverless template to base this endpoint on (must be serverless). Its container settings (image, args, disk, ports, env, registry) fill in what this body omits; body fields win, and `env` merges per key with body winning. Its allowedCudaVersions seeds `gpu.allowedCudaVersions` when the body omits it; pod-only flags are ignored. Copied once: later edits do not apply.",
|
|
791
888
|
examples: ["30zmvf89kd"]
|
|
792
889
|
},
|
|
793
890
|
timeout: {
|
|
@@ -835,8 +932,42 @@ var generatedTools = [
|
|
|
835
932
|
}
|
|
836
933
|
}
|
|
837
934
|
},
|
|
935
|
+
EndpointMount: {
|
|
936
|
+
type: "object",
|
|
937
|
+
required: ["volumeId"],
|
|
938
|
+
additionalProperties: false,
|
|
939
|
+
description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
|
|
940
|
+
properties: {
|
|
941
|
+
volumeId: {
|
|
942
|
+
type: "string",
|
|
943
|
+
description: "ID of a NetworkVolume (under `network`) or GlobalVolume (under `global`).",
|
|
944
|
+
examples: ["vol_abc"]
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
},
|
|
948
|
+
EndpointMountsInput: {
|
|
949
|
+
type: "object",
|
|
950
|
+
additionalProperties: false,
|
|
951
|
+
description: "Volumes to mount on the endpoint's workers. A `network` or `global` list that is present replaces the endpoint's current list of that kind; an empty list detaches it, and an omitted list is left unchanged.",
|
|
952
|
+
properties: {
|
|
953
|
+
network: {
|
|
954
|
+
type: "array",
|
|
955
|
+
description: "Network volumes, at most one per data center.",
|
|
956
|
+
items: {
|
|
957
|
+
$ref: "#/$defs/EndpointMount"
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
global: {
|
|
961
|
+
type: "array",
|
|
962
|
+
maxItems: 1,
|
|
963
|
+
items: {
|
|
964
|
+
$ref: "#/$defs/EndpointMount"
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
},
|
|
838
969
|
EndpointScaling: {
|
|
839
|
-
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY
|
|
970
|
+
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY` (queue-based endpoints only) or `REQUEST_COUNT`. The scaler is chosen independently of the endpoint's routing `type` and can be switched on update.",
|
|
840
971
|
oneOf: [
|
|
841
972
|
{
|
|
842
973
|
$ref: "#/$defs/QueueDelayScaling"
|
|
@@ -855,7 +986,7 @@ var generatedTools = [
|
|
|
855
986
|
},
|
|
856
987
|
EndpointType: {
|
|
857
988
|
type: "string",
|
|
858
|
-
description: "Request-routing semantics for a modern serverless endpoint
|
|
989
|
+
description: "Request-routing semantics for a modern serverless endpoint. `QUEUE` \u2014 submit asynchronous or synchronous jobs through the managed queue. `LOAD_BALANCER` \u2014 send requests directly to worker-defined HTTP paths.",
|
|
859
990
|
"x-enum-varnames": ["EndpointTypeQueue", "EndpointTypeLoadBalancer"],
|
|
860
991
|
enum: ["QUEUE", "LOAD_BALANCER"]
|
|
861
992
|
},
|
|
@@ -879,14 +1010,14 @@ var generatedTools = [
|
|
|
879
1010
|
type: "integer",
|
|
880
1011
|
minimum: 1,
|
|
881
1012
|
maximum: 3600,
|
|
882
|
-
description: "Seconds before idle workers scale down. Not applicable to queue-based
|
|
1013
|
+
description: "Seconds before idle workers scale down. Not applicable to queue-based endpoints scaling on `requestCount` \u2014 rejected on create/update and omitted from responses for that combination.",
|
|
883
1014
|
examples: [5]
|
|
884
1015
|
}
|
|
885
1016
|
}
|
|
886
1017
|
},
|
|
887
1018
|
FlashBoot: {
|
|
888
1019
|
type: "string",
|
|
889
|
-
description: "FlashBoot cold-start acceleration mode
|
|
1020
|
+
description: "FlashBoot cold-start acceleration mode. `OFF` \u2014 disabled. `FLASHBOOT` \u2014 enabled. `PRIORITY_FLASHBOOT` \u2014 enabled with priority capacity",
|
|
890
1021
|
enum: ["OFF", "FLASHBOOT", "PRIORITY_FLASHBOOT"]
|
|
891
1022
|
},
|
|
892
1023
|
QueueDelayScaling: {
|
|
@@ -912,7 +1043,7 @@ var generatedTools = [
|
|
|
912
1043
|
RequestCountScaling: {
|
|
913
1044
|
type: "object",
|
|
914
1045
|
additionalProperties: false,
|
|
915
|
-
description: "Scale on concurrent in-flight requests per worker. Required for
|
|
1046
|
+
description: "Scale on concurrent in-flight requests per worker. Required for load-balancing endpoints; also selectable for queue-based.",
|
|
916
1047
|
required: ["type", "requestCount"],
|
|
917
1048
|
properties: {
|
|
918
1049
|
type: {
|
|
@@ -931,6 +1062,47 @@ var generatedTools = [
|
|
|
931
1062
|
}
|
|
932
1063
|
}
|
|
933
1064
|
},
|
|
1065
|
+
{
|
|
1066
|
+
name: "create-global-volume",
|
|
1067
|
+
operationId: "createGlobalVolume",
|
|
1068
|
+
description: "Create a global volume. Provisions a new global volume \u2014 storage that mounts into workloads in any data center. Only a `name` is required; storage is provisioned for you. Accounts have a cap on how many global volumes they can hold; creating one past it fails with `400`. Returns `201` with the created global volume, including its assigned `id`.",
|
|
1069
|
+
method: "POST",
|
|
1070
|
+
path: "/v2/global-volumes",
|
|
1071
|
+
params: [],
|
|
1072
|
+
hasBody: true,
|
|
1073
|
+
annotations: {
|
|
1074
|
+
readOnlyHint: false,
|
|
1075
|
+
destructiveHint: false,
|
|
1076
|
+
idempotentHint: false,
|
|
1077
|
+
openWorldHint: true
|
|
1078
|
+
},
|
|
1079
|
+
inputSchema: {
|
|
1080
|
+
type: "object",
|
|
1081
|
+
properties: {
|
|
1082
|
+
body: {
|
|
1083
|
+
$ref: "#/$defs/CreateGlobalVolumeRequest"
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
required: ["body"],
|
|
1087
|
+
$defs: {
|
|
1088
|
+
CreateGlobalVolumeRequest: {
|
|
1089
|
+
type: "object",
|
|
1090
|
+
additionalProperties: false,
|
|
1091
|
+
required: ["name"],
|
|
1092
|
+
properties: {
|
|
1093
|
+
name: {
|
|
1094
|
+
type: "string",
|
|
1095
|
+
minLength: 1,
|
|
1096
|
+
maxLength: 191,
|
|
1097
|
+
pattern: "[^\\p{Z}\\t-\\r\x85]",
|
|
1098
|
+
description: "Human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
|
|
1099
|
+
examples: ["training-data"]
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
934
1106
|
{
|
|
935
1107
|
name: "create-network-volume",
|
|
936
1108
|
operationId: "createNetworkVolume",
|
|
@@ -984,7 +1156,7 @@ var generatedTools = [
|
|
|
984
1156
|
$ref: "#/$defs/VolumeType"
|
|
985
1157
|
}
|
|
986
1158
|
],
|
|
987
|
-
description: "Storage tier for the volume. Optional. When omitted, the volume is
|
|
1159
|
+
description: "Storage tier for the volume. Optional. When omitted, the volume is provisioned using the requested data center's default (primary) storage tier."
|
|
988
1160
|
}
|
|
989
1161
|
}
|
|
990
1162
|
},
|
|
@@ -1010,6 +1182,7 @@ var generatedTools = [
|
|
|
1010
1182
|
idempotentHint: false,
|
|
1011
1183
|
openWorldHint: true
|
|
1012
1184
|
},
|
|
1185
|
+
schemaOnDemand: true,
|
|
1013
1186
|
inputSchema: {
|
|
1014
1187
|
type: "object",
|
|
1015
1188
|
properties: {
|
|
@@ -1021,11 +1194,10 @@ var generatedTools = [
|
|
|
1021
1194
|
$defs: {
|
|
1022
1195
|
BaseContainerConfig: {
|
|
1023
1196
|
type: "object",
|
|
1024
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
1025
1197
|
properties: {
|
|
1026
1198
|
args: {
|
|
1027
1199
|
type: "string",
|
|
1028
|
-
description: 'The container\'s command
|
|
1200
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
1029
1201
|
examples: [
|
|
1030
1202
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
1031
1203
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -1037,7 +1209,7 @@ var generatedTools = [
|
|
|
1037
1209
|
items: {
|
|
1038
1210
|
type: "string"
|
|
1039
1211
|
},
|
|
1040
|
-
description: "Container CMD in exec form
|
|
1212
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
1041
1213
|
examples: [
|
|
1042
1214
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
1043
1215
|
]
|
|
@@ -1047,7 +1219,7 @@ var generatedTools = [
|
|
|
1047
1219
|
items: {
|
|
1048
1220
|
type: "string"
|
|
1049
1221
|
},
|
|
1050
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
1222
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
1051
1223
|
examples: [["/bin/bash", "-c"]]
|
|
1052
1224
|
},
|
|
1053
1225
|
disk: {
|
|
@@ -1119,13 +1291,27 @@ var generatedTools = [
|
|
|
1119
1291
|
}
|
|
1120
1292
|
}
|
|
1121
1293
|
},
|
|
1294
|
+
BaseMounts: {
|
|
1295
|
+
type: "object",
|
|
1296
|
+
properties: {
|
|
1297
|
+
persistent: {
|
|
1298
|
+
$ref: "#/$defs/PersistentMount"
|
|
1299
|
+
},
|
|
1300
|
+
network: {
|
|
1301
|
+
type: "array",
|
|
1302
|
+
maxItems: 1,
|
|
1303
|
+
items: {
|
|
1304
|
+
$ref: "#/$defs/NetworkMount"
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
},
|
|
1122
1309
|
Cloud: {
|
|
1123
1310
|
type: "string",
|
|
1124
|
-
description: "Cloud tier
|
|
1311
|
+
description: "Cloud tier. `SECURE` \u2014 Runpod-owned datacenter hardware. `COMMUNITY` \u2014 community-hosted hardware",
|
|
1125
1312
|
enum: ["SECURE", "COMMUNITY"]
|
|
1126
1313
|
},
|
|
1127
1314
|
ContainerConfig: {
|
|
1128
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
1129
1315
|
allOf: [
|
|
1130
1316
|
{
|
|
1131
1317
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -1151,7 +1337,7 @@ var generatedTools = [
|
|
|
1151
1337
|
unevaluatedProperties: false
|
|
1152
1338
|
},
|
|
1153
1339
|
CreateGpuConfig: {
|
|
1154
|
-
description: "GPU request for a pod create. Carries the CUDA host constraints, which
|
|
1340
|
+
description: "GPU request for a pod create. Carries the CUDA host constraints, which live here rather than at the body's top level so they are unrepresentable on a CPU pod.",
|
|
1155
1341
|
allOf: [
|
|
1156
1342
|
{
|
|
1157
1343
|
$ref: "#/$defs/BaseGpuConfig"
|
|
@@ -1165,13 +1351,13 @@ var generatedTools = [
|
|
|
1165
1351
|
type: "string",
|
|
1166
1352
|
pattern: "^\\d+\\.\\d+$"
|
|
1167
1353
|
},
|
|
1168
|
-
description: "Acceptable CUDA versions for the host machine, as `major.minor
|
|
1354
|
+
description: "Acceptable CUDA versions for the host machine, as `major.minor`. Omit to accept any version.",
|
|
1169
1355
|
examples: [["12.8", "12.6"]]
|
|
1170
1356
|
},
|
|
1171
1357
|
minCudaVersion: {
|
|
1172
1358
|
type: "string",
|
|
1173
1359
|
pattern: "^\\d+\\.\\d+$",
|
|
1174
|
-
description: "Lowest acceptable CUDA version for the host machine, as
|
|
1360
|
+
description: "Lowest acceptable CUDA version for the host machine, as `major.minor`, compared numerically rather than as a decimal \u2014 so 12.11 is above 12.2. Use this for an open-ended floor and allowedCudaVersions for an exact set.",
|
|
1175
1361
|
examples: ["12.1"]
|
|
1176
1362
|
},
|
|
1177
1363
|
minRamPerGpu: {
|
|
@@ -1199,7 +1385,7 @@ var generatedTools = [
|
|
|
1199
1385
|
{
|
|
1200
1386
|
type: "object",
|
|
1201
1387
|
required: ["name"],
|
|
1202
|
-
description: "Request body for creating a pod. Exactly one of `gpu` or `cpu
|
|
1388
|
+
description: "Request body for creating a pod. Exactly one of `gpu` or `cpu` must be set \u2014 enforced at the handler layer.",
|
|
1203
1389
|
properties: {
|
|
1204
1390
|
name: {
|
|
1205
1391
|
type: "string",
|
|
@@ -1223,13 +1409,13 @@ var generatedTools = [
|
|
|
1223
1409
|
items: {
|
|
1224
1410
|
type: "string"
|
|
1225
1411
|
},
|
|
1226
|
-
description: "Preferred data centers for placement. Omit or pass an empty
|
|
1412
|
+
description: "Preferred data centers for placement. Omit or pass an empty array to let the scheduler choose.",
|
|
1227
1413
|
examples: [["US-TX-3"]]
|
|
1228
1414
|
},
|
|
1229
1415
|
globalNetworking: {
|
|
1230
1416
|
type: "boolean",
|
|
1231
1417
|
default: false,
|
|
1232
|
-
description: "Enable global networking, giving the pod a private IP reachable across data centers. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream).
|
|
1418
|
+
description: "Enable global networking, giving the pod a private IP reachable across data centers. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream).",
|
|
1233
1419
|
examples: [false]
|
|
1234
1420
|
},
|
|
1235
1421
|
gpu: {
|
|
@@ -1241,19 +1427,19 @@ var generatedTools = [
|
|
|
1241
1427
|
startJupyter: {
|
|
1242
1428
|
type: "boolean",
|
|
1243
1429
|
default: false,
|
|
1244
|
-
description: "Create-time flag
|
|
1430
|
+
description: "Create-time flag: starts JupyterLab by injecting a generated `JUPYTER_PASSWORD` environment variable, unless the request sets one. Expose `8888/http` in `ports` to reach it.",
|
|
1245
1431
|
examples: [true]
|
|
1246
1432
|
},
|
|
1247
1433
|
startSsh: {
|
|
1248
1434
|
type: "boolean",
|
|
1249
1435
|
default: false,
|
|
1250
|
-
description: "Create-time flag
|
|
1436
|
+
description: "Create-time flag: sets up SSH access by injecting a `PUBLIC_KEY` environment variable with your account's registered SSH keys (`update-ssh-keys`), unless the request sets one. With no registered keys it does nothing and the pod has no SSH access. Direct SSH also needs a `22/tcp` entry in `ports`.",
|
|
1251
1437
|
examples: [true]
|
|
1252
1438
|
},
|
|
1253
1439
|
templateId: {
|
|
1254
1440
|
type: "string",
|
|
1255
1441
|
minLength: 1,
|
|
1256
|
-
description: "ID of a pod template to base this pod on
|
|
1442
|
+
description: "ID of a pod template to base this pod on (not a serverless one). Its container settings (image, args, disk, ports, env, registry, persistent mount) fill in what this body omits; body fields win, and `env` merges per key with body winning. A CUDA field in `gpu` replaces the template's CUDA constraint; CPU pods ignore its mount. Copied once: later template edits do not affect the pod.",
|
|
1257
1443
|
examples: ["30zmvf89kd"]
|
|
1258
1444
|
}
|
|
1259
1445
|
}
|
|
@@ -1269,28 +1455,51 @@ var generatedTools = [
|
|
|
1269
1455
|
required: ["image"]
|
|
1270
1456
|
}
|
|
1271
1457
|
},
|
|
1272
|
-
|
|
1458
|
+
GlobalMount: {
|
|
1273
1459
|
type: "object",
|
|
1460
|
+
required: ["volumeId"],
|
|
1274
1461
|
additionalProperties: false,
|
|
1275
|
-
description: "
|
|
1462
|
+
description: "Reference to a GlobalVolume. Usage-billed, so it has no size. The underlying `volumeId` is immutable post-create; the mount `path` may be changed via PATCH.",
|
|
1276
1463
|
properties: {
|
|
1277
|
-
|
|
1278
|
-
|
|
1464
|
+
volumeId: {
|
|
1465
|
+
type: "string",
|
|
1466
|
+
description: "ID of an existing GlobalVolume.",
|
|
1467
|
+
examples: ["gsb_abc"]
|
|
1279
1468
|
},
|
|
1280
|
-
|
|
1281
|
-
type: "
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
$ref: "#/$defs/NetworkMount"
|
|
1285
|
-
}
|
|
1469
|
+
path: {
|
|
1470
|
+
type: "string",
|
|
1471
|
+
description: "Mount path inside the container. Optional on create, where a default is chosen for you; a PATCH that omits it leaves the path unchanged.",
|
|
1472
|
+
examples: ["/data"]
|
|
1286
1473
|
}
|
|
1287
1474
|
}
|
|
1288
1475
|
},
|
|
1476
|
+
Mounts: {
|
|
1477
|
+
description: "Storage mounts for the pod: `persistent` (size + path) excludes both `network` and `global`; `network` (volumeId + path) and `global` (volumeId, optional path) take one entry each and can be combined. Every entry needs its full shape. On update, omit the field to leave the mounts as they are; the mount kind and a volume's volumeId cannot change, and mounts cannot be cleared.",
|
|
1478
|
+
allOf: [
|
|
1479
|
+
{
|
|
1480
|
+
$ref: "#/$defs/BaseMounts"
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
type: "object",
|
|
1484
|
+
properties: {
|
|
1485
|
+
global: {
|
|
1486
|
+
type: "array",
|
|
1487
|
+
maxItems: 1,
|
|
1488
|
+
description: "At most one global volume, on GPU and CPU pods, with no data center constraint. Combinable with `network` but not with `persistent` (rejected): upstream drops a persistent disk whenever a volume is attached.",
|
|
1489
|
+
items: {
|
|
1490
|
+
$ref: "#/$defs/GlobalMount"
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
],
|
|
1496
|
+
unevaluatedProperties: false
|
|
1497
|
+
},
|
|
1289
1498
|
NetworkMount: {
|
|
1290
1499
|
type: "object",
|
|
1291
1500
|
required: ["volumeId", "path"],
|
|
1292
1501
|
additionalProperties: false,
|
|
1293
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
1502
|
+
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on both GPU and CPU pods. The underlying `volumeId` is immutable post-create; the mount `path` may be changed via PATCH.",
|
|
1294
1503
|
properties: {
|
|
1295
1504
|
volumeId: {
|
|
1296
1505
|
type: "string",
|
|
@@ -1308,7 +1517,7 @@ var generatedTools = [
|
|
|
1308
1517
|
type: "object",
|
|
1309
1518
|
required: ["size", "path"],
|
|
1310
1519
|
additionalProperties: false,
|
|
1311
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
1520
|
+
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data does not survive a host failure. Disallowed on CPU pods. Mutually exclusive with NetworkMount. Deprecated: prefer NetworkMount for any data you cannot recreate.",
|
|
1312
1521
|
properties: {
|
|
1313
1522
|
size: {
|
|
1314
1523
|
type: "integer",
|
|
@@ -1391,6 +1600,7 @@ var generatedTools = [
|
|
|
1391
1600
|
idempotentHint: false,
|
|
1392
1601
|
openWorldHint: true
|
|
1393
1602
|
},
|
|
1603
|
+
schemaOnDemand: true,
|
|
1394
1604
|
inputSchema: {
|
|
1395
1605
|
type: "object",
|
|
1396
1606
|
properties: {
|
|
@@ -1410,7 +1620,7 @@ var generatedTools = [
|
|
|
1410
1620
|
minLength: 1,
|
|
1411
1621
|
maxLength: 191,
|
|
1412
1622
|
pattern: "^[a-zA-Z_][a-zA-Z0-9_.\\-/]*$",
|
|
1413
|
-
description: "Unique name for the secret \u2014 referenced from environment variables as `{{ RUNPOD_SECRET_<name> }}`; immutable after creation. Maximum 191 characters, must start with a letter or underscore, and may contain letters, digits, and `_.-/`.
|
|
1623
|
+
description: "Unique name for the secret \u2014 referenced from environment variables as `{{ RUNPOD_SECRET_<name> }}`; immutable after creation. Maximum 191 characters, must start with a letter or underscore, and may contain letters, digits, and `_.-/`.",
|
|
1414
1624
|
examples: ["hf-token"]
|
|
1415
1625
|
},
|
|
1416
1626
|
value: {
|
|
@@ -1444,6 +1654,7 @@ var generatedTools = [
|
|
|
1444
1654
|
idempotentHint: false,
|
|
1445
1655
|
openWorldHint: true
|
|
1446
1656
|
},
|
|
1657
|
+
schemaOnDemand: true,
|
|
1447
1658
|
inputSchema: {
|
|
1448
1659
|
type: "object",
|
|
1449
1660
|
properties: {
|
|
@@ -1455,11 +1666,10 @@ var generatedTools = [
|
|
|
1455
1666
|
$defs: {
|
|
1456
1667
|
BaseContainerConfig: {
|
|
1457
1668
|
type: "object",
|
|
1458
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
1459
1669
|
properties: {
|
|
1460
1670
|
args: {
|
|
1461
1671
|
type: "string",
|
|
1462
|
-
description: 'The container\'s command
|
|
1672
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
1463
1673
|
examples: [
|
|
1464
1674
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
1465
1675
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -1471,7 +1681,7 @@ var generatedTools = [
|
|
|
1471
1681
|
items: {
|
|
1472
1682
|
type: "string"
|
|
1473
1683
|
},
|
|
1474
|
-
description: "Container CMD in exec form
|
|
1684
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
1475
1685
|
examples: [
|
|
1476
1686
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
1477
1687
|
]
|
|
@@ -1481,7 +1691,7 @@ var generatedTools = [
|
|
|
1481
1691
|
items: {
|
|
1482
1692
|
type: "string"
|
|
1483
1693
|
},
|
|
1484
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
1694
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
1485
1695
|
examples: [["/bin/bash", "-c"]]
|
|
1486
1696
|
},
|
|
1487
1697
|
disk: {
|
|
@@ -1518,7 +1728,6 @@ var generatedTools = [
|
|
|
1518
1728
|
}
|
|
1519
1729
|
},
|
|
1520
1730
|
ContainerConfig: {
|
|
1521
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
1522
1731
|
allOf: [
|
|
1523
1732
|
{
|
|
1524
1733
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -1555,7 +1764,7 @@ var generatedTools = [
|
|
|
1555
1764
|
type: "string",
|
|
1556
1765
|
pattern: "^\\d+\\.\\d+$"
|
|
1557
1766
|
},
|
|
1558
|
-
description: "Acceptable CUDA versions for containers created from this
|
|
1767
|
+
description: "Acceptable CUDA versions for containers created from this template, as `major.minor`. Omit to accept any version \u2014 see the same field on `createPod` for matching semantics.",
|
|
1559
1768
|
examples: [["12.8", "12.6"]]
|
|
1560
1769
|
},
|
|
1561
1770
|
category: {
|
|
@@ -1581,13 +1790,13 @@ var generatedTools = [
|
|
|
1581
1790
|
startJupyter: {
|
|
1582
1791
|
type: "boolean",
|
|
1583
1792
|
default: true,
|
|
1584
|
-
description: "Start JupyterLab in containers created from this template
|
|
1793
|
+
description: "Start JupyterLab in containers created from this template: injects a generated `JUPYTER_PASSWORD` environment variable, unless `env` already sets one.",
|
|
1585
1794
|
examples: [false]
|
|
1586
1795
|
},
|
|
1587
1796
|
startSsh: {
|
|
1588
1797
|
type: "boolean",
|
|
1589
1798
|
default: true,
|
|
1590
|
-
description: "Provision SSH access in containers created from this template
|
|
1799
|
+
description: "Provision SSH access in containers created from this template: injects a `PUBLIC_KEY` environment variable carrying the deployer's registered SSH public keys (`update-ssh-keys` \u2014 with none registered the flag does nothing), unless `env` already sets one.",
|
|
1591
1800
|
examples: [true]
|
|
1592
1801
|
}
|
|
1593
1802
|
}
|
|
@@ -1599,7 +1808,7 @@ var generatedTools = [
|
|
|
1599
1808
|
type: "object",
|
|
1600
1809
|
required: ["size", "path"],
|
|
1601
1810
|
additionalProperties: false,
|
|
1602
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
1811
|
+
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data does not survive a host failure. Disallowed on CPU pods. Mutually exclusive with NetworkMount. Deprecated: prefer NetworkMount for any data you cannot recreate.",
|
|
1603
1812
|
properties: {
|
|
1604
1813
|
size: {
|
|
1605
1814
|
type: "integer",
|
|
@@ -1616,13 +1825,13 @@ var generatedTools = [
|
|
|
1616
1825
|
},
|
|
1617
1826
|
TemplateCategory: {
|
|
1618
1827
|
type: "string",
|
|
1619
|
-
description: "Controls how the template is grouped and filtered in the Runpod console
|
|
1828
|
+
description: "Controls how the template is grouped and filtered in the Runpod console. It does not affect hardware selection, scheduling, or billing. `CPU` \u2014 CPU-only workloads. `NVIDIA` \u2014 NVIDIA GPU workloads. `AMD` \u2014 AMD GPU workloads",
|
|
1620
1829
|
enum: ["CPU", "NVIDIA", "AMD"]
|
|
1621
1830
|
},
|
|
1622
1831
|
TemplateMounts: {
|
|
1623
1832
|
type: "object",
|
|
1624
1833
|
additionalProperties: false,
|
|
1625
|
-
description: "Storage mounts
|
|
1834
|
+
description: "Storage mounts for containers from this template: a single `persistent` mount only (`network` is rejected). On update, omitting `mounts` or sending `{}` leaves the existing mount unchanged.",
|
|
1626
1835
|
properties: {
|
|
1627
1836
|
persistent: {
|
|
1628
1837
|
$ref: "#/$defs/PersistentMount"
|
|
@@ -1692,6 +1901,36 @@ var generatedTools = [
|
|
|
1692
1901
|
required: ["id"]
|
|
1693
1902
|
}
|
|
1694
1903
|
},
|
|
1904
|
+
{
|
|
1905
|
+
name: "delete-global-volume",
|
|
1906
|
+
operationId: "deleteGlobalVolume",
|
|
1907
|
+
description: "Delete a global volume. Permanently deletes a global volume and its stored data. Fails with `409` while the volume is still mounted: terminate every pod that mounts it (stopped pods count) and detach it from every serverless endpoint first. Nothing is detached or terminated on your behalf.",
|
|
1908
|
+
method: "DELETE",
|
|
1909
|
+
path: "/v2/global-volumes/{id}",
|
|
1910
|
+
params: [
|
|
1911
|
+
{
|
|
1912
|
+
name: "id",
|
|
1913
|
+
location: "path"
|
|
1914
|
+
}
|
|
1915
|
+
],
|
|
1916
|
+
hasBody: false,
|
|
1917
|
+
annotations: {
|
|
1918
|
+
readOnlyHint: false,
|
|
1919
|
+
destructiveHint: true,
|
|
1920
|
+
idempotentHint: true,
|
|
1921
|
+
openWorldHint: true
|
|
1922
|
+
},
|
|
1923
|
+
inputSchema: {
|
|
1924
|
+
type: "object",
|
|
1925
|
+
properties: {
|
|
1926
|
+
id: {
|
|
1927
|
+
type: "string",
|
|
1928
|
+
description: "Global volume identifier"
|
|
1929
|
+
}
|
|
1930
|
+
},
|
|
1931
|
+
required: ["id"]
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1695
1934
|
{
|
|
1696
1935
|
name: "delete-network-volume",
|
|
1697
1936
|
operationId: "deleteNetworkVolume",
|
|
@@ -2057,12 +2296,42 @@ var generatedTools = [
|
|
|
2057
2296
|
},
|
|
2058
2297
|
buildId: {
|
|
2059
2298
|
type: "string",
|
|
2060
|
-
description: "GitHub build identifier (from
|
|
2299
|
+
description: "GitHub build identifier (from `list-endpoint-builds` or a release's `buildId`)"
|
|
2061
2300
|
}
|
|
2062
2301
|
},
|
|
2063
2302
|
required: ["id", "buildId"]
|
|
2064
2303
|
}
|
|
2065
2304
|
},
|
|
2305
|
+
{
|
|
2306
|
+
name: "get-global-volume",
|
|
2307
|
+
operationId: "getGlobalVolume",
|
|
2308
|
+
description: "Get a global volume. Returns a single global volume by ID.",
|
|
2309
|
+
method: "GET",
|
|
2310
|
+
path: "/v2/global-volumes/{id}",
|
|
2311
|
+
params: [
|
|
2312
|
+
{
|
|
2313
|
+
name: "id",
|
|
2314
|
+
location: "path"
|
|
2315
|
+
}
|
|
2316
|
+
],
|
|
2317
|
+
hasBody: false,
|
|
2318
|
+
annotations: {
|
|
2319
|
+
readOnlyHint: true,
|
|
2320
|
+
destructiveHint: false,
|
|
2321
|
+
idempotentHint: true,
|
|
2322
|
+
openWorldHint: true
|
|
2323
|
+
},
|
|
2324
|
+
inputSchema: {
|
|
2325
|
+
type: "object",
|
|
2326
|
+
properties: {
|
|
2327
|
+
id: {
|
|
2328
|
+
type: "string",
|
|
2329
|
+
description: "Global volume identifier"
|
|
2330
|
+
}
|
|
2331
|
+
},
|
|
2332
|
+
required: ["id"]
|
|
2333
|
+
}
|
|
2334
|
+
},
|
|
2066
2335
|
{
|
|
2067
2336
|
name: "get-gpu-type",
|
|
2068
2337
|
operationId: "getGpuType",
|
|
@@ -2133,7 +2402,7 @@ var generatedTools = [
|
|
|
2133
2402
|
items: {
|
|
2134
2403
|
$ref: "#/$defs/Product"
|
|
2135
2404
|
},
|
|
2136
|
-
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way).
|
|
2405
|
+
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way)."
|
|
2137
2406
|
},
|
|
2138
2407
|
count: {
|
|
2139
2408
|
type: "integer",
|
|
@@ -2151,7 +2420,7 @@ var generatedTools = [
|
|
|
2151
2420
|
type: "string",
|
|
2152
2421
|
pattern: "^[A-Z]{2}$"
|
|
2153
2422
|
},
|
|
2154
|
-
description: "Comma-separated ISO 3166-1 alpha-2 country codes, uppercase, to constrain availability to \u2014 e.g. FR or FR,DE. Values within this filter use OR semantics. Valid only with include=AVAILABILITY
|
|
2423
|
+
description: "Comma-separated ISO 3166-1 alpha-2 country codes, uppercase, to constrain availability to \u2014 e.g. FR or FR,DE. Values within this filter use OR semantics. Valid only with include=AVAILABILITY; a malformed entry is a 422."
|
|
2155
2424
|
},
|
|
2156
2425
|
cudaVersions: {
|
|
2157
2426
|
type: "array",
|
|
@@ -2159,12 +2428,12 @@ var generatedTools = [
|
|
|
2159
2428
|
type: "string",
|
|
2160
2429
|
pattern: "^\\d+\\.\\d+$"
|
|
2161
2430
|
},
|
|
2162
|
-
description: "Comma-separated CUDA versions to scope availability and lowest-price calculations to, matched exactly. Format: major.minor, e.g. 12.8 \u2014 a bare major is rejected here because it identifies no version.
|
|
2431
|
+
description: "Comma-separated CUDA versions to scope availability and lowest-price calculations to, matched exactly. Format: major.minor, e.g. 12.8 \u2014 a bare major is rejected here because it identifies no version."
|
|
2163
2432
|
},
|
|
2164
2433
|
minCudaVersion: {
|
|
2165
2434
|
type: "string",
|
|
2166
2435
|
pattern: "^\\d+(\\.\\d+)?$",
|
|
2167
|
-
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically.
|
|
2436
|
+
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically."
|
|
2168
2437
|
}
|
|
2169
2438
|
},
|
|
2170
2439
|
required: ["id"],
|
|
@@ -2217,6 +2486,25 @@ var generatedTools = [
|
|
|
2217
2486
|
required: ["id"]
|
|
2218
2487
|
}
|
|
2219
2488
|
},
|
|
2489
|
+
{
|
|
2490
|
+
name: "get-organization",
|
|
2491
|
+
operationId: "getOrganization",
|
|
2492
|
+
description: "Get your current organization. Returns the authenticated caller's current organization. Organization context comes from the caller's membership; no organization selector is required. Returns 404 when the caller does not belong to an organization, or 403 when organizations are unavailable to the caller.",
|
|
2493
|
+
method: "GET",
|
|
2494
|
+
path: "/v2/organization",
|
|
2495
|
+
params: [],
|
|
2496
|
+
hasBody: false,
|
|
2497
|
+
annotations: {
|
|
2498
|
+
readOnlyHint: true,
|
|
2499
|
+
destructiveHint: false,
|
|
2500
|
+
idempotentHint: true,
|
|
2501
|
+
openWorldHint: true
|
|
2502
|
+
},
|
|
2503
|
+
inputSchema: {
|
|
2504
|
+
type: "object",
|
|
2505
|
+
properties: {}
|
|
2506
|
+
}
|
|
2507
|
+
},
|
|
2220
2508
|
{
|
|
2221
2509
|
name: "get-pod",
|
|
2222
2510
|
operationId: "getPod",
|
|
@@ -2391,12 +2679,12 @@ var generatedTools = [
|
|
|
2391
2679
|
startTime: {
|
|
2392
2680
|
type: "string",
|
|
2393
2681
|
format: "date-time",
|
|
2394
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
2682
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2395
2683
|
},
|
|
2396
2684
|
endTime: {
|
|
2397
2685
|
type: "string",
|
|
2398
2686
|
format: "date-time",
|
|
2399
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
2687
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
2400
2688
|
},
|
|
2401
2689
|
bucketSize: {
|
|
2402
2690
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2405,7 +2693,7 @@ var generatedTools = [
|
|
|
2405
2693
|
lastN: {
|
|
2406
2694
|
type: "integer",
|
|
2407
2695
|
minimum: 1,
|
|
2408
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
2696
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
2409
2697
|
}
|
|
2410
2698
|
},
|
|
2411
2699
|
$defs: {
|
|
@@ -2467,12 +2755,12 @@ var generatedTools = [
|
|
|
2467
2755
|
startTime: {
|
|
2468
2756
|
type: "string",
|
|
2469
2757
|
format: "date-time",
|
|
2470
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
2758
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2471
2759
|
},
|
|
2472
2760
|
endTime: {
|
|
2473
2761
|
type: "string",
|
|
2474
2762
|
format: "date-time",
|
|
2475
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
2763
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
2476
2764
|
},
|
|
2477
2765
|
bucketSize: {
|
|
2478
2766
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2481,7 +2769,7 @@ var generatedTools = [
|
|
|
2481
2769
|
lastN: {
|
|
2482
2770
|
type: "integer",
|
|
2483
2771
|
minimum: 1,
|
|
2484
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
2772
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
2485
2773
|
},
|
|
2486
2774
|
clusterId: {
|
|
2487
2775
|
type: "string",
|
|
@@ -2539,10 +2827,19 @@ var generatedTools = [
|
|
|
2539
2827
|
{
|
|
2540
2828
|
name: "list-clusters",
|
|
2541
2829
|
operationId: "listClusters",
|
|
2542
|
-
description: "List clusters. Returns
|
|
2830
|
+
description: "List clusters. Returns clusters owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
2543
2831
|
method: "GET",
|
|
2544
2832
|
path: "/v2/clusters",
|
|
2545
|
-
params: [
|
|
2833
|
+
params: [
|
|
2834
|
+
{
|
|
2835
|
+
name: "cursor",
|
|
2836
|
+
location: "query"
|
|
2837
|
+
},
|
|
2838
|
+
{
|
|
2839
|
+
name: "limit",
|
|
2840
|
+
location: "query"
|
|
2841
|
+
}
|
|
2842
|
+
],
|
|
2546
2843
|
hasBody: false,
|
|
2547
2844
|
annotations: {
|
|
2548
2845
|
readOnlyHint: true,
|
|
@@ -2552,7 +2849,19 @@ var generatedTools = [
|
|
|
2552
2849
|
},
|
|
2553
2850
|
inputSchema: {
|
|
2554
2851
|
type: "object",
|
|
2555
|
-
properties: {
|
|
2852
|
+
properties: {
|
|
2853
|
+
cursor: {
|
|
2854
|
+
type: "string",
|
|
2855
|
+
minLength: 1,
|
|
2856
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
2857
|
+
},
|
|
2858
|
+
limit: {
|
|
2859
|
+
type: "integer",
|
|
2860
|
+
minimum: 1,
|
|
2861
|
+
maximum: 1e3,
|
|
2862
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2556
2865
|
}
|
|
2557
2866
|
},
|
|
2558
2867
|
{
|
|
@@ -2806,12 +3115,12 @@ var generatedTools = [
|
|
|
2806
3115
|
startTime: {
|
|
2807
3116
|
type: "string",
|
|
2808
3117
|
format: "date-time",
|
|
2809
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3118
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2810
3119
|
},
|
|
2811
3120
|
endTime: {
|
|
2812
3121
|
type: "string",
|
|
2813
3122
|
format: "date-time",
|
|
2814
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
3123
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
2815
3124
|
},
|
|
2816
3125
|
bucketSize: {
|
|
2817
3126
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2820,7 +3129,7 @@ var generatedTools = [
|
|
|
2820
3129
|
lastN: {
|
|
2821
3130
|
type: "integer",
|
|
2822
3131
|
minimum: 1,
|
|
2823
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
3132
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
2824
3133
|
}
|
|
2825
3134
|
},
|
|
2826
3135
|
$defs: {
|
|
@@ -2878,7 +3187,7 @@ var generatedTools = [
|
|
|
2878
3187
|
cursor: {
|
|
2879
3188
|
type: "string",
|
|
2880
3189
|
minLength: 1,
|
|
2881
|
-
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected
|
|
3190
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
2882
3191
|
},
|
|
2883
3192
|
limit: {
|
|
2884
3193
|
type: "integer",
|
|
@@ -2927,7 +3236,7 @@ var generatedTools = [
|
|
|
2927
3236
|
cursor: {
|
|
2928
3237
|
type: "string",
|
|
2929
3238
|
minLength: 1,
|
|
2930
|
-
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected
|
|
3239
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
2931
3240
|
},
|
|
2932
3241
|
limit: {
|
|
2933
3242
|
type: "integer",
|
|
@@ -2969,6 +3278,46 @@ var generatedTools = [
|
|
|
2969
3278
|
required: ["id"]
|
|
2970
3279
|
}
|
|
2971
3280
|
},
|
|
3281
|
+
{
|
|
3282
|
+
name: "list-global-volumes",
|
|
3283
|
+
operationId: "listGlobalVolumes",
|
|
3284
|
+
description: "List global volumes. Returns global volumes owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
3285
|
+
method: "GET",
|
|
3286
|
+
path: "/v2/global-volumes",
|
|
3287
|
+
params: [
|
|
3288
|
+
{
|
|
3289
|
+
name: "cursor",
|
|
3290
|
+
location: "query"
|
|
3291
|
+
},
|
|
3292
|
+
{
|
|
3293
|
+
name: "limit",
|
|
3294
|
+
location: "query"
|
|
3295
|
+
}
|
|
3296
|
+
],
|
|
3297
|
+
hasBody: false,
|
|
3298
|
+
annotations: {
|
|
3299
|
+
readOnlyHint: true,
|
|
3300
|
+
destructiveHint: false,
|
|
3301
|
+
idempotentHint: true,
|
|
3302
|
+
openWorldHint: true
|
|
3303
|
+
},
|
|
3304
|
+
inputSchema: {
|
|
3305
|
+
type: "object",
|
|
3306
|
+
properties: {
|
|
3307
|
+
cursor: {
|
|
3308
|
+
type: "string",
|
|
3309
|
+
minLength: 1,
|
|
3310
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
3311
|
+
},
|
|
3312
|
+
limit: {
|
|
3313
|
+
type: "integer",
|
|
3314
|
+
minimum: 1,
|
|
3315
|
+
maximum: 1e3,
|
|
3316
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
},
|
|
2972
3321
|
{
|
|
2973
3322
|
name: "list-gpu-types",
|
|
2974
3323
|
operationId: "listGpuTypes",
|
|
@@ -3032,7 +3381,7 @@ var generatedTools = [
|
|
|
3032
3381
|
items: {
|
|
3033
3382
|
$ref: "#/$defs/Product"
|
|
3034
3383
|
},
|
|
3035
|
-
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way).
|
|
3384
|
+
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way)."
|
|
3036
3385
|
},
|
|
3037
3386
|
count: {
|
|
3038
3387
|
type: "integer",
|
|
@@ -3050,7 +3399,7 @@ var generatedTools = [
|
|
|
3050
3399
|
type: "string",
|
|
3051
3400
|
pattern: "^[A-Z]{2}$"
|
|
3052
3401
|
},
|
|
3053
|
-
description: "Comma-separated ISO 3166-1 alpha-2 country codes, uppercase, to constrain availability to \u2014 e.g. FR or FR,DE. Values within this filter use OR semantics. Valid only with include=AVAILABILITY
|
|
3402
|
+
description: "Comma-separated ISO 3166-1 alpha-2 country codes, uppercase, to constrain availability to \u2014 e.g. FR or FR,DE. Values within this filter use OR semantics. Valid only with include=AVAILABILITY; a malformed entry is a 422."
|
|
3054
3403
|
},
|
|
3055
3404
|
cudaVersions: {
|
|
3056
3405
|
type: "array",
|
|
@@ -3058,12 +3407,12 @@ var generatedTools = [
|
|
|
3058
3407
|
type: "string",
|
|
3059
3408
|
pattern: "^\\d+\\.\\d+$"
|
|
3060
3409
|
},
|
|
3061
|
-
description: "Comma-separated CUDA versions to scope availability and lowest-price calculations to, matched exactly. Format: major.minor, e.g. 12.8 \u2014 a bare major is rejected here because it identifies no version.
|
|
3410
|
+
description: "Comma-separated CUDA versions to scope availability and lowest-price calculations to, matched exactly. Format: major.minor, e.g. 12.8 \u2014 a bare major is rejected here because it identifies no version."
|
|
3062
3411
|
},
|
|
3063
3412
|
minCudaVersion: {
|
|
3064
3413
|
type: "string",
|
|
3065
3414
|
pattern: "^\\d+(\\.\\d+)?$",
|
|
3066
|
-
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically.
|
|
3415
|
+
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically."
|
|
3067
3416
|
}
|
|
3068
3417
|
},
|
|
3069
3418
|
$defs: {
|
|
@@ -3126,12 +3475,12 @@ var generatedTools = [
|
|
|
3126
3475
|
startTime: {
|
|
3127
3476
|
type: "string",
|
|
3128
3477
|
format: "date-time",
|
|
3129
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3478
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3130
3479
|
},
|
|
3131
3480
|
endTime: {
|
|
3132
3481
|
type: "string",
|
|
3133
3482
|
format: "date-time",
|
|
3134
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
3483
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
3135
3484
|
},
|
|
3136
3485
|
bucketSize: {
|
|
3137
3486
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3140,7 +3489,7 @@ var generatedTools = [
|
|
|
3140
3489
|
lastN: {
|
|
3141
3490
|
type: "integer",
|
|
3142
3491
|
minimum: 1,
|
|
3143
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
3492
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
3144
3493
|
},
|
|
3145
3494
|
networkVolumeId: {
|
|
3146
3495
|
type: "string",
|
|
@@ -3168,10 +3517,19 @@ var generatedTools = [
|
|
|
3168
3517
|
{
|
|
3169
3518
|
name: "list-network-volumes",
|
|
3170
3519
|
operationId: "listNetworkVolumes",
|
|
3171
|
-
description: "List network volumes. Returns
|
|
3520
|
+
description: "List network volumes. Returns network volumes owned by the authenticated user, cursor-paginated newest-first; an omitted `limit` defaults to 1000. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
3172
3521
|
method: "GET",
|
|
3173
3522
|
path: "/v2/network-volumes",
|
|
3174
|
-
params: [
|
|
3523
|
+
params: [
|
|
3524
|
+
{
|
|
3525
|
+
name: "cursor",
|
|
3526
|
+
location: "query"
|
|
3527
|
+
},
|
|
3528
|
+
{
|
|
3529
|
+
name: "limit",
|
|
3530
|
+
location: "query"
|
|
3531
|
+
}
|
|
3532
|
+
],
|
|
3175
3533
|
hasBody: false,
|
|
3176
3534
|
annotations: {
|
|
3177
3535
|
readOnlyHint: true,
|
|
@@ -3181,7 +3539,19 @@ var generatedTools = [
|
|
|
3181
3539
|
},
|
|
3182
3540
|
inputSchema: {
|
|
3183
3541
|
type: "object",
|
|
3184
|
-
properties: {
|
|
3542
|
+
properties: {
|
|
3543
|
+
cursor: {
|
|
3544
|
+
type: "string",
|
|
3545
|
+
minLength: 1,
|
|
3546
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
3547
|
+
},
|
|
3548
|
+
limit: {
|
|
3549
|
+
type: "integer",
|
|
3550
|
+
minimum: 1,
|
|
3551
|
+
maximum: 1e3,
|
|
3552
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3185
3555
|
}
|
|
3186
3556
|
},
|
|
3187
3557
|
{
|
|
@@ -3225,12 +3595,12 @@ var generatedTools = [
|
|
|
3225
3595
|
startTime: {
|
|
3226
3596
|
type: "string",
|
|
3227
3597
|
format: "date-time",
|
|
3228
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3598
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3229
3599
|
},
|
|
3230
3600
|
endTime: {
|
|
3231
3601
|
type: "string",
|
|
3232
3602
|
format: "date-time",
|
|
3233
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
3603
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
3234
3604
|
},
|
|
3235
3605
|
bucketSize: {
|
|
3236
3606
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3239,7 +3609,7 @@ var generatedTools = [
|
|
|
3239
3609
|
lastN: {
|
|
3240
3610
|
type: "integer",
|
|
3241
3611
|
minimum: 1,
|
|
3242
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
3612
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
3243
3613
|
},
|
|
3244
3614
|
podId: {
|
|
3245
3615
|
type: "string",
|
|
@@ -3267,7 +3637,7 @@ var generatedTools = [
|
|
|
3267
3637
|
{
|
|
3268
3638
|
name: "list-pods",
|
|
3269
3639
|
operationId: "listPods",
|
|
3270
|
-
description: "List pods. Returns pods owned by the authenticated user. Cluster member pods are excluded by default; set `includeClusterPods=true` to include them (each carries a non-null `cluster` membership block). Results are cursor-paginated newest-first; an omitted `limit` defaults to 1000.
|
|
3640
|
+
description: "List pods. Returns pods owned by the authenticated user. Cluster member pods are excluded by default; set `includeClusterPods=true` to include them (each carries a non-null `cluster` membership block). Results are cursor-paginated newest-first; an omitted `limit` defaults to 1000. The cluster-member exclusion is applied before the page is cut, so a page holds `limit` pods whenever that many remain. Follow `pagination.nextCursor` until `hasNextPage` is false.",
|
|
3271
3641
|
method: "GET",
|
|
3272
3642
|
path: "/v2/pods",
|
|
3273
3643
|
params: [
|
|
@@ -3302,7 +3672,7 @@ var generatedTools = [
|
|
|
3302
3672
|
cursor: {
|
|
3303
3673
|
type: "string",
|
|
3304
3674
|
minLength: 1,
|
|
3305
|
-
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected
|
|
3675
|
+
description: "Opaque resume cursor \u2014 pass the previous response's `pagination.nextCursor` through verbatim; omit for the first page. A cursor is only valid for the operation and parameters that issued it; a malformed or foreign cursor is rejected."
|
|
3306
3676
|
},
|
|
3307
3677
|
limit: {
|
|
3308
3678
|
type: "integer",
|
|
@@ -3339,7 +3709,7 @@ var generatedTools = [
|
|
|
3339
3709
|
type: "string",
|
|
3340
3710
|
enum: ["official", "verified", "community"],
|
|
3341
3711
|
default: "official",
|
|
3342
|
-
description: "Which slice of the catalog to return: `official` for
|
|
3712
|
+
description: "Which slice of the catalog to return: `official` for Runpod-curated templates (default), `verified` for Runpod-verified community templates, or `community` for all other publicly shared templates."
|
|
3343
3713
|
}
|
|
3344
3714
|
}
|
|
3345
3715
|
}
|
|
@@ -3433,12 +3803,12 @@ var generatedTools = [
|
|
|
3433
3803
|
startTime: {
|
|
3434
3804
|
type: "string",
|
|
3435
3805
|
format: "date-time",
|
|
3436
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3806
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3437
3807
|
},
|
|
3438
3808
|
endTime: {
|
|
3439
3809
|
type: "string",
|
|
3440
3810
|
format: "date-time",
|
|
3441
|
-
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records
|
|
3811
|
+
description: "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records."
|
|
3442
3812
|
},
|
|
3443
3813
|
bucketSize: {
|
|
3444
3814
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3447,7 +3817,7 @@ var generatedTools = [
|
|
|
3447
3817
|
lastN: {
|
|
3448
3818
|
type: "integer",
|
|
3449
3819
|
minimum: 1,
|
|
3450
|
-
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".
|
|
3820
|
+
description: 'Return the last N buckets of bucketSize, ending with the current (in-progress) bucket \u2014 e.g. lastN=100 with bucketSize=day is "last 100 days".'
|
|
3451
3821
|
},
|
|
3452
3822
|
serverlessId: {
|
|
3453
3823
|
type: "string",
|
|
@@ -3586,7 +3956,7 @@ var generatedTools = [
|
|
|
3586
3956
|
type: "object",
|
|
3587
3957
|
additionalProperties: false,
|
|
3588
3958
|
minProperties: 1,
|
|
3589
|
-
description: "Request body for updating a cluster. Only the cluster name can be
|
|
3959
|
+
description: "Request body for updating a cluster. Only the cluster name can be changed \u2014 this endpoint is a rename. Compute shape, type, and container configuration are fixed at creation.",
|
|
3590
3960
|
properties: {
|
|
3591
3961
|
name: {
|
|
3592
3962
|
type: "string",
|
|
@@ -3617,6 +3987,7 @@ var generatedTools = [
|
|
|
3617
3987
|
idempotentHint: false,
|
|
3618
3988
|
openWorldHint: true
|
|
3619
3989
|
},
|
|
3990
|
+
schemaOnDemand: true,
|
|
3620
3991
|
inputSchema: {
|
|
3621
3992
|
type: "object",
|
|
3622
3993
|
properties: {
|
|
@@ -3632,11 +4003,10 @@ var generatedTools = [
|
|
|
3632
4003
|
$defs: {
|
|
3633
4004
|
BaseContainerConfig: {
|
|
3634
4005
|
type: "object",
|
|
3635
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
3636
4006
|
properties: {
|
|
3637
4007
|
args: {
|
|
3638
4008
|
type: "string",
|
|
3639
|
-
description: 'The container\'s command
|
|
4009
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
3640
4010
|
examples: [
|
|
3641
4011
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
3642
4012
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -3648,7 +4018,7 @@ var generatedTools = [
|
|
|
3648
4018
|
items: {
|
|
3649
4019
|
type: "string"
|
|
3650
4020
|
},
|
|
3651
|
-
description: "Container CMD in exec form
|
|
4021
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
3652
4022
|
examples: [
|
|
3653
4023
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
3654
4024
|
]
|
|
@@ -3658,7 +4028,7 @@ var generatedTools = [
|
|
|
3658
4028
|
items: {
|
|
3659
4029
|
type: "string"
|
|
3660
4030
|
},
|
|
3661
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
4031
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
3662
4032
|
examples: [["/bin/bash", "-c"]]
|
|
3663
4033
|
},
|
|
3664
4034
|
disk: {
|
|
@@ -3718,7 +4088,7 @@ var generatedTools = [
|
|
|
3718
4088
|
pools: {
|
|
3719
4089
|
type: "array",
|
|
3720
4090
|
minItems: 1,
|
|
3721
|
-
description:
|
|
4091
|
+
description: "Serverless GPU pool IDs (the `pool` field of `list-gpu-types`). Workers are placed on whichever listed pool has capacity; narrow to specific cards with `excludedTypes`. On update, `pools` and `excludedTypes` are replaced together, so sending `pools` alone clears the exclusions.",
|
|
3722
4092
|
items: {
|
|
3723
4093
|
type: "string"
|
|
3724
4094
|
},
|
|
@@ -3727,7 +4097,7 @@ var generatedTools = [
|
|
|
3727
4097
|
excludedTypes: {
|
|
3728
4098
|
type: "array",
|
|
3729
4099
|
uniqueItems: true,
|
|
3730
|
-
description:
|
|
4100
|
+
description: "GPU type IDs to subtract from the selected pools \u2014 the `id` field of `list-gpu-types`, the same identifiers pods take in `gpu.id`. Workers run on every type in `pools` except these; omit to use the whole pool. A value outside `pools` is rejected. On update, restate them whenever you send `pools`, or they are cleared.",
|
|
3731
4101
|
items: {
|
|
3732
4102
|
type: "string",
|
|
3733
4103
|
pattern: "^\\s*[^-\\s]"
|
|
@@ -3744,7 +4114,6 @@ var generatedTools = [
|
|
|
3744
4114
|
}
|
|
3745
4115
|
},
|
|
3746
4116
|
ContainerConfig: {
|
|
3747
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
3748
4117
|
allOf: [
|
|
3749
4118
|
{
|
|
3750
4119
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -3769,8 +4138,42 @@ var generatedTools = [
|
|
|
3769
4138
|
],
|
|
3770
4139
|
unevaluatedProperties: false
|
|
3771
4140
|
},
|
|
4141
|
+
EndpointMount: {
|
|
4142
|
+
type: "object",
|
|
4143
|
+
required: ["volumeId"],
|
|
4144
|
+
additionalProperties: false,
|
|
4145
|
+
description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
|
|
4146
|
+
properties: {
|
|
4147
|
+
volumeId: {
|
|
4148
|
+
type: "string",
|
|
4149
|
+
description: "ID of a NetworkVolume (under `network`) or GlobalVolume (under `global`).",
|
|
4150
|
+
examples: ["vol_abc"]
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
},
|
|
4154
|
+
EndpointMountsInput: {
|
|
4155
|
+
type: "object",
|
|
4156
|
+
additionalProperties: false,
|
|
4157
|
+
description: "Volumes to mount on the endpoint's workers. A `network` or `global` list that is present replaces the endpoint's current list of that kind; an empty list detaches it, and an omitted list is left unchanged.",
|
|
4158
|
+
properties: {
|
|
4159
|
+
network: {
|
|
4160
|
+
type: "array",
|
|
4161
|
+
description: "Network volumes, at most one per data center.",
|
|
4162
|
+
items: {
|
|
4163
|
+
$ref: "#/$defs/EndpointMount"
|
|
4164
|
+
}
|
|
4165
|
+
},
|
|
4166
|
+
global: {
|
|
4167
|
+
type: "array",
|
|
4168
|
+
maxItems: 1,
|
|
4169
|
+
items: {
|
|
4170
|
+
$ref: "#/$defs/EndpointMount"
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
},
|
|
3772
4175
|
EndpointScaling: {
|
|
3773
|
-
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY
|
|
4176
|
+
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY` (queue-based endpoints only) or `REQUEST_COUNT`. The scaler is chosen independently of the endpoint's routing `type` and can be switched on update.",
|
|
3774
4177
|
oneOf: [
|
|
3775
4178
|
{
|
|
3776
4179
|
$ref: "#/$defs/QueueDelayScaling"
|
|
@@ -3807,14 +4210,14 @@ var generatedTools = [
|
|
|
3807
4210
|
type: "integer",
|
|
3808
4211
|
minimum: 1,
|
|
3809
4212
|
maximum: 3600,
|
|
3810
|
-
description: "Seconds before idle workers scale down. Not applicable to queue-based
|
|
4213
|
+
description: "Seconds before idle workers scale down. Not applicable to queue-based endpoints scaling on `requestCount` \u2014 rejected on create/update and omitted from responses for that combination.",
|
|
3811
4214
|
examples: [5]
|
|
3812
4215
|
}
|
|
3813
4216
|
}
|
|
3814
4217
|
},
|
|
3815
4218
|
FlashBoot: {
|
|
3816
4219
|
type: "string",
|
|
3817
|
-
description: "FlashBoot cold-start acceleration mode
|
|
4220
|
+
description: "FlashBoot cold-start acceleration mode. `OFF` \u2014 disabled. `FLASHBOOT` \u2014 enabled. `PRIORITY_FLASHBOOT` \u2014 enabled with priority capacity",
|
|
3818
4221
|
enum: ["OFF", "FLASHBOOT", "PRIORITY_FLASHBOOT"]
|
|
3819
4222
|
},
|
|
3820
4223
|
QueueDelayScaling: {
|
|
@@ -3840,7 +4243,7 @@ var generatedTools = [
|
|
|
3840
4243
|
RequestCountScaling: {
|
|
3841
4244
|
type: "object",
|
|
3842
4245
|
additionalProperties: false,
|
|
3843
|
-
description: "Scale on concurrent in-flight requests per worker. Required for
|
|
4246
|
+
description: "Scale on concurrent in-flight requests per worker. Required for load-balancing endpoints; also selectable for queue-based.",
|
|
3844
4247
|
required: ["type", "requestCount"],
|
|
3845
4248
|
properties: {
|
|
3846
4249
|
type: {
|
|
@@ -3857,7 +4260,7 @@ var generatedTools = [
|
|
|
3857
4260
|
}
|
|
3858
4261
|
},
|
|
3859
4262
|
UpdateEndpointGpuConfig: {
|
|
3860
|
-
description: "Partial GPU update \u2014 every field is optional and an omitted one is left
|
|
4263
|
+
description: "Partial GPU update \u2014 every field is optional and an omitted one is left unchanged. `pools` is optional here, so a CUDA-only change does not resend the pool list; `excludedTypes` needs `pools` in the same request, and `pools` sent alone clears the exclusions.",
|
|
3861
4264
|
allOf: [
|
|
3862
4265
|
{
|
|
3863
4266
|
$ref: "#/$defs/BaseEndpointGpuConfig"
|
|
@@ -3874,12 +4277,12 @@ var generatedTools = [
|
|
|
3874
4277
|
type: "string",
|
|
3875
4278
|
pattern: "^\\d+\\.\\d+$"
|
|
3876
4279
|
},
|
|
3877
|
-
description: "Acceptable CUDA versions for worker placement, as
|
|
4280
|
+
description: "Acceptable CUDA versions for worker placement, as `major.minor`. An explicit `[]` clears the constraint; omitting the field leaves it unchanged. A non-empty set cannot be sent with minCudaVersion, and setting one does not clear the other: clear the other explicitly in the same patch. Takes effect as workers are replaced."
|
|
3878
4281
|
},
|
|
3879
4282
|
minCudaVersion: {
|
|
3880
4283
|
type: "string",
|
|
3881
4284
|
pattern: "^$|^\\d+\\.\\d+$",
|
|
3882
|
-
description: 'Lowest acceptable CUDA version for worker placement, as
|
|
4285
|
+
description: 'Lowest acceptable CUDA version for worker placement, as `major.minor`. An explicit `""` clears the floor; omitting the field leaves it unchanged. Cannot be sent with a non-empty allowedCudaVersions (an explicit `[]` there is fine); clear that explicitly in the same patch if the endpoint carries one. Takes effect as workers are replaced.',
|
|
3883
4286
|
examples: ["12.1"]
|
|
3884
4287
|
}
|
|
3885
4288
|
}
|
|
@@ -3900,7 +4303,7 @@ var generatedTools = [
|
|
|
3900
4303
|
type: "array",
|
|
3901
4304
|
minItems: 1,
|
|
3902
4305
|
uniqueItems: true,
|
|
3903
|
-
description: "Complete replacement CPU selection. Valid only for an existing CPU
|
|
4306
|
+
description: "Complete replacement CPU selection. Valid only for an existing CPU endpoint; endpoint compute family cannot be changed.",
|
|
3904
4307
|
items: {
|
|
3905
4308
|
$ref: "#/$defs/CreateCpuConfig"
|
|
3906
4309
|
}
|
|
@@ -3926,14 +4329,19 @@ var generatedTools = [
|
|
|
3926
4329
|
type: "array",
|
|
3927
4330
|
items: {
|
|
3928
4331
|
type: "string"
|
|
3929
|
-
}
|
|
4332
|
+
},
|
|
4333
|
+
description: "Network volume IDs. Pass `[]` to detach.",
|
|
4334
|
+
deprecated: true
|
|
4335
|
+
},
|
|
4336
|
+
mounts: {
|
|
4337
|
+
$ref: "#/$defs/EndpointMountsInput"
|
|
3930
4338
|
},
|
|
3931
4339
|
scaling: {
|
|
3932
4340
|
$ref: "#/$defs/EndpointScaling"
|
|
3933
4341
|
},
|
|
3934
4342
|
templateId: {
|
|
3935
4343
|
type: "string",
|
|
3936
|
-
description: "ID of a serverless template whose container settings
|
|
4344
|
+
description: "ID of a serverless template whose container settings (image, args, disk, ports, env, registry) are applied as if sent in this PATCH body; explicit body fields win. `env` merges template and body per key (body wins) and replaces the endpoint's existing env. Applied once; must be a serverless template you can access.",
|
|
3937
4345
|
examples: ["30zmvf89kd"]
|
|
3938
4346
|
},
|
|
3939
4347
|
timeout: {
|
|
@@ -3944,8 +4352,59 @@ var generatedTools = [
|
|
|
3944
4352
|
}
|
|
3945
4353
|
}
|
|
3946
4354
|
}
|
|
3947
|
-
],
|
|
3948
|
-
unevaluatedProperties: false
|
|
4355
|
+
],
|
|
4356
|
+
unevaluatedProperties: false
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
},
|
|
4361
|
+
{
|
|
4362
|
+
name: "update-global-volume",
|
|
4363
|
+
operationId: "updateGlobalVolume",
|
|
4364
|
+
description: "Update a global volume. Updates mutable fields on a global volume. Only provided fields are changed.",
|
|
4365
|
+
method: "PATCH",
|
|
4366
|
+
path: "/v2/global-volumes/{id}",
|
|
4367
|
+
params: [
|
|
4368
|
+
{
|
|
4369
|
+
name: "id",
|
|
4370
|
+
location: "path"
|
|
4371
|
+
}
|
|
4372
|
+
],
|
|
4373
|
+
hasBody: true,
|
|
4374
|
+
annotations: {
|
|
4375
|
+
readOnlyHint: false,
|
|
4376
|
+
destructiveHint: false,
|
|
4377
|
+
idempotentHint: false,
|
|
4378
|
+
openWorldHint: true
|
|
4379
|
+
},
|
|
4380
|
+
inputSchema: {
|
|
4381
|
+
type: "object",
|
|
4382
|
+
properties: {
|
|
4383
|
+
id: {
|
|
4384
|
+
type: "string",
|
|
4385
|
+
description: "Global volume identifier"
|
|
4386
|
+
},
|
|
4387
|
+
body: {
|
|
4388
|
+
$ref: "#/$defs/UpdateGlobalVolumeRequest"
|
|
4389
|
+
}
|
|
4390
|
+
},
|
|
4391
|
+
required: ["id", "body"],
|
|
4392
|
+
$defs: {
|
|
4393
|
+
UpdateGlobalVolumeRequest: {
|
|
4394
|
+
type: "object",
|
|
4395
|
+
additionalProperties: false,
|
|
4396
|
+
minProperties: 1,
|
|
4397
|
+
description: "Only the provided fields are updated. At least one field must be present; an empty body is rejected.",
|
|
4398
|
+
properties: {
|
|
4399
|
+
name: {
|
|
4400
|
+
type: "string",
|
|
4401
|
+
minLength: 1,
|
|
4402
|
+
maxLength: 191,
|
|
4403
|
+
pattern: "[^\\p{Z}\\t-\\r\x85]",
|
|
4404
|
+
description: "New human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
|
|
4405
|
+
examples: ["renamed-volume"]
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
3949
4408
|
}
|
|
3950
4409
|
}
|
|
3951
4410
|
}
|
|
@@ -3986,7 +4445,7 @@ var generatedTools = [
|
|
|
3986
4445
|
type: "object",
|
|
3987
4446
|
additionalProperties: false,
|
|
3988
4447
|
minProperties: 1,
|
|
3989
|
-
description: "Only the provided fields are updated. At least one field must be
|
|
4448
|
+
description: "Only the provided fields are updated. At least one field must be present; an empty body is rejected.",
|
|
3990
4449
|
properties: {
|
|
3991
4450
|
name: {
|
|
3992
4451
|
type: "string",
|
|
@@ -3998,7 +4457,7 @@ var generatedTools = [
|
|
|
3998
4457
|
type: "integer",
|
|
3999
4458
|
minimum: 10,
|
|
4000
4459
|
maximum: 4096,
|
|
4001
|
-
description: "New size in GB. Must be greater than or equal to the current size \u2014
|
|
4460
|
+
description: "New size in GB. Must be greater than or equal to the current size \u2014 network volume storage cannot be reduced.",
|
|
4002
4461
|
examples: [100]
|
|
4003
4462
|
}
|
|
4004
4463
|
}
|
|
@@ -4025,6 +4484,7 @@ var generatedTools = [
|
|
|
4025
4484
|
idempotentHint: false,
|
|
4026
4485
|
openWorldHint: true
|
|
4027
4486
|
},
|
|
4487
|
+
schemaOnDemand: true,
|
|
4028
4488
|
inputSchema: {
|
|
4029
4489
|
type: "object",
|
|
4030
4490
|
properties: {
|
|
@@ -4040,11 +4500,10 @@ var generatedTools = [
|
|
|
4040
4500
|
$defs: {
|
|
4041
4501
|
BaseContainerConfig: {
|
|
4042
4502
|
type: "object",
|
|
4043
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
4044
4503
|
properties: {
|
|
4045
4504
|
args: {
|
|
4046
4505
|
type: "string",
|
|
4047
|
-
description: 'The container\'s command
|
|
4506
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
4048
4507
|
examples: [
|
|
4049
4508
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
4050
4509
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -4056,7 +4515,7 @@ var generatedTools = [
|
|
|
4056
4515
|
items: {
|
|
4057
4516
|
type: "string"
|
|
4058
4517
|
},
|
|
4059
|
-
description: "Container CMD in exec form
|
|
4518
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
4060
4519
|
examples: [
|
|
4061
4520
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
4062
4521
|
]
|
|
@@ -4066,7 +4525,7 @@ var generatedTools = [
|
|
|
4066
4525
|
items: {
|
|
4067
4526
|
type: "string"
|
|
4068
4527
|
},
|
|
4069
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
4528
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
4070
4529
|
examples: [["/bin/bash", "-c"]]
|
|
4071
4530
|
},
|
|
4072
4531
|
disk: {
|
|
@@ -4102,8 +4561,22 @@ var generatedTools = [
|
|
|
4102
4561
|
}
|
|
4103
4562
|
}
|
|
4104
4563
|
},
|
|
4564
|
+
BaseMounts: {
|
|
4565
|
+
type: "object",
|
|
4566
|
+
properties: {
|
|
4567
|
+
persistent: {
|
|
4568
|
+
$ref: "#/$defs/PersistentMount"
|
|
4569
|
+
},
|
|
4570
|
+
network: {
|
|
4571
|
+
type: "array",
|
|
4572
|
+
maxItems: 1,
|
|
4573
|
+
items: {
|
|
4574
|
+
$ref: "#/$defs/NetworkMount"
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
},
|
|
4105
4579
|
ContainerConfig: {
|
|
4106
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
4107
4580
|
allOf: [
|
|
4108
4581
|
{
|
|
4109
4582
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -4120,28 +4593,51 @@ var generatedTools = [
|
|
|
4120
4593
|
}
|
|
4121
4594
|
]
|
|
4122
4595
|
},
|
|
4123
|
-
|
|
4596
|
+
GlobalMount: {
|
|
4124
4597
|
type: "object",
|
|
4598
|
+
required: ["volumeId"],
|
|
4125
4599
|
additionalProperties: false,
|
|
4126
|
-
description: "
|
|
4600
|
+
description: "Reference to a GlobalVolume. Usage-billed, so it has no size. The underlying `volumeId` is immutable post-create; the mount `path` may be changed via PATCH.",
|
|
4127
4601
|
properties: {
|
|
4128
|
-
|
|
4129
|
-
|
|
4602
|
+
volumeId: {
|
|
4603
|
+
type: "string",
|
|
4604
|
+
description: "ID of an existing GlobalVolume.",
|
|
4605
|
+
examples: ["gsb_abc"]
|
|
4130
4606
|
},
|
|
4131
|
-
|
|
4132
|
-
type: "
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
$ref: "#/$defs/NetworkMount"
|
|
4136
|
-
}
|
|
4607
|
+
path: {
|
|
4608
|
+
type: "string",
|
|
4609
|
+
description: "Mount path inside the container. Optional on create, where a default is chosen for you; a PATCH that omits it leaves the path unchanged.",
|
|
4610
|
+
examples: ["/data"]
|
|
4137
4611
|
}
|
|
4138
4612
|
}
|
|
4139
4613
|
},
|
|
4614
|
+
Mounts: {
|
|
4615
|
+
description: "Storage mounts for the pod: `persistent` (size + path) excludes both `network` and `global`; `network` (volumeId + path) and `global` (volumeId, optional path) take one entry each and can be combined. Every entry needs its full shape. On update, omit the field to leave the mounts as they are; the mount kind and a volume's volumeId cannot change, and mounts cannot be cleared.",
|
|
4616
|
+
allOf: [
|
|
4617
|
+
{
|
|
4618
|
+
$ref: "#/$defs/BaseMounts"
|
|
4619
|
+
},
|
|
4620
|
+
{
|
|
4621
|
+
type: "object",
|
|
4622
|
+
properties: {
|
|
4623
|
+
global: {
|
|
4624
|
+
type: "array",
|
|
4625
|
+
maxItems: 1,
|
|
4626
|
+
description: "At most one global volume, on GPU and CPU pods, with no data center constraint. Combinable with `network` but not with `persistent` (rejected): upstream drops a persistent disk whenever a volume is attached.",
|
|
4627
|
+
items: {
|
|
4628
|
+
$ref: "#/$defs/GlobalMount"
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
],
|
|
4634
|
+
unevaluatedProperties: false
|
|
4635
|
+
},
|
|
4140
4636
|
NetworkMount: {
|
|
4141
4637
|
type: "object",
|
|
4142
4638
|
required: ["volumeId", "path"],
|
|
4143
4639
|
additionalProperties: false,
|
|
4144
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
4640
|
+
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on both GPU and CPU pods. The underlying `volumeId` is immutable post-create; the mount `path` may be changed via PATCH.",
|
|
4145
4641
|
properties: {
|
|
4146
4642
|
volumeId: {
|
|
4147
4643
|
type: "string",
|
|
@@ -4159,7 +4655,7 @@ var generatedTools = [
|
|
|
4159
4655
|
type: "object",
|
|
4160
4656
|
required: ["size", "path"],
|
|
4161
4657
|
additionalProperties: false,
|
|
4162
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
4658
|
+
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data does not survive a host failure. Disallowed on CPU pods. Mutually exclusive with NetworkMount. Deprecated: prefer NetworkMount for any data you cannot recreate.",
|
|
4163
4659
|
properties: {
|
|
4164
4660
|
size: {
|
|
4165
4661
|
type: "integer",
|
|
@@ -4184,7 +4680,7 @@ var generatedTools = [
|
|
|
4184
4680
|
properties: {
|
|
4185
4681
|
globalNetworking: {
|
|
4186
4682
|
type: "boolean",
|
|
4187
|
-
description: "Enable (true) or disable (false) global networking. Takes effect on the next pod start/restart, not live. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream).
|
|
4683
|
+
description: "Enable (true) or disable (false) global networking. Takes effect on the next pod start/restart, not live. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream)."
|
|
4188
4684
|
},
|
|
4189
4685
|
locked: {
|
|
4190
4686
|
type: "boolean",
|
|
@@ -4199,7 +4695,7 @@ var generatedTools = [
|
|
|
4199
4695
|
},
|
|
4200
4696
|
templateId: {
|
|
4201
4697
|
type: "string",
|
|
4202
|
-
description: "ID of a pod template whose container settings
|
|
4698
|
+
description: "ID of a pod template whose container settings (image, args, disk, ports, env, registry; not mounts) are applied as if sent in this PATCH body; explicit body fields win. `env` merges template and body per key (body wins) and replaces the pod's existing env. Applied once; must be a non-serverless template you can access.",
|
|
4203
4699
|
examples: ["30zmvf89kd"]
|
|
4204
4700
|
}
|
|
4205
4701
|
}
|
|
@@ -4229,6 +4725,7 @@ var generatedTools = [
|
|
|
4229
4725
|
idempotentHint: false,
|
|
4230
4726
|
openWorldHint: true
|
|
4231
4727
|
},
|
|
4728
|
+
schemaOnDemand: true,
|
|
4232
4729
|
inputSchema: {
|
|
4233
4730
|
type: "object",
|
|
4234
4731
|
properties: {
|
|
@@ -4246,7 +4743,7 @@ var generatedTools = [
|
|
|
4246
4743
|
type: "object",
|
|
4247
4744
|
additionalProperties: false,
|
|
4248
4745
|
minProperties: 1,
|
|
4249
|
-
description: "Only the provided fields are updated; at least one field is required
|
|
4746
|
+
description: "Only the provided fields are updated; at least one field is required. The secret's `name` is immutable.",
|
|
4250
4747
|
properties: {
|
|
4251
4748
|
value: {
|
|
4252
4749
|
type: "string",
|
|
@@ -4298,7 +4795,7 @@ var generatedTools = [
|
|
|
4298
4795
|
type: "string",
|
|
4299
4796
|
pattern: "^(ssh|ecdsa|sk)-[^\\s]+ [^\\s]+([ \\t][^\\n\\r]*)?$"
|
|
4300
4797
|
},
|
|
4301
|
-
description: "The full set of SSH public keys to register \u2014 this is a complete
|
|
4798
|
+
description: "The full set of SSH public keys to register \u2014 this is a complete replacement, not a merge. Each entry is an authorized_keys-style line: `<type> <base64-key> [comment]`, e.g. from `~/.ssh/id_ed25519.pub`. Send `[]` to remove all keys.",
|
|
4302
4799
|
examples: [
|
|
4303
4800
|
[
|
|
4304
4801
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"
|
|
@@ -4329,6 +4826,7 @@ var generatedTools = [
|
|
|
4329
4826
|
idempotentHint: false,
|
|
4330
4827
|
openWorldHint: true
|
|
4331
4828
|
},
|
|
4829
|
+
schemaOnDemand: true,
|
|
4332
4830
|
inputSchema: {
|
|
4333
4831
|
type: "object",
|
|
4334
4832
|
properties: {
|
|
@@ -4343,11 +4841,10 @@ var generatedTools = [
|
|
|
4343
4841
|
$defs: {
|
|
4344
4842
|
BaseContainerConfig: {
|
|
4345
4843
|
type: "object",
|
|
4346
|
-
description: "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support a direct registry credential (clusters \u2014 there the registry credential arrives via a pod template, see CreateClusterRequest.templateId).\n",
|
|
4347
4844
|
properties: {
|
|
4348
4845
|
args: {
|
|
4349
4846
|
type: "string",
|
|
4350
|
-
description: 'The container\'s command
|
|
4847
|
+
description: 'The container\'s command as one raw string: a bare shell string is treated as CMD and split into arguments; a JSON object `{"entrypoint":[...],"cmd":[...]}` sets either or both. Send `""` to clear; omit to leave unchanged.',
|
|
4351
4848
|
examples: [
|
|
4352
4849
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
4353
4850
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -4359,7 +4856,7 @@ var generatedTools = [
|
|
|
4359
4856
|
items: {
|
|
4360
4857
|
type: "string"
|
|
4361
4858
|
},
|
|
4362
|
-
description: "Container CMD in exec form
|
|
4859
|
+
description: "Container CMD in exec form: when the image defines an ENTRYPOINT, the argument list passed to it. Encoded into `args`; supply both only when they describe the same command. Send `[]` to clear; omit to leave unchanged.",
|
|
4363
4860
|
examples: [
|
|
4364
4861
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
4365
4862
|
]
|
|
@@ -4369,7 +4866,7 @@ var generatedTools = [
|
|
|
4369
4866
|
items: {
|
|
4370
4867
|
type: "string"
|
|
4371
4868
|
},
|
|
4372
|
-
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged
|
|
4869
|
+
description: "Container ENTRYPOINT in exec form, overriding the image's own. Encoded into `args` field; supplying both is allowed only when they describe the same command. Send `[]` to clear, omit to leave unchanged.",
|
|
4373
4870
|
examples: [["/bin/bash", "-c"]]
|
|
4374
4871
|
},
|
|
4375
4872
|
disk: {
|
|
@@ -4406,7 +4903,6 @@ var generatedTools = [
|
|
|
4406
4903
|
}
|
|
4407
4904
|
},
|
|
4408
4905
|
ContainerConfig: {
|
|
4409
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
4410
4906
|
allOf: [
|
|
4411
4907
|
{
|
|
4412
4908
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -4427,7 +4923,7 @@ var generatedTools = [
|
|
|
4427
4923
|
type: "object",
|
|
4428
4924
|
required: ["size", "path"],
|
|
4429
4925
|
additionalProperties: false,
|
|
4430
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
4926
|
+
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data does not survive a host failure. Disallowed on CPU pods. Mutually exclusive with NetworkMount. Deprecated: prefer NetworkMount for any data you cannot recreate.",
|
|
4431
4927
|
properties: {
|
|
4432
4928
|
size: {
|
|
4433
4929
|
type: "integer",
|
|
@@ -4444,13 +4940,13 @@ var generatedTools = [
|
|
|
4444
4940
|
},
|
|
4445
4941
|
TemplateCategory: {
|
|
4446
4942
|
type: "string",
|
|
4447
|
-
description: "Controls how the template is grouped and filtered in the Runpod console
|
|
4943
|
+
description: "Controls how the template is grouped and filtered in the Runpod console. It does not affect hardware selection, scheduling, or billing. `CPU` \u2014 CPU-only workloads. `NVIDIA` \u2014 NVIDIA GPU workloads. `AMD` \u2014 AMD GPU workloads",
|
|
4448
4944
|
enum: ["CPU", "NVIDIA", "AMD"]
|
|
4449
4945
|
},
|
|
4450
4946
|
TemplateMounts: {
|
|
4451
4947
|
type: "object",
|
|
4452
4948
|
additionalProperties: false,
|
|
4453
|
-
description: "Storage mounts
|
|
4949
|
+
description: "Storage mounts for containers from this template: a single `persistent` mount only (`network` is rejected). On update, omitting `mounts` or sending `{}` leaves the existing mount unchanged.",
|
|
4454
4950
|
properties: {
|
|
4455
4951
|
persistent: {
|
|
4456
4952
|
$ref: "#/$defs/PersistentMount"
|
|
@@ -5199,6 +5695,8 @@ var listHubRepos = {
|
|
|
5199
5695
|
};
|
|
5200
5696
|
var deployHubRepo = {
|
|
5201
5697
|
name: "deploy-hub-repo",
|
|
5698
|
+
// Two sequential upstream calls: together they can outlast a client's request timeout.
|
|
5699
|
+
holdsResponse: true,
|
|
5202
5700
|
annotations: write,
|
|
5203
5701
|
description: "Deploy a Runpod Hub repo's listed release as a new Serverless endpoint (the same as clicking Deploy on the Hub). Identify the repo by `repo` (\"owner/name\" from list-hub-repos) or by `hubReleaseId`. The release supplies the prebuilt image, container disk, CUDA constraints, and env-var defaults; pass `env` to override or fill in values (required keys without a default must be provided \u2014 check list-hub-repos with includeConfig:true for the schema). GPU selection comes from the release config when it specifies one; otherwise pass gpuIds (GPU pool names, e.g. 'ADA_24' or 'ADA_80_PRO,AMPERE_80'). Uses the authenticated GraphQL API (no REST home for Hub deploys yet).",
|
|
5204
5702
|
inputSchema: {
|
|
@@ -5687,6 +6185,7 @@ var runEndpoint = {
|
|
|
5687
6185
|
};
|
|
5688
6186
|
var runsyncEndpoint = {
|
|
5689
6187
|
name: "runsync-endpoint",
|
|
6188
|
+
holdsResponse: true,
|
|
5690
6189
|
annotations: write,
|
|
5691
6190
|
description: "Submit a synchronous job to a Serverless endpoint and wait for the result. Best for fast tasks: if the job outlives the wait, the response returns a job ID and a non-terminal status (IN_QUEUE or IN_PROGRESS) to poll with get-job-status. Max payload 20 MB; results expire after 1 minute. The wait parameter extends the server-side wait" + (HOSTED ? ` \u2014 this server runs behind a 60-second gateway deadline, so waits clamp to ${HTTP_LONG_POLL_BUDGET_MS} ms, which is also the effective default. For longer jobs use run-endpoint + get-job-status.` : " to up to 5 minutes (300000 ms); it defaults to 90000 (90 seconds)."),
|
|
5692
6191
|
inputSchema: {
|
|
@@ -5731,6 +6230,7 @@ var runsyncEndpoint = {
|
|
|
5731
6230
|
};
|
|
5732
6231
|
var getJobStatus = {
|
|
5733
6232
|
name: "get-job-status",
|
|
6233
|
+
holdsResponse: true,
|
|
5734
6234
|
annotations: readOnly,
|
|
5735
6235
|
description: "Check the status of a Serverless job. Returns the current status and output when complete. Job statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT. Pass `wait` (milliseconds, up to " + STATUS_WAIT_MAX_MS + ") to BLOCK server-side, polling until the job reaches a terminal status or the budget expires \u2014 use it to ride out a cold start (a first job on a fresh worker pulls the image and loads the model, commonly 1\u20135+ minutes) in a single call instead of returning on the first IN_QUEUE and tight-looping the tool. Without `wait` it returns the current status immediately (a single check). If the budget expires before a terminal status, it returns the latest non-terminal status with pollingTimedOut:true \u2014 call again (with `wait`) to keep blocking. IMPORTANT: a job stuck IN_QUEUE does not necessarily mean a capacity shortage \u2014 a worker may have spun up and crash-looped. When the job is IN_QUEUE this tool attaches a workerHealth summary and a hint. To dig deeper call list-endpoint-workers, then read stream-worker-logs regardless of the status a worker reports: a container failing to start loops while its worker still shows RUNNING or THROTTLED and unhealthy stays 0, so UNHEALTHY is one symptom of a crash loop and not a test for it. The logs are the authority.",
|
|
5736
6236
|
inputSchema: {
|
|
@@ -5779,6 +6279,7 @@ var getJobStatus = {
|
|
|
5779
6279
|
};
|
|
5780
6280
|
var streamJob = {
|
|
5781
6281
|
name: "stream-job",
|
|
6282
|
+
holdsResponse: true,
|
|
5782
6283
|
annotations: readOnly,
|
|
5783
6284
|
description: `Retrieve streaming output from a Serverless job. The worker must support streaming output. Polls /stream/{jobId} and collects chunks until the status is COMPLETED, FAILED, CANCELLED, or TIMED_OUT, for up to ${formatBudget(STREAM_BUDGET_MS)}. If the budget expires first, returns the chunks collected so far with pollingTimedOut: true \u2014 call stream-job again to resume where it left off, or get-job-status to check without streaming.`,
|
|
5784
6285
|
inputSchema: {
|
|
@@ -6011,8 +6512,11 @@ function publicGraphqlBase(env) {
|
|
|
6011
6512
|
function authedGraphqlBase(env) {
|
|
6012
6513
|
return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
|
|
6013
6514
|
}
|
|
6515
|
+
function knowledgeSearchBase(env) {
|
|
6516
|
+
return pick(env.KNOWLEDGE_SEARCH_URL, "") || void 0;
|
|
6517
|
+
}
|
|
6014
6518
|
|
|
6015
|
-
// node_modules/.pnpm/@runpod+typescript-api-sdk@0.
|
|
6519
|
+
// node_modules/.pnpm/@runpod+typescript-api-sdk@0.3.0/node_modules/@runpod/typescript-api-sdk/dist/index.js
|
|
6016
6520
|
var PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
6017
6521
|
var supportsRequestInitExt = () => {
|
|
6018
6522
|
return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
|
|
@@ -6909,9 +7413,9 @@ function isDigit(char) {
|
|
|
6909
7413
|
return false;
|
|
6910
7414
|
return isDigitRegex.test(char);
|
|
6911
7415
|
}
|
|
6912
|
-
function parseRetryAfter(
|
|
6913
|
-
if (
|
|
6914
|
-
const value =
|
|
7416
|
+
function parseRetryAfter(header2, now = Date.now()) {
|
|
7417
|
+
if (header2 === null) return void 0;
|
|
7418
|
+
const value = header2.trim();
|
|
6915
7419
|
if (/^\d+$/.test(value)) {
|
|
6916
7420
|
const ms = Number(value) * 1e3;
|
|
6917
7421
|
return Number.isSafeInteger(ms) ? ms : void 0;
|
|
@@ -7416,6 +7920,7 @@ function logParams(args) {
|
|
|
7416
7920
|
}
|
|
7417
7921
|
var streamPodLogs = {
|
|
7418
7922
|
name: "stream-pod-logs",
|
|
7923
|
+
holdsResponse: true,
|
|
7419
7924
|
annotations: readOnly,
|
|
7420
7925
|
description: "Read a bounded snapshot of a Pod's logs (container and/or system source). Holds the live stream open for maxWaitMs and returns the parsed log lines; `truncated: true` means the byte cap cut the output. Use `since` to resume from a timestamp.",
|
|
7421
7926
|
inputSchema: {
|
|
@@ -7438,6 +7943,7 @@ var streamPodLogs = {
|
|
|
7438
7943
|
};
|
|
7439
7944
|
var streamWorkerLogs = {
|
|
7440
7945
|
name: "stream-worker-logs",
|
|
7946
|
+
holdsResponse: true,
|
|
7441
7947
|
annotations: readOnly,
|
|
7442
7948
|
description: "Read a bounded snapshot of a Serverless worker's logs (container and/or system source). Holds the live stream open for maxWaitMs and returns the parsed log lines; `truncated: true` means the byte cap cut the output. Get worker IDs from list-endpoint-workers. Use this whenever a job stays IN_QUEUE while workers exist, whatever status they report \u2014 a crash-looping container often still shows RUNNING or THROTTLED with unhealthy 0, so these logs, not the worker status, are what identify a crash loop.",
|
|
7443
7949
|
inputSchema: {
|
|
@@ -7702,6 +8208,7 @@ var source = {
|
|
|
7702
8208
|
var listGuides = {
|
|
7703
8209
|
name: "list-guides",
|
|
7704
8210
|
annotations: bundledRead,
|
|
8211
|
+
recordedArguments: ["kind", "query", "concept"],
|
|
7705
8212
|
description: "List the official Runpod guides: skills (how to work with each tool), reference docs (how Runpod works), and golden paths (live-verified end-to-end walkthroughs such as a dev pod, a Whisper endpoint or a fine-tune-to-serverless pipeline). Read one with read-guide. For a golden path, mcp says whether an agent with only these MCP tools can finish it: full (follow it with tool calls), partial (use it for the plan and facts; name the step the user must run in a terminal), none (reference only). Skills and reference docs have mcp null. concepts lists the concept ids it works with (see lookup-concept). Filter with kind, query or concept.",
|
|
7706
8213
|
inputSchema: {
|
|
7707
8214
|
type: "object",
|
|
@@ -7737,6 +8244,8 @@ var listGuides = {
|
|
|
7737
8244
|
var readGuide = {
|
|
7738
8245
|
name: "read-guide",
|
|
7739
8246
|
annotations: bundledRead,
|
|
8247
|
+
recordedArguments: ["id"],
|
|
8248
|
+
recordedGuideKind: (args) => knowledge.guides.find((guide) => guide.id === String(args.id).trim())?.kind,
|
|
7740
8249
|
description: 'Read one official Runpod guide in full, by the id list-guides returns (for example "runpod-usage/storage" or "golden-path/06-dev-pod").',
|
|
7741
8250
|
inputSchema: {
|
|
7742
8251
|
type: "object",
|
|
@@ -7774,6 +8283,7 @@ var readGuide = {
|
|
|
7774
8283
|
var lookupConcept = {
|
|
7775
8284
|
name: "lookup-concept",
|
|
7776
8285
|
annotations: bundledRead,
|
|
8286
|
+
recordedArguments: ["concept"],
|
|
7777
8287
|
description: 'Look up one Runpod concept (pod, network volume, machine, worker, template, \u2026) by id, name or alias; case, plurals and small typos are tolerated, and `matched_as` shows the key used when the match was not exact. Returns its summary, fields, states, relations and rules, each rule with the public source it comes from, the concepts that point at it, and the linked guides: examples (golden paths that use it, with their mcp level) and docs (skills and reference docs that explain it). Use it for exact facts, for example "is a volume disk tied to one machine" or "what happens to a stopped pod\'s GPU".',
|
|
7778
8288
|
inputSchema: {
|
|
7779
8289
|
type: "object",
|
|
@@ -7826,6 +8336,7 @@ var lookupConcept = {
|
|
|
7826
8336
|
var searchConcepts = {
|
|
7827
8337
|
name: "search-concepts",
|
|
7828
8338
|
annotations: bundledRead,
|
|
8339
|
+
recordedArguments: ["query", "limit"],
|
|
7829
8340
|
description: 'Search the rules of the Runpod concept graph by words, for example "restart stopped pod no gpu" or "network volume data center". Returns the best-matching rules with their concept and public evidence. Follow up with lookup-concept for the full concept.',
|
|
7830
8341
|
inputSchema: {
|
|
7831
8342
|
type: "object",
|
|
@@ -7890,9 +8401,143 @@ var guideResources = knowledge.guides.map((guide) => ({
|
|
|
7890
8401
|
text: guide.body
|
|
7891
8402
|
}));
|
|
7892
8403
|
|
|
8404
|
+
// src/specgen/prose.ts
|
|
8405
|
+
var ABBREVIATIONS = ["e.g.", "i.e.", "etc.", "vs."];
|
|
8406
|
+
var DOT = "\0";
|
|
8407
|
+
function splitSentences(text) {
|
|
8408
|
+
let guarded = text;
|
|
8409
|
+
for (const abbreviation of ABBREVIATIONS) {
|
|
8410
|
+
guarded = guarded.replaceAll(
|
|
8411
|
+
abbreviation,
|
|
8412
|
+
abbreviation.replaceAll(".", DOT)
|
|
8413
|
+
);
|
|
8414
|
+
}
|
|
8415
|
+
return guarded.split(/(?<=[.!?])\s+(?=[A-Z`"'([])/).map((sentence) => sentence.replaceAll(DOT, ".").trim()).filter(Boolean);
|
|
8416
|
+
}
|
|
8417
|
+
function leadSentence(text) {
|
|
8418
|
+
return splitSentences(text)[0] ?? text;
|
|
8419
|
+
}
|
|
8420
|
+
|
|
8421
|
+
// src/specgen/on-demand.ts
|
|
8422
|
+
var DESCRIBE_TOOL_NAME = "describe-tool";
|
|
8423
|
+
var ON_DEMAND_POINTER = ` Call ${DESCRIBE_TOOL_NAME} for the full argument schema before the first use.`;
|
|
8424
|
+
function listedAnnotations(annotations) {
|
|
8425
|
+
const { idempotentHint, ...listed } = annotations;
|
|
8426
|
+
return idempotentHint ? annotations : listed;
|
|
8427
|
+
}
|
|
8428
|
+
function listTool(tool) {
|
|
8429
|
+
const { name, description, inputSchema } = tool;
|
|
8430
|
+
const annotations = listedAnnotations(tool.annotations);
|
|
8431
|
+
if (!tool.schemaOnDemand)
|
|
8432
|
+
return { name, description, inputSchema, annotations };
|
|
8433
|
+
return {
|
|
8434
|
+
name,
|
|
8435
|
+
description: description + ON_DEMAND_POINTER,
|
|
8436
|
+
inputSchema: callShape(inputSchema),
|
|
8437
|
+
annotations
|
|
8438
|
+
};
|
|
8439
|
+
}
|
|
8440
|
+
function callShape(schema) {
|
|
8441
|
+
const defs = schema.$defs ?? {};
|
|
8442
|
+
const resolve = (node) => {
|
|
8443
|
+
if (typeof node.$ref !== "string") return node;
|
|
8444
|
+
const name = node.$ref.split("/").pop() ?? "";
|
|
8445
|
+
return defs[name] ?? {};
|
|
8446
|
+
};
|
|
8447
|
+
const properties = Object.fromEntries(
|
|
8448
|
+
Object.entries(schema.properties ?? {}).map(
|
|
8449
|
+
([key, value]) => [key, shallowProperty(resolve(value), resolve)]
|
|
8450
|
+
)
|
|
8451
|
+
);
|
|
8452
|
+
return {
|
|
8453
|
+
type: "object",
|
|
8454
|
+
properties,
|
|
8455
|
+
...schema.required ? { required: schema.required } : {}
|
|
8456
|
+
};
|
|
8457
|
+
}
|
|
8458
|
+
function shallowProperty(node, resolve) {
|
|
8459
|
+
const out = {};
|
|
8460
|
+
const type = schemaType(node, resolve);
|
|
8461
|
+
if (type !== void 0) out.type = type;
|
|
8462
|
+
if (type === "array") {
|
|
8463
|
+
const items = resolve(node.items ?? {});
|
|
8464
|
+
const itemType = schemaType(items, resolve);
|
|
8465
|
+
if (itemType !== void 0) out.items = { type: itemType };
|
|
8466
|
+
}
|
|
8467
|
+
if (Array.isArray(node.enum)) out.enum = node.enum;
|
|
8468
|
+
if (typeof node.description === "string")
|
|
8469
|
+
out.description = leadSentence(node.description);
|
|
8470
|
+
return out;
|
|
8471
|
+
}
|
|
8472
|
+
function schemaType(node, resolve) {
|
|
8473
|
+
if (node.type !== void 0) return node.type;
|
|
8474
|
+
if (node.properties || node.allOf) return "object";
|
|
8475
|
+
const branches2 = node.anyOf ?? node.oneOf;
|
|
8476
|
+
const allObjects = branches2?.every(
|
|
8477
|
+
(branch) => schemaType(resolve(branch), resolve) === "object"
|
|
8478
|
+
) ?? false;
|
|
8479
|
+
return allObjects ? "object" : void 0;
|
|
8480
|
+
}
|
|
8481
|
+
|
|
8482
|
+
// src/specgen/tools/describe.ts
|
|
8483
|
+
function createDescribeTool(served) {
|
|
8484
|
+
return {
|
|
8485
|
+
name: DESCRIBE_TOOL_NAME,
|
|
8486
|
+
description: "Return one tool's full definition: its description, complete argument schema (every field, nested objects, constraints) and annotations. Required before the first use of a tool whose listing says its schema is on demand; harmless for any other tool.",
|
|
8487
|
+
inputSchema: {
|
|
8488
|
+
type: "object",
|
|
8489
|
+
properties: {
|
|
8490
|
+
name: {
|
|
8491
|
+
type: "string",
|
|
8492
|
+
description: "A tool name exactly as this server's tool list spells it."
|
|
8493
|
+
}
|
|
8494
|
+
},
|
|
8495
|
+
required: ["name"]
|
|
8496
|
+
},
|
|
8497
|
+
annotations: {
|
|
8498
|
+
readOnlyHint: true,
|
|
8499
|
+
destructiveHint: false,
|
|
8500
|
+
idempotentHint: true,
|
|
8501
|
+
openWorldHint: false
|
|
8502
|
+
},
|
|
8503
|
+
handler: async (_ctx, args) => {
|
|
8504
|
+
const name = String(args.name ?? "");
|
|
8505
|
+
const tools = served();
|
|
8506
|
+
const tool = tools.find((candidate) => candidate.name === name);
|
|
8507
|
+
if (!tool) {
|
|
8508
|
+
return {
|
|
8509
|
+
ok: false,
|
|
8510
|
+
status: 404,
|
|
8511
|
+
payload: {
|
|
8512
|
+
error: `No tool named ${name}.`,
|
|
8513
|
+
suggestions: similarNames(
|
|
8514
|
+
name,
|
|
8515
|
+
tools.map((candidate) => candidate.name)
|
|
8516
|
+
),
|
|
8517
|
+
hint: "Tool names are exactly as this server lists them; the suggestions share a word with the name you sent."
|
|
8518
|
+
}
|
|
8519
|
+
};
|
|
8520
|
+
}
|
|
8521
|
+
const { description, inputSchema, annotations } = tool;
|
|
8522
|
+
return ok({ name: tool.name, description, inputSchema, annotations });
|
|
8523
|
+
}
|
|
8524
|
+
};
|
|
8525
|
+
}
|
|
8526
|
+
function similarNames(query, names) {
|
|
8527
|
+
const wanted = new Set(words2(query));
|
|
8528
|
+
return names.map((name) => {
|
|
8529
|
+
const own = new Set(words2(name));
|
|
8530
|
+
const shared = [...own].filter((word) => wanted.has(word)).length;
|
|
8531
|
+
return { name, score: shared / (/* @__PURE__ */ new Set([...own, ...wanted])).size };
|
|
8532
|
+
}).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.name.localeCompare(b.name)).slice(0, 8).map((entry) => entry.name);
|
|
8533
|
+
}
|
|
8534
|
+
function words2(name) {
|
|
8535
|
+
return name.toLowerCase().split(/[-_\s]+/).filter(Boolean).map((word) => word.replace(/s$/, ""));
|
|
8536
|
+
}
|
|
8537
|
+
|
|
7893
8538
|
// src/server.ts
|
|
7894
8539
|
var SERVER_NAME = "Runpod API Server";
|
|
7895
|
-
var SERVER_VERSION = true ? "4.
|
|
8540
|
+
var SERVER_VERSION = true ? "4.4.0" : "dev";
|
|
7896
8541
|
|
|
7897
8542
|
// src/specgen/analytics.ts
|
|
7898
8543
|
import { createHmac } from "crypto";
|
|
@@ -7908,7 +8553,22 @@ function analyticsCallerId(apiKey, accountId) {
|
|
|
7908
8553
|
const prefix = accountId ? "a:" : "k:";
|
|
7909
8554
|
return prefix + createHmac("sha256", salt).update(identity).digest("hex").slice(0, 16);
|
|
7910
8555
|
}
|
|
7911
|
-
|
|
8556
|
+
var MAX_RECORDED_VALUE_LENGTH = 200;
|
|
8557
|
+
function bounded(value) {
|
|
8558
|
+
return value.slice(0, MAX_RECORDED_VALUE_LENGTH);
|
|
8559
|
+
}
|
|
8560
|
+
function recordedArgumentValues(names, args) {
|
|
8561
|
+
if (!names?.length) return void 0;
|
|
8562
|
+
const values = {};
|
|
8563
|
+
for (const name of names) {
|
|
8564
|
+
const value = args[name];
|
|
8565
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
8566
|
+
values[name] = bounded(String(value).trim());
|
|
8567
|
+
}
|
|
8568
|
+
}
|
|
8569
|
+
return Object.keys(values).length ? values : void 0;
|
|
8570
|
+
}
|
|
8571
|
+
function capture(event, distinctId, properties) {
|
|
7912
8572
|
const posthogKey = process.env.POSTHOG_API_KEY;
|
|
7913
8573
|
if (!posthogKey) return;
|
|
7914
8574
|
void fetch(`${posthogHost()}/capture/`, {
|
|
@@ -7916,18 +8576,12 @@ function captureToolCall(apiKey, event) {
|
|
|
7916
8576
|
headers: { "Content-Type": "application/json" },
|
|
7917
8577
|
body: JSON.stringify({
|
|
7918
8578
|
api_key: posthogKey,
|
|
7919
|
-
event
|
|
7920
|
-
distinct_id:
|
|
8579
|
+
event,
|
|
8580
|
+
distinct_id: distinctId,
|
|
7921
8581
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7922
8582
|
properties: {
|
|
7923
|
-
|
|
7924
|
-
ok: event.ok,
|
|
7925
|
-
status: event.status,
|
|
7926
|
-
duration_ms: event.durationMs,
|
|
7927
|
-
transport: event.transport,
|
|
7928
|
-
server_version: event.serverVersion,
|
|
8583
|
+
...properties,
|
|
7929
8584
|
surface_version: SURFACE_VERSION,
|
|
7930
|
-
...event.clientName ? { client_name: event.clientName } : {},
|
|
7931
8585
|
$process_person_profile: false
|
|
7932
8586
|
}
|
|
7933
8587
|
}),
|
|
@@ -7935,6 +8589,63 @@ function captureToolCall(apiKey, event) {
|
|
|
7935
8589
|
}).catch(() => {
|
|
7936
8590
|
});
|
|
7937
8591
|
}
|
|
8592
|
+
function captureToolCall(apiKey, event) {
|
|
8593
|
+
const args = Object.fromEntries(
|
|
8594
|
+
Object.entries(event.args ?? {}).map(([name, value]) => [
|
|
8595
|
+
`arg_${name}`,
|
|
8596
|
+
value
|
|
8597
|
+
])
|
|
8598
|
+
);
|
|
8599
|
+
capture("runpod_mcp_tool_call", analyticsCallerId(apiKey, event.accountId), {
|
|
8600
|
+
tool: event.tool,
|
|
8601
|
+
ok: event.ok,
|
|
8602
|
+
status: event.status,
|
|
8603
|
+
duration_ms: event.durationMs,
|
|
8604
|
+
transport: event.transport,
|
|
8605
|
+
server_version: event.serverVersion,
|
|
8606
|
+
...event.clientName ? { client_name: event.clientName } : {},
|
|
8607
|
+
...event.guideKind ? { guide_kind: event.guideKind } : {},
|
|
8608
|
+
...event.blockedBy ? { blocked_by: event.blockedBy } : {},
|
|
8609
|
+
...args
|
|
8610
|
+
});
|
|
8611
|
+
}
|
|
8612
|
+
function captureLoopBlocked(apiKey, event) {
|
|
8613
|
+
capture(
|
|
8614
|
+
"runpod_mcp_loop_blocked",
|
|
8615
|
+
analyticsCallerId(apiKey, event.accountId),
|
|
8616
|
+
{
|
|
8617
|
+
tool: event.tool,
|
|
8618
|
+
blocked_for_s: event.blockedForS,
|
|
8619
|
+
transport: event.transport,
|
|
8620
|
+
server_version: event.serverVersion,
|
|
8621
|
+
...event.clientName ? { client_name: event.clientName } : {}
|
|
8622
|
+
}
|
|
8623
|
+
);
|
|
8624
|
+
}
|
|
8625
|
+
function captureResourceCall(apiKey, event) {
|
|
8626
|
+
capture(
|
|
8627
|
+
"runpod_mcp_resource_call",
|
|
8628
|
+
analyticsCallerId(apiKey, event.accountId),
|
|
8629
|
+
{
|
|
8630
|
+
method: event.method,
|
|
8631
|
+
uri: bounded(event.uri),
|
|
8632
|
+
ok: event.ok,
|
|
8633
|
+
transport: event.transport,
|
|
8634
|
+
server_version: event.serverVersion,
|
|
8635
|
+
...event.clientName ? { client_name: event.clientName } : {}
|
|
8636
|
+
}
|
|
8637
|
+
);
|
|
8638
|
+
}
|
|
8639
|
+
|
|
8640
|
+
// src/alp/ingest.ts
|
|
8641
|
+
function isSinkUrl(value) {
|
|
8642
|
+
try {
|
|
8643
|
+
const url = new URL(value);
|
|
8644
|
+
return url.protocol === "https:" && url.hostname.endsWith(".convex.site") && url.pathname === "/alp/submit";
|
|
8645
|
+
} catch {
|
|
8646
|
+
return false;
|
|
8647
|
+
}
|
|
8648
|
+
}
|
|
7938
8649
|
|
|
7939
8650
|
// src/alp/read.ts
|
|
7940
8651
|
var DEFAULT_JOURNAL_LIMIT = 20;
|
|
@@ -8156,6 +8867,177 @@ function createAlpTools(opts) {
|
|
|
8156
8867
|
return [reportFeedback, saveToJournal, askQuestion, readJournalTool];
|
|
8157
8868
|
}
|
|
8158
8869
|
|
|
8870
|
+
// src/search/knowledge.ts
|
|
8871
|
+
var SEARCH_NAMESPACES = ["docs", "knowledge", "blog", "site"];
|
|
8872
|
+
var MAX_QUERY_CHARS = 2e3;
|
|
8873
|
+
var MAX_SEARCH_LIMIT = 20;
|
|
8874
|
+
var ATTEMPTS = 7;
|
|
8875
|
+
var BASE_DELAY_MS = 250;
|
|
8876
|
+
var ATTEMPT_TIMEOUT_MS = 1e4;
|
|
8877
|
+
var RETRY_DEADLINE_MS = 3e4;
|
|
8878
|
+
var PLATFORM_LIMIT = /TooManyConcurrentRequests|Too many concurrent requests/;
|
|
8879
|
+
var AT_CAPACITY = {
|
|
8880
|
+
status: 503,
|
|
8881
|
+
body: {
|
|
8882
|
+
error: "Runpod knowledge search is at capacity.",
|
|
8883
|
+
hint: "Retry the same call in a few seconds."
|
|
8884
|
+
}
|
|
8885
|
+
};
|
|
8886
|
+
var UNREACHABLE = {
|
|
8887
|
+
status: 504,
|
|
8888
|
+
body: {
|
|
8889
|
+
error: "Runpod knowledge search did not respond.",
|
|
8890
|
+
hint: "Retry the same call once."
|
|
8891
|
+
}
|
|
8892
|
+
};
|
|
8893
|
+
function searchConfigured(env = process.env) {
|
|
8894
|
+
return Boolean(knowledgeSearchBase(env) && env.RUNPOD_ASSISTANT_API_KEY);
|
|
8895
|
+
}
|
|
8896
|
+
function parseSearchRequest(raw) {
|
|
8897
|
+
if (typeof raw.query !== "string" || !raw.query.trim()) {
|
|
8898
|
+
return { error: "query must be a non-empty string." };
|
|
8899
|
+
}
|
|
8900
|
+
if (raw.query.length > MAX_QUERY_CHARS) {
|
|
8901
|
+
return { error: `query exceeds ${MAX_QUERY_CHARS} characters.` };
|
|
8902
|
+
}
|
|
8903
|
+
const request = { query: raw.query };
|
|
8904
|
+
if (raw.namespaces !== void 0) {
|
|
8905
|
+
if (!Array.isArray(raw.namespaces) || raw.namespaces.length === 0 || !raw.namespaces.every(
|
|
8906
|
+
(ns) => SEARCH_NAMESPACES.includes(ns)
|
|
8907
|
+
)) {
|
|
8908
|
+
return {
|
|
8909
|
+
error: `namespaces must be a non-empty list of: ${SEARCH_NAMESPACES.join(", ")}.`
|
|
8910
|
+
};
|
|
8911
|
+
}
|
|
8912
|
+
request.namespaces = raw.namespaces;
|
|
8913
|
+
}
|
|
8914
|
+
if (raw.limit !== void 0) {
|
|
8915
|
+
if (typeof raw.limit !== "number" || !Number.isInteger(raw.limit) || raw.limit < 1 || raw.limit > MAX_SEARCH_LIMIT) {
|
|
8916
|
+
return {
|
|
8917
|
+
error: `limit must be an integer from 1 to ${MAX_SEARCH_LIMIT}.`
|
|
8918
|
+
};
|
|
8919
|
+
}
|
|
8920
|
+
request.limit = raw.limit;
|
|
8921
|
+
}
|
|
8922
|
+
return { request };
|
|
8923
|
+
}
|
|
8924
|
+
async function searchKnowledge(request, opts = {}) {
|
|
8925
|
+
const env = opts.env ?? process.env;
|
|
8926
|
+
const doFetch = opts.fetch ?? fetch;
|
|
8927
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
8928
|
+
const now = opts.now ?? Date.now;
|
|
8929
|
+
if (!searchConfigured(env)) {
|
|
8930
|
+
return {
|
|
8931
|
+
status: 503,
|
|
8932
|
+
body: { error: "Knowledge search is not configured on this server." }
|
|
8933
|
+
};
|
|
8934
|
+
}
|
|
8935
|
+
const url = `${knowledgeSearchBase(env)}/v1/search`;
|
|
8936
|
+
const init = {
|
|
8937
|
+
method: "POST",
|
|
8938
|
+
headers: {
|
|
8939
|
+
Authorization: `Bearer ${env.RUNPOD_ASSISTANT_API_KEY}`,
|
|
8940
|
+
"Content-Type": "application/json"
|
|
8941
|
+
},
|
|
8942
|
+
body: JSON.stringify({ ...request, source: "runpod-mcp" })
|
|
8943
|
+
};
|
|
8944
|
+
const startedAt = now();
|
|
8945
|
+
for (let attempt = 1; ; attempt++) {
|
|
8946
|
+
try {
|
|
8947
|
+
const res = await doFetch(url, {
|
|
8948
|
+
...init,
|
|
8949
|
+
signal: AbortSignal.timeout(ATTEMPT_TIMEOUT_MS)
|
|
8950
|
+
});
|
|
8951
|
+
if (res.ok) {
|
|
8952
|
+
const data = await res.json().catch(() => null);
|
|
8953
|
+
if (!data) {
|
|
8954
|
+
console.warn("knowledge_search_failed status=200 invalid_json");
|
|
8955
|
+
return {
|
|
8956
|
+
status: 502,
|
|
8957
|
+
body: { error: "Runpod knowledge search failed." }
|
|
8958
|
+
};
|
|
8959
|
+
}
|
|
8960
|
+
return {
|
|
8961
|
+
status: 200,
|
|
8962
|
+
body: {
|
|
8963
|
+
text: String(data.text ?? ""),
|
|
8964
|
+
totalResults: Number(data.totalResults ?? 0),
|
|
8965
|
+
failedNamespaces: Array.isArray(data.failedNamespaces) ? data.failedNamespaces : []
|
|
8966
|
+
}
|
|
8967
|
+
};
|
|
8968
|
+
}
|
|
8969
|
+
const text = await res.text();
|
|
8970
|
+
const retryable = res.status === 503 || res.status === 429 || PLATFORM_LIMIT.test(text);
|
|
8971
|
+
if (!retryable) {
|
|
8972
|
+
console.warn(`knowledge_search_failed status=${res.status}`);
|
|
8973
|
+
return res.status === 400 ? { status: 400, body: { error: errorField(text) } } : { status: 502, body: { error: "Runpod knowledge search failed." } };
|
|
8974
|
+
}
|
|
8975
|
+
} catch (error) {
|
|
8976
|
+
console.warn(
|
|
8977
|
+
`knowledge_search_unreachable ${error instanceof Error ? error.name : "error"}`
|
|
8978
|
+
);
|
|
8979
|
+
return UNREACHABLE;
|
|
8980
|
+
}
|
|
8981
|
+
const delay = Math.random() * BASE_DELAY_MS * 2 ** (attempt - 1);
|
|
8982
|
+
if (attempt >= ATTEMPTS || now() - startedAt + delay > RETRY_DEADLINE_MS) {
|
|
8983
|
+
return AT_CAPACITY;
|
|
8984
|
+
}
|
|
8985
|
+
await sleep2(delay);
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
function errorField(text) {
|
|
8989
|
+
try {
|
|
8990
|
+
const parsed = JSON.parse(text);
|
|
8991
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
8992
|
+
} catch {
|
|
8993
|
+
}
|
|
8994
|
+
return "Invalid search request.";
|
|
8995
|
+
}
|
|
8996
|
+
|
|
8997
|
+
// src/specgen/tools/search.ts
|
|
8998
|
+
function createSearchDocsTool(search) {
|
|
8999
|
+
return {
|
|
9000
|
+
name: "search-docs",
|
|
9001
|
+
annotations: readOnly,
|
|
9002
|
+
recordedArguments: ["limit"],
|
|
9003
|
+
description: 'Search Runpod documentation, curated support knowledge, the Runpod blog and runpod.io for passages that answer a question, for example "how do I attach a network volume to a Serverless endpoint". Returns ranked passages with their source URLs. Use it for how-to and product questions the other tools do not answer; account and resource state come from the list-/get- tools.',
|
|
9004
|
+
inputSchema: {
|
|
9005
|
+
type: "object",
|
|
9006
|
+
properties: {
|
|
9007
|
+
query: {
|
|
9008
|
+
type: "string",
|
|
9009
|
+
maxLength: MAX_QUERY_CHARS,
|
|
9010
|
+
description: "The question, in natural language."
|
|
9011
|
+
},
|
|
9012
|
+
namespaces: {
|
|
9013
|
+
type: "array",
|
|
9014
|
+
items: { type: "string", enum: [...SEARCH_NAMESPACES] },
|
|
9015
|
+
minItems: 1,
|
|
9016
|
+
description: "Sources to search: docs (docs.runpod.io), knowledge (curated support answers), blog, site (runpod.io pages). Default: docs, knowledge, blog."
|
|
9017
|
+
},
|
|
9018
|
+
limit: {
|
|
9019
|
+
type: "integer",
|
|
9020
|
+
minimum: 1,
|
|
9021
|
+
maximum: MAX_SEARCH_LIMIT,
|
|
9022
|
+
description: "Most passages to return. Default 8."
|
|
9023
|
+
}
|
|
9024
|
+
},
|
|
9025
|
+
required: ["query"],
|
|
9026
|
+
additionalProperties: false
|
|
9027
|
+
},
|
|
9028
|
+
handler: async (ctx, args) => {
|
|
9029
|
+
const parsed = parseSearchRequest(args);
|
|
9030
|
+
if ("error" in parsed) return badRequest(parsed.error);
|
|
9031
|
+
const outcome = await search(parsed.request, ctx.apiKey);
|
|
9032
|
+
return {
|
|
9033
|
+
ok: outcome.status === 200,
|
|
9034
|
+
status: outcome.status,
|
|
9035
|
+
payload: outcome.body
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
};
|
|
9039
|
+
}
|
|
9040
|
+
|
|
8159
9041
|
// src/specgen/ops.ts
|
|
8160
9042
|
import { createHash, randomBytes } from "crypto";
|
|
8161
9043
|
var SALT = randomBytes(16).toString("hex");
|
|
@@ -8180,6 +9062,9 @@ var curatedTools = [
|
|
|
8180
9062
|
listPublicEndpoints,
|
|
8181
9063
|
...knowledgeTools
|
|
8182
9064
|
];
|
|
9065
|
+
var responseHoldingTools = new Set(
|
|
9066
|
+
curatedTools.filter((tool) => tool.holdsResponse).map((tool) => tool.name)
|
|
9067
|
+
);
|
|
8183
9068
|
var SERVER_INSTRUCTIONS = `These tools cover the Runpod v2 REST surface: compute catalog (GPUs, CPUs, data centers, capacity), pods, serverless endpoints and jobs, templates, network volumes, container registries, billing, public endpoints, and the Hub.
|
|
8184
9069
|
|
|
8185
9070
|
Answer from live reads, as facts. Account and availability questions can only be answered from tool data: call the relevant list-/get- tool and quote the figures, names, and ids it returns verbatim. State stock and status definitively from the read you just made \u2014 never "probably" or "check later". When the user names a resource loosely ("my comfyui pod"), resolve it with a list- tool; ask only on genuine ambiguity. If nothing exists (no pods, zero spend), say exactly that \u2014 an honest empty answer is complete.
|
|
@@ -8196,14 +9081,22 @@ PLAYBOOKS \u2014 READ BEFORE ACTING. Each Runpod task has a journey playbook car
|
|
|
8196
9081
|
|
|
8197
9082
|
THE OFFICIAL RUNPOD PLUGIN. Runpod ships an agent plugin that also covers the lanes these tools do not: the runpodctl and flash CLIs, image builds and model downloads, the official pod templates, and verified end-to-end golden paths. Check once per session whether skills named runpod, runpod-usage, or runpodctl are available to you \u2014 read what you already have, never shell out to look. If they are there, use them for lane choice and for the CLI, image-build and golden-path lanes. For work done with these tools, the journey playbook is the procedure, wherever it is served from: the plugin's runpod-mcp skill and the journey skills it routes to when you have them, otherwise the same playbooks through read-guide here. If you do not see them, recommend the plugin to the user, and recommend updating to the latest if what they have is missing something you need. Point them at https://github.com/runpod/runpod-plugins-official \u2014 its README carries the install, update, and clone commands for each client, so read it yourself when you need the exact one rather than guessing a command. This is a recommendation, never a prerequisite: make it once, briefly, and get on with the task. Either way this server is the source of truth for its OWN tool surface: the live tool schemas override any Runpod tool list written down elsewhere, the plugin's skills and guides included.
|
|
8198
9083
|
|
|
8199
|
-
The tool schemas are generated from the Runpod v2 OpenAPI contract, served as a machine-readable document at https://api.runpod.io/v2/openapi.json \u2014 consult it for fields beyond the tool surface. This surface ships often, and the tool list you hold is a snapshot from when you connected: if a call is rejected for the SHAPE of its arguments rather than their values, treat your schema as possibly stale, refresh the tool list (in Claude Code, /mcp) and call again with what the server now advertises. Retrying variants of a rejected shape cannot succeed. These instructions are a snapshot from the same moment. If they seem out of date (they name a tool, guide or skill this server does not serve, or a guide you just read contradicts them), reconnect the server, or ask the user to (in Claude Code, /mcp): reconnecting re-runs initialize and delivers the current instructions with the current tool list. Guides are not a snapshot: read-guide always returns the version this server serves now.`;
|
|
9084
|
+
The tool schemas are generated from the Runpod v2 OpenAPI contract, served as a machine-readable document at https://api.runpod.io/v2/openapi.json \u2014 consult it for fields beyond the tool surface. Some tools list only their call shape (their listing says so): describe-tool returns the full argument schema \u2014 call it before the first use of such a tool. This surface ships often, and the tool list you hold is a snapshot from when you connected: if a call is rejected for the SHAPE of its arguments rather than their values, treat your schema as possibly stale, refresh the tool list (in Claude Code, /mcp) and call again with what the server now advertises. Retrying variants of a rejected shape cannot succeed. These instructions are a snapshot from the same moment. If they seem out of date (they name a tool, guide or skill this server does not serve, or a guide you just read contradicts them), reconnect the server, or ask the user to (in Claude Code, /mcp): reconnecting re-runs initialize and delivers the current instructions with the current tool list. Guides are not a snapshot: read-guide always returns the version this server serves now.`;
|
|
8200
9085
|
var ALP_INSTRUCTIONS = `
|
|
8201
9086
|
|
|
8202
9087
|
CONTRIBUTING BACK IS OPTIONAL. Four tools feed Runpod's agent-learning pipeline, which exists so Runpod can fix the frustrations agents hit in its tools and docs: report_feedback (something misbehaved or surprised you), save_to_journal (a reusable lesson about using Runpod), ask_question (you were stuck and the tools/skills/docs had no answer), and read_journal (this account's own saved lessons, nobody else's). Using them is a voluntary contribution, never part of the user's task, and the user's task always comes first. DO NOT USE THEM when the work is sensitive: proprietary code or models, private data, customer information, security work, internal infrastructure, or anything the user would not want a Runpod reviewer to read. Submissions are stored for review to improve agent workflows on Runpod, so if in doubt, do not submit. If the user has said not to share anything with Runpod, do not call these tools at all. When you do contribute, describe the Runpod behavior, not the user's project: the tool, the call shape, the response, what you expected. Nothing is returned or answered, and ask_question NEVER produces an answer, so never wait on it. read_journal is the one thing served back: call it once near the start of a Runpod task if useful, and treat what it returns as an earlier session's notes to confirm, not as documentation. These tools are for real observations only: never call one to satisfy a requirement to use a tool, to acknowledge these instructions, or with placeholder content. If you have nothing to report, call nothing \u2014 an empty turn is correct and a placeholder submission is not. Never include API keys or secrets in submissions.`;
|
|
8203
9088
|
function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
8204
9089
|
const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
|
|
8205
9090
|
const caller = callerId(ctx.apiKey);
|
|
8206
|
-
const servedCuratedTools =
|
|
9091
|
+
const servedCuratedTools = [
|
|
9092
|
+
...curatedTools,
|
|
9093
|
+
...opts.search ? [createSearchDocsTool(opts.search)] : [],
|
|
9094
|
+
...opts.alp ? createAlpTools(opts.alp) : [],
|
|
9095
|
+
createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
|
|
9096
|
+
];
|
|
9097
|
+
const callShapeOnlyTools = new Set(
|
|
9098
|
+
[...servedCuratedTools, ...generatedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
|
|
9099
|
+
);
|
|
8207
9100
|
const server = new Server(
|
|
8208
9101
|
{ name: SERVER_NAME, version: `${version} [specgen]` },
|
|
8209
9102
|
{
|
|
@@ -8222,24 +9115,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8222
9115
|
}
|
|
8223
9116
|
};
|
|
8224
9117
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
8225
|
-
tools: [
|
|
8226
|
-
...servedCuratedTools.map(
|
|
8227
|
-
({ name, description, inputSchema, annotations }) => ({
|
|
8228
|
-
name,
|
|
8229
|
-
description,
|
|
8230
|
-
inputSchema,
|
|
8231
|
-
annotations
|
|
8232
|
-
})
|
|
8233
|
-
),
|
|
8234
|
-
...generatedTools.map(
|
|
8235
|
-
({ name, description, inputSchema, annotations }) => ({
|
|
8236
|
-
name,
|
|
8237
|
-
description,
|
|
8238
|
-
inputSchema,
|
|
8239
|
-
annotations
|
|
8240
|
-
})
|
|
8241
|
-
)
|
|
8242
|
-
]
|
|
9118
|
+
tools: [...servedCuratedTools, ...generatedTools].map(listTool)
|
|
8243
9119
|
}));
|
|
8244
9120
|
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
8245
9121
|
resources: guideResources.map(({ text: _text, ...resource }) => resource)
|
|
@@ -8251,6 +9127,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8251
9127
|
const guide = guideResources.find(
|
|
8252
9128
|
(candidate) => candidate.uri === request.params.uri
|
|
8253
9129
|
);
|
|
9130
|
+
if (opts.analytics) {
|
|
9131
|
+
captureResourceCall(ctx.apiKey, {
|
|
9132
|
+
method: "resources/read",
|
|
9133
|
+
uri: guide ? guide.uri : "unknown",
|
|
9134
|
+
ok: Boolean(guide),
|
|
9135
|
+
...opts.analytics
|
|
9136
|
+
});
|
|
9137
|
+
}
|
|
8254
9138
|
if (!guide) {
|
|
8255
9139
|
throw new Error(
|
|
8256
9140
|
`Unknown resource ${request.params.uri}. Resources are the plugin guides under ${GUIDE_URI_PREFIX}; call list-guides for the guide ids.`
|
|
@@ -8273,6 +9157,16 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8273
9157
|
status: 429,
|
|
8274
9158
|
durationMs: 0
|
|
8275
9159
|
});
|
|
9160
|
+
if (opts.analytics) {
|
|
9161
|
+
captureToolCall(ctx.apiKey, {
|
|
9162
|
+
tool: request.params.name,
|
|
9163
|
+
ok: false,
|
|
9164
|
+
status: 429,
|
|
9165
|
+
durationMs: 0,
|
|
9166
|
+
...verdict.reason ? { blockedBy: verdict.reason } : {},
|
|
9167
|
+
...opts.analytics
|
|
9168
|
+
});
|
|
9169
|
+
}
|
|
8276
9170
|
return {
|
|
8277
9171
|
content: [
|
|
8278
9172
|
{
|
|
@@ -8310,11 +9204,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8310
9204
|
ok: result.ok,
|
|
8311
9205
|
status: result.status,
|
|
8312
9206
|
durationMs: Date.now() - startedAt,
|
|
9207
|
+
args: recordedArgumentValues(curated?.recordedArguments, args),
|
|
9208
|
+
guideKind: curated?.recordedGuideKind?.(args),
|
|
8313
9209
|
...opts.analytics
|
|
8314
9210
|
});
|
|
8315
9211
|
}
|
|
9212
|
+
opts.onToolResult?.(request.params.name, result.status);
|
|
8316
9213
|
if (!result.ok && result.status === 401) opts.onUnauthorized?.();
|
|
8317
|
-
const payload = result.ok ? result.payload : withRecoveryHint(result);
|
|
9214
|
+
const payload = result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name));
|
|
8318
9215
|
return {
|
|
8319
9216
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
8320
9217
|
isError: !result.ok
|
|
@@ -8332,9 +9229,29 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8332
9229
|
}
|
|
8333
9230
|
return server;
|
|
8334
9231
|
}
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
9232
|
+
var SHAPE_HINT = "Input shape mismatch: check this tool's schema for required fields. For job payloads, the worker's release config defines the expected input object \u2014 fix the payload and retry; don't abandon the task.";
|
|
9233
|
+
var DETAIL_HINTS = [
|
|
9234
|
+
[
|
|
9235
|
+
/no longer any instances available|not enough free GPUs/i,
|
|
9236
|
+
"Capacity, not input: the request is valid but no machine can take it right now. Don't change the payload shape. Retry with another GPU type, data center, cloud, CUDA version or count, or try again later. For a stopped Pod, its host's GPUs are taken; that Pod can only start once they free up."
|
|
9237
|
+
],
|
|
9238
|
+
[
|
|
9239
|
+
/at least \$\d|insufficient (?:funds|balance)|\bbalance\b/i,
|
|
9240
|
+
"Account balance, not input: this operation needs funds on the account. Ask the user to add credit in the Runpod console; list-billing shows recent spend."
|
|
9241
|
+
],
|
|
9242
|
+
[
|
|
9243
|
+
/mutually exclusive|cannot be combined with/i,
|
|
9244
|
+
"Two arguments conflict: send only one of them and leave the other out entirely. Do not change anything else."
|
|
9245
|
+
]
|
|
9246
|
+
];
|
|
9247
|
+
function errorHint(status, detail) {
|
|
9248
|
+
if (status === 400 && detail) {
|
|
9249
|
+
for (const [pattern, hint] of DETAIL_HINTS)
|
|
9250
|
+
if (pattern.test(detail)) return hint;
|
|
9251
|
+
if (/^unauthorized$/i.test(detail.trim()))
|
|
9252
|
+
return "Upstream refused this write. With a key that can read, this usually means the account has no balance: ask the user to check their balance in the Runpod console before retrying.";
|
|
9253
|
+
}
|
|
9254
|
+
if (status === 400 || status === 422) return SHAPE_HINT;
|
|
8338
9255
|
if (status === 401) return "The Runpod API key is missing or invalid.";
|
|
8339
9256
|
if (status === 402)
|
|
8340
9257
|
return "Check your account balance in the Runpod console before retrying billable operations; list-billing shows the recent spend behind it.";
|
|
@@ -8348,13 +9265,23 @@ function errorHint(status) {
|
|
|
8348
9265
|
return "Upstream Runpod error: retry once; if it persists, report it as an API-side failure.";
|
|
8349
9266
|
return void 0;
|
|
8350
9267
|
}
|
|
8351
|
-
|
|
9268
|
+
var CALL_SHAPE_ONLY_HINT = `This tool lists its call shape only; ${DESCRIBE_TOOL_NAME} serves the full argument schema.`;
|
|
9269
|
+
function withRecoveryHint(result, listsCallShapeOnly = false) {
|
|
8352
9270
|
const payload = asRecord(result.payload) ?? { error: result.payload };
|
|
9271
|
+
const hint = payload.hint ?? asRecord(payload.detail)?.hint ?? errorHint(result.status, detailText(payload));
|
|
9272
|
+
const shapeRejected = result.status === 400 || result.status === 422;
|
|
8353
9273
|
return {
|
|
8354
9274
|
...payload,
|
|
8355
|
-
hint:
|
|
9275
|
+
hint: listsCallShapeOnly && shapeRejected ? [hint, CALL_SHAPE_ONLY_HINT].filter(Boolean).join(" ") : hint
|
|
8356
9276
|
};
|
|
8357
9277
|
}
|
|
9278
|
+
function detailText(payload) {
|
|
9279
|
+
if (Array.isArray(payload.errors) && payload.errors.length) return void 0;
|
|
9280
|
+
const detail = payload.detail ?? payload.error;
|
|
9281
|
+
if (typeof detail === "string") return detail;
|
|
9282
|
+
const nested = asRecord(detail);
|
|
9283
|
+
return typeof nested?.detail === "string" ? nested.detail : void 0;
|
|
9284
|
+
}
|
|
8358
9285
|
function asRecord(value) {
|
|
8359
9286
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
8360
9287
|
}
|
|
@@ -8520,6 +9447,58 @@ function createToolContext(options = {}) {
|
|
|
8520
9447
|
};
|
|
8521
9448
|
}
|
|
8522
9449
|
|
|
9450
|
+
// src/specgen/not-found-limiter.ts
|
|
9451
|
+
var SINK_TIMEOUT_MS = 3e3;
|
|
9452
|
+
var NOT_FOUND_LOOP = "not_found_loop";
|
|
9453
|
+
var blocked = /* @__PURE__ */ new Map();
|
|
9454
|
+
function notFoundSinkUrl(submitUrl) {
|
|
9455
|
+
if (!isSinkUrl(submitUrl)) return null;
|
|
9456
|
+
const url = new URL(submitUrl);
|
|
9457
|
+
url.pathname = "/ratelimit/not-found";
|
|
9458
|
+
return url.toString();
|
|
9459
|
+
}
|
|
9460
|
+
function createNotFoundLimiter(opts) {
|
|
9461
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
9462
|
+
const now = opts.now ?? Date.now;
|
|
9463
|
+
return {
|
|
9464
|
+
rateLimiter: async (_caller, tool) => {
|
|
9465
|
+
const pair = `${opts.key}|${tool}`;
|
|
9466
|
+
const until = blocked.get(pair);
|
|
9467
|
+
if (until === void 0) return { allowed: true };
|
|
9468
|
+
if (until <= now()) {
|
|
9469
|
+
blocked.delete(pair);
|
|
9470
|
+
return { allowed: true };
|
|
9471
|
+
}
|
|
9472
|
+
return {
|
|
9473
|
+
allowed: false,
|
|
9474
|
+
retryAfterS: Math.ceil((until - now()) / 1e3),
|
|
9475
|
+
reason: NOT_FOUND_LOOP
|
|
9476
|
+
};
|
|
9477
|
+
},
|
|
9478
|
+
onToolResult: (tool, status) => {
|
|
9479
|
+
if (status !== 404) return;
|
|
9480
|
+
const pair = `${opts.key}|${tool}`;
|
|
9481
|
+
void fetchImpl(opts.sinkUrl, {
|
|
9482
|
+
method: "POST",
|
|
9483
|
+
headers: {
|
|
9484
|
+
"Content-Type": "application/json",
|
|
9485
|
+
"X-ALP-Secret": opts.secret
|
|
9486
|
+
},
|
|
9487
|
+
body: JSON.stringify({ key: pair }),
|
|
9488
|
+
signal: AbortSignal.timeout(SINK_TIMEOUT_MS)
|
|
9489
|
+
}).then((response) => response.ok ? response.json() : null).then((body) => {
|
|
9490
|
+
const reply = body;
|
|
9491
|
+
const until = reply?.blockedUntil;
|
|
9492
|
+
if (typeof until === "number" && until > now()) {
|
|
9493
|
+
blocked.set(pair, until);
|
|
9494
|
+
if (reply?.started === true) opts.onBlockStarted?.(tool, until);
|
|
9495
|
+
}
|
|
9496
|
+
}).catch(() => {
|
|
9497
|
+
});
|
|
9498
|
+
}
|
|
9499
|
+
};
|
|
9500
|
+
}
|
|
9501
|
+
|
|
8523
9502
|
// src/_shared/credential-check.ts
|
|
8524
9503
|
import { createHash as createHash2 } from "crypto";
|
|
8525
9504
|
var VALID_TTL_MS = 6e4;
|
|
@@ -8631,8 +9610,7 @@ function extractBearerToken(req) {
|
|
|
8631
9610
|
return parts[1];
|
|
8632
9611
|
}
|
|
8633
9612
|
function analyticsOptedOut(req) {
|
|
8634
|
-
const
|
|
8635
|
-
const value = (Array.isArray(raw) ? raw[0] : raw)?.trim().toLowerCase();
|
|
9613
|
+
const value = header(req, "x-runpod-analytics")?.trim().toLowerCase();
|
|
8636
9614
|
return value === "off" || value === "0" || value === "false";
|
|
8637
9615
|
}
|
|
8638
9616
|
function getBaseUrl(req) {
|
|
@@ -8691,14 +9669,16 @@ function credentialCheckMayBeWrongEnvironment(env = process.env) {
|
|
|
8691
9669
|
);
|
|
8692
9670
|
return restMoved !== graphqlMoved;
|
|
8693
9671
|
}
|
|
8694
|
-
function
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
9672
|
+
function parseMcpMessages(body) {
|
|
9673
|
+
const elements = Array.isArray(body) ? body : [body];
|
|
9674
|
+
return elements.flatMap((element) => {
|
|
9675
|
+
const parsed = JSONRPCMessageSchema.safeParse(element);
|
|
9676
|
+
return parsed.success ? [parsed.data] : [];
|
|
9677
|
+
});
|
|
8698
9678
|
}
|
|
9679
|
+
var invokesMethod = (message) => "method" in message;
|
|
8699
9680
|
function bodyIsCheckable(body) {
|
|
8700
|
-
|
|
8701
|
-
return messages.some(looksLikeMcpMessage);
|
|
9681
|
+
return parseMcpMessages(body).some(invokesMethod);
|
|
8702
9682
|
}
|
|
8703
9683
|
function isJsonContentType(req) {
|
|
8704
9684
|
const ct = req.headers["content-type"];
|
|
@@ -8736,17 +9716,79 @@ function earlyCredentialCheckSkip(req) {
|
|
|
8736
9716
|
if (credentialCheckMayBeWrongEnvironment()) return "skip_env_mismatch";
|
|
8737
9717
|
return null;
|
|
8738
9718
|
}
|
|
9719
|
+
var callsResponseHoldingTool = (message) => {
|
|
9720
|
+
const call = CallToolRequestSchema2.safeParse(message);
|
|
9721
|
+
return call.success && responseHoldingTools.has(call.data.params.name);
|
|
9722
|
+
};
|
|
9723
|
+
function prefersJsonResponse(messages) {
|
|
9724
|
+
return messages.length > 0 && !messages.some(callsResponseHoldingTool);
|
|
9725
|
+
}
|
|
9726
|
+
var DEFAULT_REQUEST_LOG_SAMPLE_RATE = 0.1;
|
|
9727
|
+
function requestLogSampleRate(env = process.env) {
|
|
9728
|
+
if (env.MCP_VERBOSE_LOGS === "true") return 1;
|
|
9729
|
+
const raw = env.MCP_REQUEST_LOG_SAMPLE_RATE;
|
|
9730
|
+
if (raw === void 0 || raw === "") return DEFAULT_REQUEST_LOG_SAMPLE_RATE;
|
|
9731
|
+
const parsed = Number(raw);
|
|
9732
|
+
if (!Number.isFinite(parsed)) return DEFAULT_REQUEST_LOG_SAMPLE_RATE;
|
|
9733
|
+
return Math.min(1, Math.max(0, parsed));
|
|
9734
|
+
}
|
|
9735
|
+
function summarizeRpc(messages) {
|
|
9736
|
+
const rpc = messages.map((message) => {
|
|
9737
|
+
const call = CallToolRequestSchema2.safeParse(message);
|
|
9738
|
+
if (call.success) return `tools/call:${call.data.params.name}`;
|
|
9739
|
+
return "method" in message ? message.method : "response";
|
|
9740
|
+
});
|
|
9741
|
+
const init = messages.map((message) => InitializeRequestSchema.safeParse(message)).find((result) => result.success);
|
|
9742
|
+
const client = init?.success ? `${init.data.params.clientInfo.name}/${init.data.params.clientInfo.version}` : void 0;
|
|
9743
|
+
return { rpc: rpc.length > 0 ? rpc.join(",") : void 0, client };
|
|
9744
|
+
}
|
|
9745
|
+
function header(req, name) {
|
|
9746
|
+
const value = req.headers[name];
|
|
9747
|
+
return Array.isArray(value) ? value[0] : value;
|
|
9748
|
+
}
|
|
9749
|
+
function clientAddress(req) {
|
|
9750
|
+
return header(req, "x-real-ip") || header(req, "x-forwarded-for")?.split(",")[0].trim() || req.socket?.remoteAddress || void 0;
|
|
9751
|
+
}
|
|
9752
|
+
function startRequestLog(req, res, bearerToken) {
|
|
9753
|
+
const sampleRate = requestLogSampleRate();
|
|
9754
|
+
if (Math.random() >= sampleRate) return { note() {
|
|
9755
|
+
} };
|
|
9756
|
+
const startedAt = Date.now();
|
|
9757
|
+
let summary = {};
|
|
9758
|
+
const address = clientAddress(req);
|
|
9759
|
+
const userAgent = header(req, "user-agent");
|
|
9760
|
+
let emitted = false;
|
|
9761
|
+
const emit = () => {
|
|
9762
|
+
if (emitted) return;
|
|
9763
|
+
emitted = true;
|
|
9764
|
+
console.log("mcp_request", {
|
|
9765
|
+
method: req.method,
|
|
9766
|
+
url: req.url,
|
|
9767
|
+
status: res.writableFinished ? res.statusCode : void 0,
|
|
9768
|
+
durationMs: Date.now() - startedAt,
|
|
9769
|
+
rpc: summary.rpc,
|
|
9770
|
+
client: summary.client,
|
|
9771
|
+
ua: userAgent?.slice(0, 160),
|
|
9772
|
+
caller: callerId(bearerToken ?? void 0),
|
|
9773
|
+
ip: address ? callerId(address) : void 0,
|
|
9774
|
+
sampleRate
|
|
9775
|
+
});
|
|
9776
|
+
};
|
|
9777
|
+
res.on("finish", emit);
|
|
9778
|
+
res.on("close", emit);
|
|
9779
|
+
return {
|
|
9780
|
+
note(next) {
|
|
9781
|
+
summary = next;
|
|
9782
|
+
}
|
|
9783
|
+
};
|
|
9784
|
+
}
|
|
8739
9785
|
function logCredentialCheck(outcome) {
|
|
8740
9786
|
if (outcome === "pass" && process.env.MCP_VERBOSE_LOGS !== "true") return;
|
|
8741
9787
|
console.log("credential_check", { outcome });
|
|
8742
9788
|
}
|
|
8743
9789
|
async function handleMcpRequest(req, res, opts = {}) {
|
|
8744
9790
|
const bearerToken = extractBearerToken(req);
|
|
8745
|
-
|
|
8746
|
-
method: req.method,
|
|
8747
|
-
url: req.url,
|
|
8748
|
-
hasBearerToken: !!bearerToken
|
|
8749
|
-
});
|
|
9791
|
+
const requestLog = startRequestLog(req, res, bearerToken);
|
|
8750
9792
|
if (req.method === "GET") {
|
|
8751
9793
|
res.writeHead(405, {
|
|
8752
9794
|
Allow: "POST, DELETE",
|
|
@@ -8775,9 +9817,7 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8775
9817
|
let body = req.body;
|
|
8776
9818
|
let accountId;
|
|
8777
9819
|
const early = earlyCredentialCheckSkip(req);
|
|
8778
|
-
if (early) {
|
|
8779
|
-
logCredentialCheck(early);
|
|
8780
|
-
} else {
|
|
9820
|
+
if (!early) {
|
|
8781
9821
|
const read = await readJsonBody(req);
|
|
8782
9822
|
if (read === BODY_TOO_LARGE) {
|
|
8783
9823
|
res.writeHead(413, { "Content-Type": "application/json" });
|
|
@@ -8785,26 +9825,47 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8785
9825
|
return;
|
|
8786
9826
|
}
|
|
8787
9827
|
body = read;
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
9828
|
+
}
|
|
9829
|
+
const messages = parseMcpMessages(body);
|
|
9830
|
+
requestLog.note(summarizeRpc(messages));
|
|
9831
|
+
if (early) {
|
|
9832
|
+
logCredentialCheck(early);
|
|
9833
|
+
} else if (!messages.some(invokesMethod)) {
|
|
9834
|
+
logCredentialCheck("skip_not_mcp_body");
|
|
9835
|
+
} else {
|
|
9836
|
+
const verify = opts.verifyCredential ?? defaultCredentialChecker.verify;
|
|
9837
|
+
const verdict = await verify(bearerToken);
|
|
9838
|
+
if (verdict.status === "valid") accountId = verdict.accountId;
|
|
9839
|
+
logCredentialCheck(
|
|
9840
|
+
verdict.status === "invalid" ? "reject" : verdict.status === "valid" ? "pass" : "fail_open"
|
|
9841
|
+
);
|
|
9842
|
+
if (verdict.status === "invalid") {
|
|
9843
|
+
writeUnauthorized(
|
|
9844
|
+
req,
|
|
9845
|
+
res,
|
|
9846
|
+
`${verdict.reason} Re-authenticate to continue.`,
|
|
9847
|
+
true
|
|
8796
9848
|
);
|
|
8797
|
-
|
|
8798
|
-
writeUnauthorized(
|
|
8799
|
-
req,
|
|
8800
|
-
res,
|
|
8801
|
-
`${verdict.reason} Re-authenticate to continue.`,
|
|
8802
|
-
true
|
|
8803
|
-
);
|
|
8804
|
-
return;
|
|
8805
|
-
}
|
|
9849
|
+
return;
|
|
8806
9850
|
}
|
|
8807
9851
|
}
|
|
9852
|
+
const notFoundUrl = process.env.ALP_SINK_URL ? notFoundSinkUrl(process.env.ALP_SINK_URL) : null;
|
|
9853
|
+
const notFoundLimiter = bearerToken && notFoundUrl && process.env.ALP_SINK_SECRET ? createNotFoundLimiter({
|
|
9854
|
+
key: analyticsCallerId(bearerToken, accountId),
|
|
9855
|
+
sinkUrl: notFoundUrl,
|
|
9856
|
+
secret: process.env.ALP_SINK_SECRET,
|
|
9857
|
+
// One usage event per block, unless this client opted out.
|
|
9858
|
+
onBlockStarted: analyticsOptedOut(req) ? void 0 : (tool, blockedUntil) => captureLoopBlocked(bearerToken, {
|
|
9859
|
+
tool,
|
|
9860
|
+
blockedForS: Math.round((blockedUntil - Date.now()) / 1e3),
|
|
9861
|
+
transport: "http",
|
|
9862
|
+
serverVersion: opts.serverVersion ?? SERVER_VERSION,
|
|
9863
|
+
clientName: sanitizeUaToken(
|
|
9864
|
+
String(req.headers["user-agent"] ?? "unknown")
|
|
9865
|
+
),
|
|
9866
|
+
accountId
|
|
9867
|
+
})
|
|
9868
|
+
}) : null;
|
|
8808
9869
|
const server = createSpecgenServer(
|
|
8809
9870
|
createToolContext({
|
|
8810
9871
|
apiKey: bearerToken,
|
|
@@ -8845,6 +9906,13 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8845
9906
|
harnessSource: "user_agent"
|
|
8846
9907
|
}
|
|
8847
9908
|
} : {},
|
|
9909
|
+
// search-docs: listed only where the deployment holds the assistant's
|
|
9910
|
+
// service key; the search runs in-process with it.
|
|
9911
|
+
...searchConfigured() ? { search: (request) => searchKnowledge(request) } : {},
|
|
9912
|
+
...notFoundLimiter ? {
|
|
9913
|
+
rateLimiter: notFoundLimiter.rateLimiter,
|
|
9914
|
+
onToolResult: notFoundLimiter.onToolResult
|
|
9915
|
+
} : {},
|
|
8848
9916
|
// A tool call that 401s proves a cached "valid" verdict wrong before
|
|
8849
9917
|
// its TTL — drop it so the next request re-checks and re-auths.
|
|
8850
9918
|
onUnauthorized: () => (opts.invalidateCredential ?? defaultCredentialChecker.invalidate)(
|
|
@@ -8853,8 +9921,9 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8853
9921
|
}
|
|
8854
9922
|
);
|
|
8855
9923
|
const transport = new StreamableHTTPServerTransport({
|
|
8856
|
-
sessionIdGenerator: void 0
|
|
9924
|
+
sessionIdGenerator: void 0,
|
|
8857
9925
|
// stateless — no session persistence
|
|
9926
|
+
enableJsonResponse: prefersJsonResponse(messages)
|
|
8858
9927
|
});
|
|
8859
9928
|
res.on("close", () => {
|
|
8860
9929
|
transport.close().catch(() => {
|
|
@@ -8868,7 +9937,12 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8868
9937
|
export {
|
|
8869
9938
|
bodyIsCheckable,
|
|
8870
9939
|
defaultCredentialChecker,
|
|
9940
|
+
extractBearerToken,
|
|
8871
9941
|
getBaseUrl,
|
|
8872
|
-
handleMcpRequest
|
|
9942
|
+
handleMcpRequest,
|
|
9943
|
+
parseMcpMessages,
|
|
9944
|
+
prefersJsonResponse,
|
|
9945
|
+
requestLogSampleRate,
|
|
9946
|
+
summarizeRpc
|
|
8873
9947
|
};
|
|
8874
9948
|
//# sourceMappingURL=http.mjs.map
|