@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.cjs
CHANGED
|
@@ -22,11 +22,17 @@ var http_exports = {};
|
|
|
22
22
|
__export(http_exports, {
|
|
23
23
|
bodyIsCheckable: () => bodyIsCheckable,
|
|
24
24
|
defaultCredentialChecker: () => defaultCredentialChecker,
|
|
25
|
+
extractBearerToken: () => extractBearerToken,
|
|
25
26
|
getBaseUrl: () => getBaseUrl,
|
|
26
|
-
handleMcpRequest: () => handleMcpRequest
|
|
27
|
+
handleMcpRequest: () => handleMcpRequest,
|
|
28
|
+
parseMcpMessages: () => parseMcpMessages,
|
|
29
|
+
prefersJsonResponse: () => prefersJsonResponse,
|
|
30
|
+
requestLogSampleRate: () => requestLogSampleRate,
|
|
31
|
+
summarizeRpc: () => summarizeRpc
|
|
27
32
|
});
|
|
28
33
|
module.exports = __toCommonJS(http_exports);
|
|
29
34
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
35
|
+
var import_types2 = require("@modelcontextprotocol/sdk/types.js");
|
|
30
36
|
|
|
31
37
|
// src/specgen/server.ts
|
|
32
38
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -108,11 +114,11 @@ function readParams(params) {
|
|
|
108
114
|
}
|
|
109
115
|
return { values, unreadable };
|
|
110
116
|
}
|
|
111
|
-
function parseExhaustedWindows(
|
|
112
|
-
if (!
|
|
117
|
+
function parseExhaustedWindows(header2) {
|
|
118
|
+
if (!header2) return { windows: [], dropped: false };
|
|
113
119
|
const windows = [];
|
|
114
120
|
let dropped = false;
|
|
115
|
-
for (const item of splitOutsideStrings(
|
|
121
|
+
for (const item of splitOutsideStrings(header2, ",")) {
|
|
116
122
|
if (item.trim() === "") continue;
|
|
117
123
|
const [rawName, ...params] = splitOutsideStrings(item, ";");
|
|
118
124
|
if (!params.every(isWellFormedParam)) {
|
|
@@ -230,10 +236,13 @@ function validateArguments(inputSchema, args) {
|
|
|
230
236
|
async function dispatchGeneratedTool(client, tool, args) {
|
|
231
237
|
const rejected = validateArguments(tool.inputSchema, args);
|
|
232
238
|
if (rejected) return rejected;
|
|
239
|
+
const required = new Set(tool.inputSchema.required ?? []);
|
|
233
240
|
const pathParams = {};
|
|
234
241
|
const query = {};
|
|
235
242
|
for (const param of tool.params) {
|
|
236
243
|
if (args[param.name] === void 0) continue;
|
|
244
|
+
if (param.location === "query" && !required.has(param.name) && isEmptyValue(args[param.name]))
|
|
245
|
+
continue;
|
|
237
246
|
if (param.location === "path") {
|
|
238
247
|
pathParams[param.name] = args[param.name];
|
|
239
248
|
continue;
|
|
@@ -255,6 +264,11 @@ async function dispatchGeneratedTool(client, tool, args) {
|
|
|
255
264
|
};
|
|
256
265
|
}
|
|
257
266
|
}
|
|
267
|
+
if (tool.hasBody && requestBody !== void 0) {
|
|
268
|
+
const properties = tool.inputSchema.properties ?? {};
|
|
269
|
+
const defs = tool.inputSchema.$defs ?? {};
|
|
270
|
+
requestBody = coerceScalars(requestBody, properties.body, defs);
|
|
271
|
+
}
|
|
258
272
|
const verbs = client;
|
|
259
273
|
const { data, error, response } = await verbs[tool.method](tool.path, {
|
|
260
274
|
params: { path: pathParams, query },
|
|
@@ -267,6 +281,79 @@ async function dispatchGeneratedTool(client, tool, args) {
|
|
|
267
281
|
payload: data ?? { status: response.status }
|
|
268
282
|
};
|
|
269
283
|
}
|
|
284
|
+
function isEmptyValue(value) {
|
|
285
|
+
return value === null || value === "" || Array.isArray(value) && !value.length;
|
|
286
|
+
}
|
|
287
|
+
function asSchema(value) {
|
|
288
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
289
|
+
}
|
|
290
|
+
function resolveSchema(schema, defs, depth = 0) {
|
|
291
|
+
const node = asSchema(schema);
|
|
292
|
+
if (!node || depth > 16) return node;
|
|
293
|
+
const ref = node.$ref;
|
|
294
|
+
if (typeof ref === "string" && ref.startsWith("#/$defs/"))
|
|
295
|
+
return resolveSchema(defs[ref.slice("#/$defs/".length)], defs, depth + 1);
|
|
296
|
+
return node;
|
|
297
|
+
}
|
|
298
|
+
function branches(schema, defs, depth = 0) {
|
|
299
|
+
const node = resolveSchema(schema, defs);
|
|
300
|
+
if (!node || depth > 16) return [];
|
|
301
|
+
const out = [node];
|
|
302
|
+
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
|
303
|
+
const list = node[key];
|
|
304
|
+
if (Array.isArray(list))
|
|
305
|
+
for (const sub of list) out.push(...branches(sub, defs, depth + 1));
|
|
306
|
+
}
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
function types(schemas) {
|
|
310
|
+
const out = /* @__PURE__ */ new Set();
|
|
311
|
+
for (const s of schemas) {
|
|
312
|
+
if (typeof s.type === "string") out.add(s.type);
|
|
313
|
+
else if (Array.isArray(s.type)) {
|
|
314
|
+
for (const t of s.type) if (typeof t === "string") out.add(t);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return out;
|
|
318
|
+
}
|
|
319
|
+
var NUMERIC = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
320
|
+
function coerceScalars(value, schema, defs, depth = 0) {
|
|
321
|
+
if (depth > 32) return value;
|
|
322
|
+
const applicable = branches(schema, defs);
|
|
323
|
+
if (!applicable.length) return value;
|
|
324
|
+
const allowed = types(applicable);
|
|
325
|
+
if (typeof value === "string") {
|
|
326
|
+
if (allowed.has("string")) return value;
|
|
327
|
+
if ((allowed.has("integer") || allowed.has("number")) && NUMERIC.test(value)) {
|
|
328
|
+
const n = Number(value);
|
|
329
|
+
if (allowed.has("number") || Number.isInteger(n)) return n;
|
|
330
|
+
}
|
|
331
|
+
if (allowed.has("boolean") && (value === "true" || value === "false"))
|
|
332
|
+
return value === "true";
|
|
333
|
+
return value;
|
|
334
|
+
}
|
|
335
|
+
if (Array.isArray(value)) {
|
|
336
|
+
const items = applicable.map((s) => s.items).filter(Boolean);
|
|
337
|
+
if (!items.length) return value;
|
|
338
|
+
return value.map(
|
|
339
|
+
(item) => coerceScalars(item, { anyOf: items }, defs, depth + 1)
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
const object = asSchema(value);
|
|
343
|
+
if (!object) return value;
|
|
344
|
+
const out = {};
|
|
345
|
+
for (const [key, child] of Object.entries(object)) {
|
|
346
|
+
const childSchemas = [];
|
|
347
|
+
for (const s of applicable) {
|
|
348
|
+
const props = asSchema(s.properties);
|
|
349
|
+
if (props && key in props) childSchemas.push(props[key]);
|
|
350
|
+
else if (asSchema(s.additionalProperties))
|
|
351
|
+
childSchemas.push(s.additionalProperties);
|
|
352
|
+
}
|
|
353
|
+
out[key] = childSchemas.length ? coerceScalars(child, { anyOf: childSchemas }, defs, depth + 1) : child;
|
|
354
|
+
}
|
|
355
|
+
return out;
|
|
356
|
+
}
|
|
270
357
|
|
|
271
358
|
// src/specgen/generated/tools.gen.ts
|
|
272
359
|
var generatedTools = [
|
|
@@ -284,6 +371,7 @@ var generatedTools = [
|
|
|
284
371
|
idempotentHint: false,
|
|
285
372
|
openWorldHint: true
|
|
286
373
|
},
|
|
374
|
+
schemaOnDemand: true,
|
|
287
375
|
inputSchema: {
|
|
288
376
|
type: "object",
|
|
289
377
|
properties: {
|
|
@@ -295,11 +383,10 @@ var generatedTools = [
|
|
|
295
383
|
$defs: {
|
|
296
384
|
BaseContainerConfig: {
|
|
297
385
|
type: "object",
|
|
298
|
-
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",
|
|
299
386
|
properties: {
|
|
300
387
|
args: {
|
|
301
388
|
type: "string",
|
|
302
|
-
description: 'The container\'s command
|
|
389
|
+
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.',
|
|
303
390
|
examples: [
|
|
304
391
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
305
392
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -311,7 +398,7 @@ var generatedTools = [
|
|
|
311
398
|
items: {
|
|
312
399
|
type: "string"
|
|
313
400
|
},
|
|
314
|
-
description: "Container CMD in exec form
|
|
401
|
+
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.",
|
|
315
402
|
examples: [
|
|
316
403
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
317
404
|
]
|
|
@@ -321,7 +408,7 @@ var generatedTools = [
|
|
|
321
408
|
items: {
|
|
322
409
|
type: "string"
|
|
323
410
|
},
|
|
324
|
-
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
|
|
411
|
+
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.",
|
|
325
412
|
examples: [["/bin/bash", "-c"]]
|
|
326
413
|
},
|
|
327
414
|
disk: {
|
|
@@ -357,6 +444,21 @@ var generatedTools = [
|
|
|
357
444
|
}
|
|
358
445
|
}
|
|
359
446
|
},
|
|
447
|
+
BaseMounts: {
|
|
448
|
+
type: "object",
|
|
449
|
+
properties: {
|
|
450
|
+
persistent: {
|
|
451
|
+
$ref: "#/$defs/PersistentMount"
|
|
452
|
+
},
|
|
453
|
+
network: {
|
|
454
|
+
type: "array",
|
|
455
|
+
maxItems: 1,
|
|
456
|
+
items: {
|
|
457
|
+
$ref: "#/$defs/NetworkMount"
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
},
|
|
360
462
|
ClusterCompute: {
|
|
361
463
|
type: "object",
|
|
362
464
|
additionalProperties: false,
|
|
@@ -384,6 +486,15 @@ var generatedTools = [
|
|
|
384
486
|
}
|
|
385
487
|
}
|
|
386
488
|
},
|
|
489
|
+
ClusterMounts: {
|
|
490
|
+
description: "Storage mounts for a cluster create: `persistent` or `network`, not both. Clusters cannot mount global volumes, so `global` is rejected.",
|
|
491
|
+
allOf: [
|
|
492
|
+
{
|
|
493
|
+
$ref: "#/$defs/BaseMounts"
|
|
494
|
+
}
|
|
495
|
+
],
|
|
496
|
+
unevaluatedProperties: false
|
|
497
|
+
},
|
|
387
498
|
ClusterType: {
|
|
388
499
|
type: "string",
|
|
389
500
|
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.",
|
|
@@ -398,7 +509,7 @@ var generatedTools = [
|
|
|
398
509
|
{
|
|
399
510
|
type: "object",
|
|
400
511
|
required: ["name", "type", "compute"],
|
|
401
|
-
description: "Request body for creating a cluster. `compute` defines the
|
|
512
|
+
description: "Request body for creating a cluster. `compute` defines the homogeneous pod shape; the container configuration (image, env, ports, \u2026) applies to every pod.",
|
|
402
513
|
properties: {
|
|
403
514
|
compute: {
|
|
404
515
|
$ref: "#/$defs/ClusterCompute"
|
|
@@ -414,7 +525,7 @@ var generatedTools = [
|
|
|
414
525
|
templateId: {
|
|
415
526
|
type: "string",
|
|
416
527
|
minLength: 1,
|
|
417
|
-
description: "ID of a pod template to provision every member pod from
|
|
528
|
+
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.",
|
|
418
529
|
examples: ["30zmvf89kd"]
|
|
419
530
|
},
|
|
420
531
|
dataCenterIds: {
|
|
@@ -422,11 +533,11 @@ var generatedTools = [
|
|
|
422
533
|
items: {
|
|
423
534
|
type: "string"
|
|
424
535
|
},
|
|
425
|
-
description: "Preferred data centers for placement. Omit or pass an empty
|
|
536
|
+
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.",
|
|
426
537
|
example: ["US-TX-3"]
|
|
427
538
|
},
|
|
428
539
|
mounts: {
|
|
429
|
-
$ref: "#/$defs/
|
|
540
|
+
$ref: "#/$defs/ClusterMounts"
|
|
430
541
|
},
|
|
431
542
|
startJupyter: {
|
|
432
543
|
type: "boolean",
|
|
@@ -443,28 +554,11 @@ var generatedTools = [
|
|
|
443
554
|
],
|
|
444
555
|
unevaluatedProperties: false
|
|
445
556
|
},
|
|
446
|
-
Mounts: {
|
|
447
|
-
type: "object",
|
|
448
|
-
additionalProperties: false,
|
|
449
|
-
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",
|
|
450
|
-
properties: {
|
|
451
|
-
persistent: {
|
|
452
|
-
$ref: "#/$defs/PersistentMount"
|
|
453
|
-
},
|
|
454
|
-
network: {
|
|
455
|
-
type: "array",
|
|
456
|
-
maxItems: 1,
|
|
457
|
-
items: {
|
|
458
|
-
$ref: "#/$defs/NetworkMount"
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
},
|
|
463
557
|
NetworkMount: {
|
|
464
558
|
type: "object",
|
|
465
559
|
required: ["volumeId", "path"],
|
|
466
560
|
additionalProperties: false,
|
|
467
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
561
|
+
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.",
|
|
468
562
|
properties: {
|
|
469
563
|
volumeId: {
|
|
470
564
|
type: "string",
|
|
@@ -482,7 +576,7 @@ var generatedTools = [
|
|
|
482
576
|
type: "object",
|
|
483
577
|
required: ["size", "path"],
|
|
484
578
|
additionalProperties: false,
|
|
485
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
579
|
+
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.",
|
|
486
580
|
properties: {
|
|
487
581
|
size: {
|
|
488
582
|
type: "integer",
|
|
@@ -559,6 +653,7 @@ var generatedTools = [
|
|
|
559
653
|
idempotentHint: false,
|
|
560
654
|
openWorldHint: true
|
|
561
655
|
},
|
|
656
|
+
schemaOnDemand: true,
|
|
562
657
|
inputSchema: {
|
|
563
658
|
type: "object",
|
|
564
659
|
properties: {
|
|
@@ -570,11 +665,10 @@ var generatedTools = [
|
|
|
570
665
|
$defs: {
|
|
571
666
|
BaseContainerConfig: {
|
|
572
667
|
type: "object",
|
|
573
|
-
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",
|
|
574
668
|
properties: {
|
|
575
669
|
args: {
|
|
576
670
|
type: "string",
|
|
577
|
-
description: 'The container\'s command
|
|
671
|
+
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.',
|
|
578
672
|
examples: [
|
|
579
673
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
580
674
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -586,7 +680,7 @@ var generatedTools = [
|
|
|
586
680
|
items: {
|
|
587
681
|
type: "string"
|
|
588
682
|
},
|
|
589
|
-
description: "Container CMD in exec form
|
|
683
|
+
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.",
|
|
590
684
|
examples: [
|
|
591
685
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
592
686
|
]
|
|
@@ -596,7 +690,7 @@ var generatedTools = [
|
|
|
596
690
|
items: {
|
|
597
691
|
type: "string"
|
|
598
692
|
},
|
|
599
|
-
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
|
|
693
|
+
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.",
|
|
600
694
|
examples: [["/bin/bash", "-c"]]
|
|
601
695
|
},
|
|
602
696
|
disk: {
|
|
@@ -656,7 +750,7 @@ var generatedTools = [
|
|
|
656
750
|
pools: {
|
|
657
751
|
type: "array",
|
|
658
752
|
minItems: 1,
|
|
659
|
-
description:
|
|
753
|
+
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.",
|
|
660
754
|
items: {
|
|
661
755
|
type: "string"
|
|
662
756
|
},
|
|
@@ -665,7 +759,7 @@ var generatedTools = [
|
|
|
665
759
|
excludedTypes: {
|
|
666
760
|
type: "array",
|
|
667
761
|
uniqueItems: true,
|
|
668
|
-
description:
|
|
762
|
+
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.",
|
|
669
763
|
items: {
|
|
670
764
|
type: "string",
|
|
671
765
|
pattern: "^\\s*[^-\\s]"
|
|
@@ -682,7 +776,6 @@ var generatedTools = [
|
|
|
682
776
|
}
|
|
683
777
|
},
|
|
684
778
|
ContainerConfig: {
|
|
685
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
686
779
|
allOf: [
|
|
687
780
|
{
|
|
688
781
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -708,7 +801,7 @@ var generatedTools = [
|
|
|
708
801
|
unevaluatedProperties: false
|
|
709
802
|
},
|
|
710
803
|
CreateEndpointGpuConfig: {
|
|
711
|
-
description: "GPU request for an endpoint create. Carries the CUDA constraints, which
|
|
804
|
+
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.",
|
|
712
805
|
allOf: [
|
|
713
806
|
{
|
|
714
807
|
$ref: "#/$defs/BaseEndpointGpuConfig"
|
|
@@ -723,13 +816,13 @@ var generatedTools = [
|
|
|
723
816
|
type: "string",
|
|
724
817
|
pattern: "^\\d+\\.\\d+$"
|
|
725
818
|
},
|
|
726
|
-
description: "Acceptable CUDA versions for worker placement, as
|
|
819
|
+
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`).",
|
|
727
820
|
examples: [["12.8", "12.6"]]
|
|
728
821
|
},
|
|
729
822
|
minCudaVersion: {
|
|
730
823
|
type: "string",
|
|
731
824
|
pattern: "^\\d+\\.\\d+$",
|
|
732
|
-
description: "Lowest acceptable CUDA version for worker placement, as
|
|
825
|
+
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.",
|
|
733
826
|
examples: ["12.1"]
|
|
734
827
|
}
|
|
735
828
|
}
|
|
@@ -773,13 +866,13 @@ var generatedTools = [
|
|
|
773
866
|
$ref: "#/$defs/EndpointType"
|
|
774
867
|
}
|
|
775
868
|
],
|
|
776
|
-
description: "Request-routing model. Required \u2014 it determines the valid scaler
|
|
869
|
+
description: "Request-routing model. Required \u2014 it determines the valid scaler and request URLs, so it must be chosen explicitly on every create."
|
|
777
870
|
},
|
|
778
871
|
cpu: {
|
|
779
872
|
type: "array",
|
|
780
873
|
minItems: 1,
|
|
781
874
|
uniqueItems: true,
|
|
782
|
-
description: "Eligible CPU configurations for each worker. Memory is derived from the
|
|
875
|
+
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.",
|
|
783
876
|
items: {
|
|
784
877
|
$ref: "#/$defs/CreateCpuConfig"
|
|
785
878
|
}
|
|
@@ -803,12 +896,17 @@ var generatedTools = [
|
|
|
803
896
|
type: "array",
|
|
804
897
|
items: {
|
|
805
898
|
type: "string"
|
|
806
|
-
}
|
|
899
|
+
},
|
|
900
|
+
description: "Network volume IDs.",
|
|
901
|
+
deprecated: true
|
|
902
|
+
},
|
|
903
|
+
mounts: {
|
|
904
|
+
$ref: "#/$defs/EndpointMountsInput"
|
|
807
905
|
},
|
|
808
906
|
templateId: {
|
|
809
907
|
type: "string",
|
|
810
908
|
minLength: 1,
|
|
811
|
-
description: "ID of a serverless template to base this endpoint on
|
|
909
|
+
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.",
|
|
812
910
|
examples: ["30zmvf89kd"]
|
|
813
911
|
},
|
|
814
912
|
timeout: {
|
|
@@ -856,8 +954,42 @@ var generatedTools = [
|
|
|
856
954
|
}
|
|
857
955
|
}
|
|
858
956
|
},
|
|
957
|
+
EndpointMount: {
|
|
958
|
+
type: "object",
|
|
959
|
+
required: ["volumeId"],
|
|
960
|
+
additionalProperties: false,
|
|
961
|
+
description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
|
|
962
|
+
properties: {
|
|
963
|
+
volumeId: {
|
|
964
|
+
type: "string",
|
|
965
|
+
description: "ID of a NetworkVolume (under `network`) or GlobalVolume (under `global`).",
|
|
966
|
+
examples: ["vol_abc"]
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
},
|
|
970
|
+
EndpointMountsInput: {
|
|
971
|
+
type: "object",
|
|
972
|
+
additionalProperties: false,
|
|
973
|
+
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.",
|
|
974
|
+
properties: {
|
|
975
|
+
network: {
|
|
976
|
+
type: "array",
|
|
977
|
+
description: "Network volumes, at most one per data center.",
|
|
978
|
+
items: {
|
|
979
|
+
$ref: "#/$defs/EndpointMount"
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
global: {
|
|
983
|
+
type: "array",
|
|
984
|
+
maxItems: 1,
|
|
985
|
+
items: {
|
|
986
|
+
$ref: "#/$defs/EndpointMount"
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
},
|
|
859
991
|
EndpointScaling: {
|
|
860
|
-
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY
|
|
992
|
+
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.",
|
|
861
993
|
oneOf: [
|
|
862
994
|
{
|
|
863
995
|
$ref: "#/$defs/QueueDelayScaling"
|
|
@@ -876,7 +1008,7 @@ var generatedTools = [
|
|
|
876
1008
|
},
|
|
877
1009
|
EndpointType: {
|
|
878
1010
|
type: "string",
|
|
879
|
-
description: "Request-routing semantics for a modern serverless endpoint
|
|
1011
|
+
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.",
|
|
880
1012
|
"x-enum-varnames": ["EndpointTypeQueue", "EndpointTypeLoadBalancer"],
|
|
881
1013
|
enum: ["QUEUE", "LOAD_BALANCER"]
|
|
882
1014
|
},
|
|
@@ -900,14 +1032,14 @@ var generatedTools = [
|
|
|
900
1032
|
type: "integer",
|
|
901
1033
|
minimum: 1,
|
|
902
1034
|
maximum: 3600,
|
|
903
|
-
description: "Seconds before idle workers scale down. Not applicable to queue-based
|
|
1035
|
+
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.",
|
|
904
1036
|
examples: [5]
|
|
905
1037
|
}
|
|
906
1038
|
}
|
|
907
1039
|
},
|
|
908
1040
|
FlashBoot: {
|
|
909
1041
|
type: "string",
|
|
910
|
-
description: "FlashBoot cold-start acceleration mode
|
|
1042
|
+
description: "FlashBoot cold-start acceleration mode. `OFF` \u2014 disabled. `FLASHBOOT` \u2014 enabled. `PRIORITY_FLASHBOOT` \u2014 enabled with priority capacity",
|
|
911
1043
|
enum: ["OFF", "FLASHBOOT", "PRIORITY_FLASHBOOT"]
|
|
912
1044
|
},
|
|
913
1045
|
QueueDelayScaling: {
|
|
@@ -933,7 +1065,7 @@ var generatedTools = [
|
|
|
933
1065
|
RequestCountScaling: {
|
|
934
1066
|
type: "object",
|
|
935
1067
|
additionalProperties: false,
|
|
936
|
-
description: "Scale on concurrent in-flight requests per worker. Required for
|
|
1068
|
+
description: "Scale on concurrent in-flight requests per worker. Required for load-balancing endpoints; also selectable for queue-based.",
|
|
937
1069
|
required: ["type", "requestCount"],
|
|
938
1070
|
properties: {
|
|
939
1071
|
type: {
|
|
@@ -952,6 +1084,47 @@ var generatedTools = [
|
|
|
952
1084
|
}
|
|
953
1085
|
}
|
|
954
1086
|
},
|
|
1087
|
+
{
|
|
1088
|
+
name: "create-global-volume",
|
|
1089
|
+
operationId: "createGlobalVolume",
|
|
1090
|
+
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`.",
|
|
1091
|
+
method: "POST",
|
|
1092
|
+
path: "/v2/global-volumes",
|
|
1093
|
+
params: [],
|
|
1094
|
+
hasBody: true,
|
|
1095
|
+
annotations: {
|
|
1096
|
+
readOnlyHint: false,
|
|
1097
|
+
destructiveHint: false,
|
|
1098
|
+
idempotentHint: false,
|
|
1099
|
+
openWorldHint: true
|
|
1100
|
+
},
|
|
1101
|
+
inputSchema: {
|
|
1102
|
+
type: "object",
|
|
1103
|
+
properties: {
|
|
1104
|
+
body: {
|
|
1105
|
+
$ref: "#/$defs/CreateGlobalVolumeRequest"
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
required: ["body"],
|
|
1109
|
+
$defs: {
|
|
1110
|
+
CreateGlobalVolumeRequest: {
|
|
1111
|
+
type: "object",
|
|
1112
|
+
additionalProperties: false,
|
|
1113
|
+
required: ["name"],
|
|
1114
|
+
properties: {
|
|
1115
|
+
name: {
|
|
1116
|
+
type: "string",
|
|
1117
|
+
minLength: 1,
|
|
1118
|
+
maxLength: 191,
|
|
1119
|
+
pattern: "[^\\p{Z}\\t-\\r\x85]",
|
|
1120
|
+
description: "Human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
|
|
1121
|
+
examples: ["training-data"]
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
},
|
|
955
1128
|
{
|
|
956
1129
|
name: "create-network-volume",
|
|
957
1130
|
operationId: "createNetworkVolume",
|
|
@@ -1005,7 +1178,7 @@ var generatedTools = [
|
|
|
1005
1178
|
$ref: "#/$defs/VolumeType"
|
|
1006
1179
|
}
|
|
1007
1180
|
],
|
|
1008
|
-
description: "Storage tier for the volume. Optional. When omitted, the volume is
|
|
1181
|
+
description: "Storage tier for the volume. Optional. When omitted, the volume is provisioned using the requested data center's default (primary) storage tier."
|
|
1009
1182
|
}
|
|
1010
1183
|
}
|
|
1011
1184
|
},
|
|
@@ -1031,6 +1204,7 @@ var generatedTools = [
|
|
|
1031
1204
|
idempotentHint: false,
|
|
1032
1205
|
openWorldHint: true
|
|
1033
1206
|
},
|
|
1207
|
+
schemaOnDemand: true,
|
|
1034
1208
|
inputSchema: {
|
|
1035
1209
|
type: "object",
|
|
1036
1210
|
properties: {
|
|
@@ -1042,11 +1216,10 @@ var generatedTools = [
|
|
|
1042
1216
|
$defs: {
|
|
1043
1217
|
BaseContainerConfig: {
|
|
1044
1218
|
type: "object",
|
|
1045
|
-
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",
|
|
1046
1219
|
properties: {
|
|
1047
1220
|
args: {
|
|
1048
1221
|
type: "string",
|
|
1049
|
-
description: 'The container\'s command
|
|
1222
|
+
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.',
|
|
1050
1223
|
examples: [
|
|
1051
1224
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
1052
1225
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -1058,7 +1231,7 @@ var generatedTools = [
|
|
|
1058
1231
|
items: {
|
|
1059
1232
|
type: "string"
|
|
1060
1233
|
},
|
|
1061
|
-
description: "Container CMD in exec form
|
|
1234
|
+
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.",
|
|
1062
1235
|
examples: [
|
|
1063
1236
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
1064
1237
|
]
|
|
@@ -1068,7 +1241,7 @@ var generatedTools = [
|
|
|
1068
1241
|
items: {
|
|
1069
1242
|
type: "string"
|
|
1070
1243
|
},
|
|
1071
|
-
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
|
|
1244
|
+
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.",
|
|
1072
1245
|
examples: [["/bin/bash", "-c"]]
|
|
1073
1246
|
},
|
|
1074
1247
|
disk: {
|
|
@@ -1140,13 +1313,27 @@ var generatedTools = [
|
|
|
1140
1313
|
}
|
|
1141
1314
|
}
|
|
1142
1315
|
},
|
|
1316
|
+
BaseMounts: {
|
|
1317
|
+
type: "object",
|
|
1318
|
+
properties: {
|
|
1319
|
+
persistent: {
|
|
1320
|
+
$ref: "#/$defs/PersistentMount"
|
|
1321
|
+
},
|
|
1322
|
+
network: {
|
|
1323
|
+
type: "array",
|
|
1324
|
+
maxItems: 1,
|
|
1325
|
+
items: {
|
|
1326
|
+
$ref: "#/$defs/NetworkMount"
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
},
|
|
1143
1331
|
Cloud: {
|
|
1144
1332
|
type: "string",
|
|
1145
|
-
description: "Cloud tier
|
|
1333
|
+
description: "Cloud tier. `SECURE` \u2014 Runpod-owned datacenter hardware. `COMMUNITY` \u2014 community-hosted hardware",
|
|
1146
1334
|
enum: ["SECURE", "COMMUNITY"]
|
|
1147
1335
|
},
|
|
1148
1336
|
ContainerConfig: {
|
|
1149
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
1150
1337
|
allOf: [
|
|
1151
1338
|
{
|
|
1152
1339
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -1172,7 +1359,7 @@ var generatedTools = [
|
|
|
1172
1359
|
unevaluatedProperties: false
|
|
1173
1360
|
},
|
|
1174
1361
|
CreateGpuConfig: {
|
|
1175
|
-
description: "GPU request for a pod create. Carries the CUDA host constraints, which
|
|
1362
|
+
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.",
|
|
1176
1363
|
allOf: [
|
|
1177
1364
|
{
|
|
1178
1365
|
$ref: "#/$defs/BaseGpuConfig"
|
|
@@ -1186,13 +1373,13 @@ var generatedTools = [
|
|
|
1186
1373
|
type: "string",
|
|
1187
1374
|
pattern: "^\\d+\\.\\d+$"
|
|
1188
1375
|
},
|
|
1189
|
-
description: "Acceptable CUDA versions for the host machine, as `major.minor
|
|
1376
|
+
description: "Acceptable CUDA versions for the host machine, as `major.minor`. Omit to accept any version.",
|
|
1190
1377
|
examples: [["12.8", "12.6"]]
|
|
1191
1378
|
},
|
|
1192
1379
|
minCudaVersion: {
|
|
1193
1380
|
type: "string",
|
|
1194
1381
|
pattern: "^\\d+\\.\\d+$",
|
|
1195
|
-
description: "Lowest acceptable CUDA version for the host machine, as
|
|
1382
|
+
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.",
|
|
1196
1383
|
examples: ["12.1"]
|
|
1197
1384
|
},
|
|
1198
1385
|
minRamPerGpu: {
|
|
@@ -1220,7 +1407,7 @@ var generatedTools = [
|
|
|
1220
1407
|
{
|
|
1221
1408
|
type: "object",
|
|
1222
1409
|
required: ["name"],
|
|
1223
|
-
description: "Request body for creating a pod. Exactly one of `gpu` or `cpu
|
|
1410
|
+
description: "Request body for creating a pod. Exactly one of `gpu` or `cpu` must be set \u2014 enforced at the handler layer.",
|
|
1224
1411
|
properties: {
|
|
1225
1412
|
name: {
|
|
1226
1413
|
type: "string",
|
|
@@ -1244,13 +1431,13 @@ var generatedTools = [
|
|
|
1244
1431
|
items: {
|
|
1245
1432
|
type: "string"
|
|
1246
1433
|
},
|
|
1247
|
-
description: "Preferred data centers for placement. Omit or pass an empty
|
|
1434
|
+
description: "Preferred data centers for placement. Omit or pass an empty array to let the scheduler choose.",
|
|
1248
1435
|
examples: [["US-TX-3"]]
|
|
1249
1436
|
},
|
|
1250
1437
|
globalNetworking: {
|
|
1251
1438
|
type: "boolean",
|
|
1252
1439
|
default: false,
|
|
1253
|
-
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).
|
|
1440
|
+
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).",
|
|
1254
1441
|
examples: [false]
|
|
1255
1442
|
},
|
|
1256
1443
|
gpu: {
|
|
@@ -1262,19 +1449,19 @@ var generatedTools = [
|
|
|
1262
1449
|
startJupyter: {
|
|
1263
1450
|
type: "boolean",
|
|
1264
1451
|
default: false,
|
|
1265
|
-
description: "Create-time flag
|
|
1452
|
+
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.",
|
|
1266
1453
|
examples: [true]
|
|
1267
1454
|
},
|
|
1268
1455
|
startSsh: {
|
|
1269
1456
|
type: "boolean",
|
|
1270
1457
|
default: false,
|
|
1271
|
-
description: "Create-time flag
|
|
1458
|
+
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`.",
|
|
1272
1459
|
examples: [true]
|
|
1273
1460
|
},
|
|
1274
1461
|
templateId: {
|
|
1275
1462
|
type: "string",
|
|
1276
1463
|
minLength: 1,
|
|
1277
|
-
description: "ID of a pod template to base this pod on
|
|
1464
|
+
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.",
|
|
1278
1465
|
examples: ["30zmvf89kd"]
|
|
1279
1466
|
}
|
|
1280
1467
|
}
|
|
@@ -1290,28 +1477,51 @@ var generatedTools = [
|
|
|
1290
1477
|
required: ["image"]
|
|
1291
1478
|
}
|
|
1292
1479
|
},
|
|
1293
|
-
|
|
1480
|
+
GlobalMount: {
|
|
1294
1481
|
type: "object",
|
|
1482
|
+
required: ["volumeId"],
|
|
1295
1483
|
additionalProperties: false,
|
|
1296
|
-
description: "
|
|
1484
|
+
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.",
|
|
1297
1485
|
properties: {
|
|
1298
|
-
|
|
1299
|
-
|
|
1486
|
+
volumeId: {
|
|
1487
|
+
type: "string",
|
|
1488
|
+
description: "ID of an existing GlobalVolume.",
|
|
1489
|
+
examples: ["gsb_abc"]
|
|
1300
1490
|
},
|
|
1301
|
-
|
|
1302
|
-
type: "
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
$ref: "#/$defs/NetworkMount"
|
|
1306
|
-
}
|
|
1491
|
+
path: {
|
|
1492
|
+
type: "string",
|
|
1493
|
+
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.",
|
|
1494
|
+
examples: ["/data"]
|
|
1307
1495
|
}
|
|
1308
1496
|
}
|
|
1309
1497
|
},
|
|
1498
|
+
Mounts: {
|
|
1499
|
+
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.",
|
|
1500
|
+
allOf: [
|
|
1501
|
+
{
|
|
1502
|
+
$ref: "#/$defs/BaseMounts"
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
type: "object",
|
|
1506
|
+
properties: {
|
|
1507
|
+
global: {
|
|
1508
|
+
type: "array",
|
|
1509
|
+
maxItems: 1,
|
|
1510
|
+
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.",
|
|
1511
|
+
items: {
|
|
1512
|
+
$ref: "#/$defs/GlobalMount"
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
],
|
|
1518
|
+
unevaluatedProperties: false
|
|
1519
|
+
},
|
|
1310
1520
|
NetworkMount: {
|
|
1311
1521
|
type: "object",
|
|
1312
1522
|
required: ["volumeId", "path"],
|
|
1313
1523
|
additionalProperties: false,
|
|
1314
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
1524
|
+
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.",
|
|
1315
1525
|
properties: {
|
|
1316
1526
|
volumeId: {
|
|
1317
1527
|
type: "string",
|
|
@@ -1329,7 +1539,7 @@ var generatedTools = [
|
|
|
1329
1539
|
type: "object",
|
|
1330
1540
|
required: ["size", "path"],
|
|
1331
1541
|
additionalProperties: false,
|
|
1332
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
1542
|
+
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.",
|
|
1333
1543
|
properties: {
|
|
1334
1544
|
size: {
|
|
1335
1545
|
type: "integer",
|
|
@@ -1412,6 +1622,7 @@ var generatedTools = [
|
|
|
1412
1622
|
idempotentHint: false,
|
|
1413
1623
|
openWorldHint: true
|
|
1414
1624
|
},
|
|
1625
|
+
schemaOnDemand: true,
|
|
1415
1626
|
inputSchema: {
|
|
1416
1627
|
type: "object",
|
|
1417
1628
|
properties: {
|
|
@@ -1431,7 +1642,7 @@ var generatedTools = [
|
|
|
1431
1642
|
minLength: 1,
|
|
1432
1643
|
maxLength: 191,
|
|
1433
1644
|
pattern: "^[a-zA-Z_][a-zA-Z0-9_.\\-/]*$",
|
|
1434
|
-
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 `_.-/`.
|
|
1645
|
+
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 `_.-/`.",
|
|
1435
1646
|
examples: ["hf-token"]
|
|
1436
1647
|
},
|
|
1437
1648
|
value: {
|
|
@@ -1465,6 +1676,7 @@ var generatedTools = [
|
|
|
1465
1676
|
idempotentHint: false,
|
|
1466
1677
|
openWorldHint: true
|
|
1467
1678
|
},
|
|
1679
|
+
schemaOnDemand: true,
|
|
1468
1680
|
inputSchema: {
|
|
1469
1681
|
type: "object",
|
|
1470
1682
|
properties: {
|
|
@@ -1476,11 +1688,10 @@ var generatedTools = [
|
|
|
1476
1688
|
$defs: {
|
|
1477
1689
|
BaseContainerConfig: {
|
|
1478
1690
|
type: "object",
|
|
1479
|
-
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",
|
|
1480
1691
|
properties: {
|
|
1481
1692
|
args: {
|
|
1482
1693
|
type: "string",
|
|
1483
|
-
description: 'The container\'s command
|
|
1694
|
+
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.',
|
|
1484
1695
|
examples: [
|
|
1485
1696
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
1486
1697
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -1492,7 +1703,7 @@ var generatedTools = [
|
|
|
1492
1703
|
items: {
|
|
1493
1704
|
type: "string"
|
|
1494
1705
|
},
|
|
1495
|
-
description: "Container CMD in exec form
|
|
1706
|
+
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.",
|
|
1496
1707
|
examples: [
|
|
1497
1708
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
1498
1709
|
]
|
|
@@ -1502,7 +1713,7 @@ var generatedTools = [
|
|
|
1502
1713
|
items: {
|
|
1503
1714
|
type: "string"
|
|
1504
1715
|
},
|
|
1505
|
-
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
|
|
1716
|
+
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.",
|
|
1506
1717
|
examples: [["/bin/bash", "-c"]]
|
|
1507
1718
|
},
|
|
1508
1719
|
disk: {
|
|
@@ -1539,7 +1750,6 @@ var generatedTools = [
|
|
|
1539
1750
|
}
|
|
1540
1751
|
},
|
|
1541
1752
|
ContainerConfig: {
|
|
1542
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
1543
1753
|
allOf: [
|
|
1544
1754
|
{
|
|
1545
1755
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -1576,7 +1786,7 @@ var generatedTools = [
|
|
|
1576
1786
|
type: "string",
|
|
1577
1787
|
pattern: "^\\d+\\.\\d+$"
|
|
1578
1788
|
},
|
|
1579
|
-
description: "Acceptable CUDA versions for containers created from this
|
|
1789
|
+
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.",
|
|
1580
1790
|
examples: [["12.8", "12.6"]]
|
|
1581
1791
|
},
|
|
1582
1792
|
category: {
|
|
@@ -1602,13 +1812,13 @@ var generatedTools = [
|
|
|
1602
1812
|
startJupyter: {
|
|
1603
1813
|
type: "boolean",
|
|
1604
1814
|
default: true,
|
|
1605
|
-
description: "Start JupyterLab in containers created from this template
|
|
1815
|
+
description: "Start JupyterLab in containers created from this template: injects a generated `JUPYTER_PASSWORD` environment variable, unless `env` already sets one.",
|
|
1606
1816
|
examples: [false]
|
|
1607
1817
|
},
|
|
1608
1818
|
startSsh: {
|
|
1609
1819
|
type: "boolean",
|
|
1610
1820
|
default: true,
|
|
1611
|
-
description: "Provision SSH access in containers created from this template
|
|
1821
|
+
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.",
|
|
1612
1822
|
examples: [true]
|
|
1613
1823
|
}
|
|
1614
1824
|
}
|
|
@@ -1620,7 +1830,7 @@ var generatedTools = [
|
|
|
1620
1830
|
type: "object",
|
|
1621
1831
|
required: ["size", "path"],
|
|
1622
1832
|
additionalProperties: false,
|
|
1623
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
1833
|
+
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.",
|
|
1624
1834
|
properties: {
|
|
1625
1835
|
size: {
|
|
1626
1836
|
type: "integer",
|
|
@@ -1637,13 +1847,13 @@ var generatedTools = [
|
|
|
1637
1847
|
},
|
|
1638
1848
|
TemplateCategory: {
|
|
1639
1849
|
type: "string",
|
|
1640
|
-
description: "Controls how the template is grouped and filtered in the Runpod console
|
|
1850
|
+
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",
|
|
1641
1851
|
enum: ["CPU", "NVIDIA", "AMD"]
|
|
1642
1852
|
},
|
|
1643
1853
|
TemplateMounts: {
|
|
1644
1854
|
type: "object",
|
|
1645
1855
|
additionalProperties: false,
|
|
1646
|
-
description: "Storage mounts
|
|
1856
|
+
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.",
|
|
1647
1857
|
properties: {
|
|
1648
1858
|
persistent: {
|
|
1649
1859
|
$ref: "#/$defs/PersistentMount"
|
|
@@ -1713,6 +1923,36 @@ var generatedTools = [
|
|
|
1713
1923
|
required: ["id"]
|
|
1714
1924
|
}
|
|
1715
1925
|
},
|
|
1926
|
+
{
|
|
1927
|
+
name: "delete-global-volume",
|
|
1928
|
+
operationId: "deleteGlobalVolume",
|
|
1929
|
+
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.",
|
|
1930
|
+
method: "DELETE",
|
|
1931
|
+
path: "/v2/global-volumes/{id}",
|
|
1932
|
+
params: [
|
|
1933
|
+
{
|
|
1934
|
+
name: "id",
|
|
1935
|
+
location: "path"
|
|
1936
|
+
}
|
|
1937
|
+
],
|
|
1938
|
+
hasBody: false,
|
|
1939
|
+
annotations: {
|
|
1940
|
+
readOnlyHint: false,
|
|
1941
|
+
destructiveHint: true,
|
|
1942
|
+
idempotentHint: true,
|
|
1943
|
+
openWorldHint: true
|
|
1944
|
+
},
|
|
1945
|
+
inputSchema: {
|
|
1946
|
+
type: "object",
|
|
1947
|
+
properties: {
|
|
1948
|
+
id: {
|
|
1949
|
+
type: "string",
|
|
1950
|
+
description: "Global volume identifier"
|
|
1951
|
+
}
|
|
1952
|
+
},
|
|
1953
|
+
required: ["id"]
|
|
1954
|
+
}
|
|
1955
|
+
},
|
|
1716
1956
|
{
|
|
1717
1957
|
name: "delete-network-volume",
|
|
1718
1958
|
operationId: "deleteNetworkVolume",
|
|
@@ -2078,12 +2318,42 @@ var generatedTools = [
|
|
|
2078
2318
|
},
|
|
2079
2319
|
buildId: {
|
|
2080
2320
|
type: "string",
|
|
2081
|
-
description: "GitHub build identifier (from
|
|
2321
|
+
description: "GitHub build identifier (from `list-endpoint-builds` or a release's `buildId`)"
|
|
2082
2322
|
}
|
|
2083
2323
|
},
|
|
2084
2324
|
required: ["id", "buildId"]
|
|
2085
2325
|
}
|
|
2086
2326
|
},
|
|
2327
|
+
{
|
|
2328
|
+
name: "get-global-volume",
|
|
2329
|
+
operationId: "getGlobalVolume",
|
|
2330
|
+
description: "Get a global volume. Returns a single global volume by ID.",
|
|
2331
|
+
method: "GET",
|
|
2332
|
+
path: "/v2/global-volumes/{id}",
|
|
2333
|
+
params: [
|
|
2334
|
+
{
|
|
2335
|
+
name: "id",
|
|
2336
|
+
location: "path"
|
|
2337
|
+
}
|
|
2338
|
+
],
|
|
2339
|
+
hasBody: false,
|
|
2340
|
+
annotations: {
|
|
2341
|
+
readOnlyHint: true,
|
|
2342
|
+
destructiveHint: false,
|
|
2343
|
+
idempotentHint: true,
|
|
2344
|
+
openWorldHint: true
|
|
2345
|
+
},
|
|
2346
|
+
inputSchema: {
|
|
2347
|
+
type: "object",
|
|
2348
|
+
properties: {
|
|
2349
|
+
id: {
|
|
2350
|
+
type: "string",
|
|
2351
|
+
description: "Global volume identifier"
|
|
2352
|
+
}
|
|
2353
|
+
},
|
|
2354
|
+
required: ["id"]
|
|
2355
|
+
}
|
|
2356
|
+
},
|
|
2087
2357
|
{
|
|
2088
2358
|
name: "get-gpu-type",
|
|
2089
2359
|
operationId: "getGpuType",
|
|
@@ -2154,7 +2424,7 @@ var generatedTools = [
|
|
|
2154
2424
|
items: {
|
|
2155
2425
|
$ref: "#/$defs/Product"
|
|
2156
2426
|
},
|
|
2157
|
-
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way).
|
|
2427
|
+
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way)."
|
|
2158
2428
|
},
|
|
2159
2429
|
count: {
|
|
2160
2430
|
type: "integer",
|
|
@@ -2172,7 +2442,7 @@ var generatedTools = [
|
|
|
2172
2442
|
type: "string",
|
|
2173
2443
|
pattern: "^[A-Z]{2}$"
|
|
2174
2444
|
},
|
|
2175
|
-
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
|
|
2445
|
+
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."
|
|
2176
2446
|
},
|
|
2177
2447
|
cudaVersions: {
|
|
2178
2448
|
type: "array",
|
|
@@ -2180,12 +2450,12 @@ var generatedTools = [
|
|
|
2180
2450
|
type: "string",
|
|
2181
2451
|
pattern: "^\\d+\\.\\d+$"
|
|
2182
2452
|
},
|
|
2183
|
-
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.
|
|
2453
|
+
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."
|
|
2184
2454
|
},
|
|
2185
2455
|
minCudaVersion: {
|
|
2186
2456
|
type: "string",
|
|
2187
2457
|
pattern: "^\\d+(\\.\\d+)?$",
|
|
2188
|
-
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically.
|
|
2458
|
+
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically."
|
|
2189
2459
|
}
|
|
2190
2460
|
},
|
|
2191
2461
|
required: ["id"],
|
|
@@ -2238,6 +2508,25 @@ var generatedTools = [
|
|
|
2238
2508
|
required: ["id"]
|
|
2239
2509
|
}
|
|
2240
2510
|
},
|
|
2511
|
+
{
|
|
2512
|
+
name: "get-organization",
|
|
2513
|
+
operationId: "getOrganization",
|
|
2514
|
+
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.",
|
|
2515
|
+
method: "GET",
|
|
2516
|
+
path: "/v2/organization",
|
|
2517
|
+
params: [],
|
|
2518
|
+
hasBody: false,
|
|
2519
|
+
annotations: {
|
|
2520
|
+
readOnlyHint: true,
|
|
2521
|
+
destructiveHint: false,
|
|
2522
|
+
idempotentHint: true,
|
|
2523
|
+
openWorldHint: true
|
|
2524
|
+
},
|
|
2525
|
+
inputSchema: {
|
|
2526
|
+
type: "object",
|
|
2527
|
+
properties: {}
|
|
2528
|
+
}
|
|
2529
|
+
},
|
|
2241
2530
|
{
|
|
2242
2531
|
name: "get-pod",
|
|
2243
2532
|
operationId: "getPod",
|
|
@@ -2412,12 +2701,12 @@ var generatedTools = [
|
|
|
2412
2701
|
startTime: {
|
|
2413
2702
|
type: "string",
|
|
2414
2703
|
format: "date-time",
|
|
2415
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
2704
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2416
2705
|
},
|
|
2417
2706
|
endTime: {
|
|
2418
2707
|
type: "string",
|
|
2419
2708
|
format: "date-time",
|
|
2420
|
-
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
|
|
2709
|
+
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."
|
|
2421
2710
|
},
|
|
2422
2711
|
bucketSize: {
|
|
2423
2712
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2426,7 +2715,7 @@ var generatedTools = [
|
|
|
2426
2715
|
lastN: {
|
|
2427
2716
|
type: "integer",
|
|
2428
2717
|
minimum: 1,
|
|
2429
|
-
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".
|
|
2718
|
+
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".'
|
|
2430
2719
|
}
|
|
2431
2720
|
},
|
|
2432
2721
|
$defs: {
|
|
@@ -2488,12 +2777,12 @@ var generatedTools = [
|
|
|
2488
2777
|
startTime: {
|
|
2489
2778
|
type: "string",
|
|
2490
2779
|
format: "date-time",
|
|
2491
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
2780
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2492
2781
|
},
|
|
2493
2782
|
endTime: {
|
|
2494
2783
|
type: "string",
|
|
2495
2784
|
format: "date-time",
|
|
2496
|
-
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
|
|
2785
|
+
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."
|
|
2497
2786
|
},
|
|
2498
2787
|
bucketSize: {
|
|
2499
2788
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2502,7 +2791,7 @@ var generatedTools = [
|
|
|
2502
2791
|
lastN: {
|
|
2503
2792
|
type: "integer",
|
|
2504
2793
|
minimum: 1,
|
|
2505
|
-
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".
|
|
2794
|
+
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".'
|
|
2506
2795
|
},
|
|
2507
2796
|
clusterId: {
|
|
2508
2797
|
type: "string",
|
|
@@ -2560,10 +2849,19 @@ var generatedTools = [
|
|
|
2560
2849
|
{
|
|
2561
2850
|
name: "list-clusters",
|
|
2562
2851
|
operationId: "listClusters",
|
|
2563
|
-
description: "List clusters. Returns
|
|
2852
|
+
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.",
|
|
2564
2853
|
method: "GET",
|
|
2565
2854
|
path: "/v2/clusters",
|
|
2566
|
-
params: [
|
|
2855
|
+
params: [
|
|
2856
|
+
{
|
|
2857
|
+
name: "cursor",
|
|
2858
|
+
location: "query"
|
|
2859
|
+
},
|
|
2860
|
+
{
|
|
2861
|
+
name: "limit",
|
|
2862
|
+
location: "query"
|
|
2863
|
+
}
|
|
2864
|
+
],
|
|
2567
2865
|
hasBody: false,
|
|
2568
2866
|
annotations: {
|
|
2569
2867
|
readOnlyHint: true,
|
|
@@ -2573,7 +2871,19 @@ var generatedTools = [
|
|
|
2573
2871
|
},
|
|
2574
2872
|
inputSchema: {
|
|
2575
2873
|
type: "object",
|
|
2576
|
-
properties: {
|
|
2874
|
+
properties: {
|
|
2875
|
+
cursor: {
|
|
2876
|
+
type: "string",
|
|
2877
|
+
minLength: 1,
|
|
2878
|
+
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."
|
|
2879
|
+
},
|
|
2880
|
+
limit: {
|
|
2881
|
+
type: "integer",
|
|
2882
|
+
minimum: 1,
|
|
2883
|
+
maximum: 1e3,
|
|
2884
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2577
2887
|
}
|
|
2578
2888
|
},
|
|
2579
2889
|
{
|
|
@@ -2827,12 +3137,12 @@ var generatedTools = [
|
|
|
2827
3137
|
startTime: {
|
|
2828
3138
|
type: "string",
|
|
2829
3139
|
format: "date-time",
|
|
2830
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3140
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
2831
3141
|
},
|
|
2832
3142
|
endTime: {
|
|
2833
3143
|
type: "string",
|
|
2834
3144
|
format: "date-time",
|
|
2835
|
-
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
|
|
3145
|
+
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."
|
|
2836
3146
|
},
|
|
2837
3147
|
bucketSize: {
|
|
2838
3148
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -2841,7 +3151,7 @@ var generatedTools = [
|
|
|
2841
3151
|
lastN: {
|
|
2842
3152
|
type: "integer",
|
|
2843
3153
|
minimum: 1,
|
|
2844
|
-
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".
|
|
3154
|
+
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".'
|
|
2845
3155
|
}
|
|
2846
3156
|
},
|
|
2847
3157
|
$defs: {
|
|
@@ -2899,7 +3209,7 @@ var generatedTools = [
|
|
|
2899
3209
|
cursor: {
|
|
2900
3210
|
type: "string",
|
|
2901
3211
|
minLength: 1,
|
|
2902
|
-
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
|
|
3212
|
+
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."
|
|
2903
3213
|
},
|
|
2904
3214
|
limit: {
|
|
2905
3215
|
type: "integer",
|
|
@@ -2948,7 +3258,7 @@ var generatedTools = [
|
|
|
2948
3258
|
cursor: {
|
|
2949
3259
|
type: "string",
|
|
2950
3260
|
minLength: 1,
|
|
2951
|
-
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
|
|
3261
|
+
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."
|
|
2952
3262
|
},
|
|
2953
3263
|
limit: {
|
|
2954
3264
|
type: "integer",
|
|
@@ -2990,6 +3300,46 @@ var generatedTools = [
|
|
|
2990
3300
|
required: ["id"]
|
|
2991
3301
|
}
|
|
2992
3302
|
},
|
|
3303
|
+
{
|
|
3304
|
+
name: "list-global-volumes",
|
|
3305
|
+
operationId: "listGlobalVolumes",
|
|
3306
|
+
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.",
|
|
3307
|
+
method: "GET",
|
|
3308
|
+
path: "/v2/global-volumes",
|
|
3309
|
+
params: [
|
|
3310
|
+
{
|
|
3311
|
+
name: "cursor",
|
|
3312
|
+
location: "query"
|
|
3313
|
+
},
|
|
3314
|
+
{
|
|
3315
|
+
name: "limit",
|
|
3316
|
+
location: "query"
|
|
3317
|
+
}
|
|
3318
|
+
],
|
|
3319
|
+
hasBody: false,
|
|
3320
|
+
annotations: {
|
|
3321
|
+
readOnlyHint: true,
|
|
3322
|
+
destructiveHint: false,
|
|
3323
|
+
idempotentHint: true,
|
|
3324
|
+
openWorldHint: true
|
|
3325
|
+
},
|
|
3326
|
+
inputSchema: {
|
|
3327
|
+
type: "object",
|
|
3328
|
+
properties: {
|
|
3329
|
+
cursor: {
|
|
3330
|
+
type: "string",
|
|
3331
|
+
minLength: 1,
|
|
3332
|
+
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."
|
|
3333
|
+
},
|
|
3334
|
+
limit: {
|
|
3335
|
+
type: "integer",
|
|
3336
|
+
minimum: 1,
|
|
3337
|
+
maximum: 1e3,
|
|
3338
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
},
|
|
2993
3343
|
{
|
|
2994
3344
|
name: "list-gpu-types",
|
|
2995
3345
|
operationId: "listGpuTypes",
|
|
@@ -3053,7 +3403,7 @@ var generatedTools = [
|
|
|
3053
3403
|
items: {
|
|
3054
3404
|
$ref: "#/$defs/Product"
|
|
3055
3405
|
},
|
|
3056
|
-
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way).
|
|
3406
|
+
description: "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way)."
|
|
3057
3407
|
},
|
|
3058
3408
|
count: {
|
|
3059
3409
|
type: "integer",
|
|
@@ -3071,7 +3421,7 @@ var generatedTools = [
|
|
|
3071
3421
|
type: "string",
|
|
3072
3422
|
pattern: "^[A-Z]{2}$"
|
|
3073
3423
|
},
|
|
3074
|
-
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
|
|
3424
|
+
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."
|
|
3075
3425
|
},
|
|
3076
3426
|
cudaVersions: {
|
|
3077
3427
|
type: "array",
|
|
@@ -3079,12 +3429,12 @@ var generatedTools = [
|
|
|
3079
3429
|
type: "string",
|
|
3080
3430
|
pattern: "^\\d+\\.\\d+$"
|
|
3081
3431
|
},
|
|
3082
|
-
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.
|
|
3432
|
+
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."
|
|
3083
3433
|
},
|
|
3084
3434
|
minCudaVersion: {
|
|
3085
3435
|
type: "string",
|
|
3086
3436
|
pattern: "^\\d+(\\.\\d+)?$",
|
|
3087
|
-
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically.
|
|
3437
|
+
description: "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically."
|
|
3088
3438
|
}
|
|
3089
3439
|
},
|
|
3090
3440
|
$defs: {
|
|
@@ -3147,12 +3497,12 @@ var generatedTools = [
|
|
|
3147
3497
|
startTime: {
|
|
3148
3498
|
type: "string",
|
|
3149
3499
|
format: "date-time",
|
|
3150
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3500
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3151
3501
|
},
|
|
3152
3502
|
endTime: {
|
|
3153
3503
|
type: "string",
|
|
3154
3504
|
format: "date-time",
|
|
3155
|
-
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
|
|
3505
|
+
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."
|
|
3156
3506
|
},
|
|
3157
3507
|
bucketSize: {
|
|
3158
3508
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3161,7 +3511,7 @@ var generatedTools = [
|
|
|
3161
3511
|
lastN: {
|
|
3162
3512
|
type: "integer",
|
|
3163
3513
|
minimum: 1,
|
|
3164
|
-
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".
|
|
3514
|
+
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".'
|
|
3165
3515
|
},
|
|
3166
3516
|
networkVolumeId: {
|
|
3167
3517
|
type: "string",
|
|
@@ -3189,10 +3539,19 @@ var generatedTools = [
|
|
|
3189
3539
|
{
|
|
3190
3540
|
name: "list-network-volumes",
|
|
3191
3541
|
operationId: "listNetworkVolumes",
|
|
3192
|
-
description: "List network volumes. Returns
|
|
3542
|
+
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.",
|
|
3193
3543
|
method: "GET",
|
|
3194
3544
|
path: "/v2/network-volumes",
|
|
3195
|
-
params: [
|
|
3545
|
+
params: [
|
|
3546
|
+
{
|
|
3547
|
+
name: "cursor",
|
|
3548
|
+
location: "query"
|
|
3549
|
+
},
|
|
3550
|
+
{
|
|
3551
|
+
name: "limit",
|
|
3552
|
+
location: "query"
|
|
3553
|
+
}
|
|
3554
|
+
],
|
|
3196
3555
|
hasBody: false,
|
|
3197
3556
|
annotations: {
|
|
3198
3557
|
readOnlyHint: true,
|
|
@@ -3202,7 +3561,19 @@ var generatedTools = [
|
|
|
3202
3561
|
},
|
|
3203
3562
|
inputSchema: {
|
|
3204
3563
|
type: "object",
|
|
3205
|
-
properties: {
|
|
3564
|
+
properties: {
|
|
3565
|
+
cursor: {
|
|
3566
|
+
type: "string",
|
|
3567
|
+
minLength: 1,
|
|
3568
|
+
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."
|
|
3569
|
+
},
|
|
3570
|
+
limit: {
|
|
3571
|
+
type: "integer",
|
|
3572
|
+
minimum: 1,
|
|
3573
|
+
maximum: 1e3,
|
|
3574
|
+
description: "Page size, 1\u20131000. Defaults to 1000 when omitted."
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3206
3577
|
}
|
|
3207
3578
|
},
|
|
3208
3579
|
{
|
|
@@ -3246,12 +3617,12 @@ var generatedTools = [
|
|
|
3246
3617
|
startTime: {
|
|
3247
3618
|
type: "string",
|
|
3248
3619
|
format: "date-time",
|
|
3249
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3620
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3250
3621
|
},
|
|
3251
3622
|
endTime: {
|
|
3252
3623
|
type: "string",
|
|
3253
3624
|
format: "date-time",
|
|
3254
|
-
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
|
|
3625
|
+
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."
|
|
3255
3626
|
},
|
|
3256
3627
|
bucketSize: {
|
|
3257
3628
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3260,7 +3631,7 @@ var generatedTools = [
|
|
|
3260
3631
|
lastN: {
|
|
3261
3632
|
type: "integer",
|
|
3262
3633
|
minimum: 1,
|
|
3263
|
-
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".
|
|
3634
|
+
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".'
|
|
3264
3635
|
},
|
|
3265
3636
|
podId: {
|
|
3266
3637
|
type: "string",
|
|
@@ -3288,7 +3659,7 @@ var generatedTools = [
|
|
|
3288
3659
|
{
|
|
3289
3660
|
name: "list-pods",
|
|
3290
3661
|
operationId: "listPods",
|
|
3291
|
-
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.
|
|
3662
|
+
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.",
|
|
3292
3663
|
method: "GET",
|
|
3293
3664
|
path: "/v2/pods",
|
|
3294
3665
|
params: [
|
|
@@ -3323,7 +3694,7 @@ var generatedTools = [
|
|
|
3323
3694
|
cursor: {
|
|
3324
3695
|
type: "string",
|
|
3325
3696
|
minLength: 1,
|
|
3326
|
-
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
|
|
3697
|
+
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."
|
|
3327
3698
|
},
|
|
3328
3699
|
limit: {
|
|
3329
3700
|
type: "integer",
|
|
@@ -3360,7 +3731,7 @@ var generatedTools = [
|
|
|
3360
3731
|
type: "string",
|
|
3361
3732
|
enum: ["official", "verified", "community"],
|
|
3362
3733
|
default: "official",
|
|
3363
|
-
description: "Which slice of the catalog to return: `official` for
|
|
3734
|
+
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."
|
|
3364
3735
|
}
|
|
3365
3736
|
}
|
|
3366
3737
|
}
|
|
@@ -3454,12 +3825,12 @@ var generatedTools = [
|
|
|
3454
3825
|
startTime: {
|
|
3455
3826
|
type: "string",
|
|
3456
3827
|
format: "date-time",
|
|
3457
|
-
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago.
|
|
3828
|
+
description: "Start of the billing period (RFC 3339). Defaults to 30 days ago."
|
|
3458
3829
|
},
|
|
3459
3830
|
endTime: {
|
|
3460
3831
|
type: "string",
|
|
3461
3832
|
format: "date-time",
|
|
3462
|
-
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
|
|
3833
|
+
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."
|
|
3463
3834
|
},
|
|
3464
3835
|
bucketSize: {
|
|
3465
3836
|
$ref: "#/$defs/BillingBucketSize",
|
|
@@ -3468,7 +3839,7 @@ var generatedTools = [
|
|
|
3468
3839
|
lastN: {
|
|
3469
3840
|
type: "integer",
|
|
3470
3841
|
minimum: 1,
|
|
3471
|
-
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".
|
|
3842
|
+
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".'
|
|
3472
3843
|
},
|
|
3473
3844
|
serverlessId: {
|
|
3474
3845
|
type: "string",
|
|
@@ -3607,7 +3978,7 @@ var generatedTools = [
|
|
|
3607
3978
|
type: "object",
|
|
3608
3979
|
additionalProperties: false,
|
|
3609
3980
|
minProperties: 1,
|
|
3610
|
-
description: "Request body for updating a cluster. Only the cluster name can be
|
|
3981
|
+
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.",
|
|
3611
3982
|
properties: {
|
|
3612
3983
|
name: {
|
|
3613
3984
|
type: "string",
|
|
@@ -3638,6 +4009,7 @@ var generatedTools = [
|
|
|
3638
4009
|
idempotentHint: false,
|
|
3639
4010
|
openWorldHint: true
|
|
3640
4011
|
},
|
|
4012
|
+
schemaOnDemand: true,
|
|
3641
4013
|
inputSchema: {
|
|
3642
4014
|
type: "object",
|
|
3643
4015
|
properties: {
|
|
@@ -3653,11 +4025,10 @@ var generatedTools = [
|
|
|
3653
4025
|
$defs: {
|
|
3654
4026
|
BaseContainerConfig: {
|
|
3655
4027
|
type: "object",
|
|
3656
|
-
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",
|
|
3657
4028
|
properties: {
|
|
3658
4029
|
args: {
|
|
3659
4030
|
type: "string",
|
|
3660
|
-
description: 'The container\'s command
|
|
4031
|
+
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.',
|
|
3661
4032
|
examples: [
|
|
3662
4033
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
3663
4034
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -3669,7 +4040,7 @@ var generatedTools = [
|
|
|
3669
4040
|
items: {
|
|
3670
4041
|
type: "string"
|
|
3671
4042
|
},
|
|
3672
|
-
description: "Container CMD in exec form
|
|
4043
|
+
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.",
|
|
3673
4044
|
examples: [
|
|
3674
4045
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
3675
4046
|
]
|
|
@@ -3679,7 +4050,7 @@ var generatedTools = [
|
|
|
3679
4050
|
items: {
|
|
3680
4051
|
type: "string"
|
|
3681
4052
|
},
|
|
3682
|
-
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
|
|
4053
|
+
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.",
|
|
3683
4054
|
examples: [["/bin/bash", "-c"]]
|
|
3684
4055
|
},
|
|
3685
4056
|
disk: {
|
|
@@ -3739,7 +4110,7 @@ var generatedTools = [
|
|
|
3739
4110
|
pools: {
|
|
3740
4111
|
type: "array",
|
|
3741
4112
|
minItems: 1,
|
|
3742
|
-
description:
|
|
4113
|
+
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.",
|
|
3743
4114
|
items: {
|
|
3744
4115
|
type: "string"
|
|
3745
4116
|
},
|
|
@@ -3748,7 +4119,7 @@ var generatedTools = [
|
|
|
3748
4119
|
excludedTypes: {
|
|
3749
4120
|
type: "array",
|
|
3750
4121
|
uniqueItems: true,
|
|
3751
|
-
description:
|
|
4122
|
+
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.",
|
|
3752
4123
|
items: {
|
|
3753
4124
|
type: "string",
|
|
3754
4125
|
pattern: "^\\s*[^-\\s]"
|
|
@@ -3765,7 +4136,6 @@ var generatedTools = [
|
|
|
3765
4136
|
}
|
|
3766
4137
|
},
|
|
3767
4138
|
ContainerConfig: {
|
|
3768
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
3769
4139
|
allOf: [
|
|
3770
4140
|
{
|
|
3771
4141
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -3790,8 +4160,42 @@ var generatedTools = [
|
|
|
3790
4160
|
],
|
|
3791
4161
|
unevaluatedProperties: false
|
|
3792
4162
|
},
|
|
4163
|
+
EndpointMount: {
|
|
4164
|
+
type: "object",
|
|
4165
|
+
required: ["volumeId"],
|
|
4166
|
+
additionalProperties: false,
|
|
4167
|
+
description: "A volume mounted on every worker, always at `/runpod-volume`. Custom paths are not supported yet.",
|
|
4168
|
+
properties: {
|
|
4169
|
+
volumeId: {
|
|
4170
|
+
type: "string",
|
|
4171
|
+
description: "ID of a NetworkVolume (under `network`) or GlobalVolume (under `global`).",
|
|
4172
|
+
examples: ["vol_abc"]
|
|
4173
|
+
}
|
|
4174
|
+
}
|
|
4175
|
+
},
|
|
4176
|
+
EndpointMountsInput: {
|
|
4177
|
+
type: "object",
|
|
4178
|
+
additionalProperties: false,
|
|
4179
|
+
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.",
|
|
4180
|
+
properties: {
|
|
4181
|
+
network: {
|
|
4182
|
+
type: "array",
|
|
4183
|
+
description: "Network volumes, at most one per data center.",
|
|
4184
|
+
items: {
|
|
4185
|
+
$ref: "#/$defs/EndpointMount"
|
|
4186
|
+
}
|
|
4187
|
+
},
|
|
4188
|
+
global: {
|
|
4189
|
+
type: "array",
|
|
4190
|
+
maxItems: 1,
|
|
4191
|
+
items: {
|
|
4192
|
+
$ref: "#/$defs/EndpointMount"
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
},
|
|
3793
4197
|
EndpointScaling: {
|
|
3794
|
-
description: "Autoscaling signal \u2014 a discriminated union on `type`: `QUEUE_DELAY
|
|
4198
|
+
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.",
|
|
3795
4199
|
oneOf: [
|
|
3796
4200
|
{
|
|
3797
4201
|
$ref: "#/$defs/QueueDelayScaling"
|
|
@@ -3828,14 +4232,14 @@ var generatedTools = [
|
|
|
3828
4232
|
type: "integer",
|
|
3829
4233
|
minimum: 1,
|
|
3830
4234
|
maximum: 3600,
|
|
3831
|
-
description: "Seconds before idle workers scale down. Not applicable to queue-based
|
|
4235
|
+
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.",
|
|
3832
4236
|
examples: [5]
|
|
3833
4237
|
}
|
|
3834
4238
|
}
|
|
3835
4239
|
},
|
|
3836
4240
|
FlashBoot: {
|
|
3837
4241
|
type: "string",
|
|
3838
|
-
description: "FlashBoot cold-start acceleration mode
|
|
4242
|
+
description: "FlashBoot cold-start acceleration mode. `OFF` \u2014 disabled. `FLASHBOOT` \u2014 enabled. `PRIORITY_FLASHBOOT` \u2014 enabled with priority capacity",
|
|
3839
4243
|
enum: ["OFF", "FLASHBOOT", "PRIORITY_FLASHBOOT"]
|
|
3840
4244
|
},
|
|
3841
4245
|
QueueDelayScaling: {
|
|
@@ -3861,7 +4265,7 @@ var generatedTools = [
|
|
|
3861
4265
|
RequestCountScaling: {
|
|
3862
4266
|
type: "object",
|
|
3863
4267
|
additionalProperties: false,
|
|
3864
|
-
description: "Scale on concurrent in-flight requests per worker. Required for
|
|
4268
|
+
description: "Scale on concurrent in-flight requests per worker. Required for load-balancing endpoints; also selectable for queue-based.",
|
|
3865
4269
|
required: ["type", "requestCount"],
|
|
3866
4270
|
properties: {
|
|
3867
4271
|
type: {
|
|
@@ -3878,7 +4282,7 @@ var generatedTools = [
|
|
|
3878
4282
|
}
|
|
3879
4283
|
},
|
|
3880
4284
|
UpdateEndpointGpuConfig: {
|
|
3881
|
-
description: "Partial GPU update \u2014 every field is optional and an omitted one is left
|
|
4285
|
+
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.",
|
|
3882
4286
|
allOf: [
|
|
3883
4287
|
{
|
|
3884
4288
|
$ref: "#/$defs/BaseEndpointGpuConfig"
|
|
@@ -3895,12 +4299,12 @@ var generatedTools = [
|
|
|
3895
4299
|
type: "string",
|
|
3896
4300
|
pattern: "^\\d+\\.\\d+$"
|
|
3897
4301
|
},
|
|
3898
|
-
description: "Acceptable CUDA versions for worker placement, as
|
|
4302
|
+
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."
|
|
3899
4303
|
},
|
|
3900
4304
|
minCudaVersion: {
|
|
3901
4305
|
type: "string",
|
|
3902
4306
|
pattern: "^$|^\\d+\\.\\d+$",
|
|
3903
|
-
description: 'Lowest acceptable CUDA version for worker placement, as
|
|
4307
|
+
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.',
|
|
3904
4308
|
examples: ["12.1"]
|
|
3905
4309
|
}
|
|
3906
4310
|
}
|
|
@@ -3921,7 +4325,7 @@ var generatedTools = [
|
|
|
3921
4325
|
type: "array",
|
|
3922
4326
|
minItems: 1,
|
|
3923
4327
|
uniqueItems: true,
|
|
3924
|
-
description: "Complete replacement CPU selection. Valid only for an existing CPU
|
|
4328
|
+
description: "Complete replacement CPU selection. Valid only for an existing CPU endpoint; endpoint compute family cannot be changed.",
|
|
3925
4329
|
items: {
|
|
3926
4330
|
$ref: "#/$defs/CreateCpuConfig"
|
|
3927
4331
|
}
|
|
@@ -3947,14 +4351,19 @@ var generatedTools = [
|
|
|
3947
4351
|
type: "array",
|
|
3948
4352
|
items: {
|
|
3949
4353
|
type: "string"
|
|
3950
|
-
}
|
|
4354
|
+
},
|
|
4355
|
+
description: "Network volume IDs. Pass `[]` to detach.",
|
|
4356
|
+
deprecated: true
|
|
4357
|
+
},
|
|
4358
|
+
mounts: {
|
|
4359
|
+
$ref: "#/$defs/EndpointMountsInput"
|
|
3951
4360
|
},
|
|
3952
4361
|
scaling: {
|
|
3953
4362
|
$ref: "#/$defs/EndpointScaling"
|
|
3954
4363
|
},
|
|
3955
4364
|
templateId: {
|
|
3956
4365
|
type: "string",
|
|
3957
|
-
description: "ID of a serverless template whose container settings
|
|
4366
|
+
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.",
|
|
3958
4367
|
examples: ["30zmvf89kd"]
|
|
3959
4368
|
},
|
|
3960
4369
|
timeout: {
|
|
@@ -3965,8 +4374,59 @@ var generatedTools = [
|
|
|
3965
4374
|
}
|
|
3966
4375
|
}
|
|
3967
4376
|
}
|
|
3968
|
-
],
|
|
3969
|
-
unevaluatedProperties: false
|
|
4377
|
+
],
|
|
4378
|
+
unevaluatedProperties: false
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
},
|
|
4383
|
+
{
|
|
4384
|
+
name: "update-global-volume",
|
|
4385
|
+
operationId: "updateGlobalVolume",
|
|
4386
|
+
description: "Update a global volume. Updates mutable fields on a global volume. Only provided fields are changed.",
|
|
4387
|
+
method: "PATCH",
|
|
4388
|
+
path: "/v2/global-volumes/{id}",
|
|
4389
|
+
params: [
|
|
4390
|
+
{
|
|
4391
|
+
name: "id",
|
|
4392
|
+
location: "path"
|
|
4393
|
+
}
|
|
4394
|
+
],
|
|
4395
|
+
hasBody: true,
|
|
4396
|
+
annotations: {
|
|
4397
|
+
readOnlyHint: false,
|
|
4398
|
+
destructiveHint: false,
|
|
4399
|
+
idempotentHint: false,
|
|
4400
|
+
openWorldHint: true
|
|
4401
|
+
},
|
|
4402
|
+
inputSchema: {
|
|
4403
|
+
type: "object",
|
|
4404
|
+
properties: {
|
|
4405
|
+
id: {
|
|
4406
|
+
type: "string",
|
|
4407
|
+
description: "Global volume identifier"
|
|
4408
|
+
},
|
|
4409
|
+
body: {
|
|
4410
|
+
$ref: "#/$defs/UpdateGlobalVolumeRequest"
|
|
4411
|
+
}
|
|
4412
|
+
},
|
|
4413
|
+
required: ["id", "body"],
|
|
4414
|
+
$defs: {
|
|
4415
|
+
UpdateGlobalVolumeRequest: {
|
|
4416
|
+
type: "object",
|
|
4417
|
+
additionalProperties: false,
|
|
4418
|
+
minProperties: 1,
|
|
4419
|
+
description: "Only the provided fields are updated. At least one field must be present; an empty body is rejected.",
|
|
4420
|
+
properties: {
|
|
4421
|
+
name: {
|
|
4422
|
+
type: "string",
|
|
4423
|
+
minLength: 1,
|
|
4424
|
+
maxLength: 191,
|
|
4425
|
+
pattern: "[^\\p{Z}\\t-\\r\x85]",
|
|
4426
|
+
description: "New human-readable name, 1\u2013191 characters with at least one non-whitespace character. Leading and trailing whitespace is trimmed.",
|
|
4427
|
+
examples: ["renamed-volume"]
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
3970
4430
|
}
|
|
3971
4431
|
}
|
|
3972
4432
|
}
|
|
@@ -4007,7 +4467,7 @@ var generatedTools = [
|
|
|
4007
4467
|
type: "object",
|
|
4008
4468
|
additionalProperties: false,
|
|
4009
4469
|
minProperties: 1,
|
|
4010
|
-
description: "Only the provided fields are updated. At least one field must be
|
|
4470
|
+
description: "Only the provided fields are updated. At least one field must be present; an empty body is rejected.",
|
|
4011
4471
|
properties: {
|
|
4012
4472
|
name: {
|
|
4013
4473
|
type: "string",
|
|
@@ -4019,7 +4479,7 @@ var generatedTools = [
|
|
|
4019
4479
|
type: "integer",
|
|
4020
4480
|
minimum: 10,
|
|
4021
4481
|
maximum: 4096,
|
|
4022
|
-
description: "New size in GB. Must be greater than or equal to the current size \u2014
|
|
4482
|
+
description: "New size in GB. Must be greater than or equal to the current size \u2014 network volume storage cannot be reduced.",
|
|
4023
4483
|
examples: [100]
|
|
4024
4484
|
}
|
|
4025
4485
|
}
|
|
@@ -4046,6 +4506,7 @@ var generatedTools = [
|
|
|
4046
4506
|
idempotentHint: false,
|
|
4047
4507
|
openWorldHint: true
|
|
4048
4508
|
},
|
|
4509
|
+
schemaOnDemand: true,
|
|
4049
4510
|
inputSchema: {
|
|
4050
4511
|
type: "object",
|
|
4051
4512
|
properties: {
|
|
@@ -4061,11 +4522,10 @@ var generatedTools = [
|
|
|
4061
4522
|
$defs: {
|
|
4062
4523
|
BaseContainerConfig: {
|
|
4063
4524
|
type: "object",
|
|
4064
|
-
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",
|
|
4065
4525
|
properties: {
|
|
4066
4526
|
args: {
|
|
4067
4527
|
type: "string",
|
|
4068
|
-
description: 'The container\'s command
|
|
4528
|
+
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.',
|
|
4069
4529
|
examples: [
|
|
4070
4530
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
4071
4531
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -4077,7 +4537,7 @@ var generatedTools = [
|
|
|
4077
4537
|
items: {
|
|
4078
4538
|
type: "string"
|
|
4079
4539
|
},
|
|
4080
|
-
description: "Container CMD in exec form
|
|
4540
|
+
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.",
|
|
4081
4541
|
examples: [
|
|
4082
4542
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
4083
4543
|
]
|
|
@@ -4087,7 +4547,7 @@ var generatedTools = [
|
|
|
4087
4547
|
items: {
|
|
4088
4548
|
type: "string"
|
|
4089
4549
|
},
|
|
4090
|
-
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
|
|
4550
|
+
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.",
|
|
4091
4551
|
examples: [["/bin/bash", "-c"]]
|
|
4092
4552
|
},
|
|
4093
4553
|
disk: {
|
|
@@ -4123,8 +4583,22 @@ var generatedTools = [
|
|
|
4123
4583
|
}
|
|
4124
4584
|
}
|
|
4125
4585
|
},
|
|
4586
|
+
BaseMounts: {
|
|
4587
|
+
type: "object",
|
|
4588
|
+
properties: {
|
|
4589
|
+
persistent: {
|
|
4590
|
+
$ref: "#/$defs/PersistentMount"
|
|
4591
|
+
},
|
|
4592
|
+
network: {
|
|
4593
|
+
type: "array",
|
|
4594
|
+
maxItems: 1,
|
|
4595
|
+
items: {
|
|
4596
|
+
$ref: "#/$defs/NetworkMount"
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
},
|
|
4126
4601
|
ContainerConfig: {
|
|
4127
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
4128
4602
|
allOf: [
|
|
4129
4603
|
{
|
|
4130
4604
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -4141,28 +4615,51 @@ var generatedTools = [
|
|
|
4141
4615
|
}
|
|
4142
4616
|
]
|
|
4143
4617
|
},
|
|
4144
|
-
|
|
4618
|
+
GlobalMount: {
|
|
4145
4619
|
type: "object",
|
|
4620
|
+
required: ["volumeId"],
|
|
4146
4621
|
additionalProperties: false,
|
|
4147
|
-
description: "
|
|
4622
|
+
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.",
|
|
4148
4623
|
properties: {
|
|
4149
|
-
|
|
4150
|
-
|
|
4624
|
+
volumeId: {
|
|
4625
|
+
type: "string",
|
|
4626
|
+
description: "ID of an existing GlobalVolume.",
|
|
4627
|
+
examples: ["gsb_abc"]
|
|
4151
4628
|
},
|
|
4152
|
-
|
|
4153
|
-
type: "
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
$ref: "#/$defs/NetworkMount"
|
|
4157
|
-
}
|
|
4629
|
+
path: {
|
|
4630
|
+
type: "string",
|
|
4631
|
+
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.",
|
|
4632
|
+
examples: ["/data"]
|
|
4158
4633
|
}
|
|
4159
4634
|
}
|
|
4160
4635
|
},
|
|
4636
|
+
Mounts: {
|
|
4637
|
+
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.",
|
|
4638
|
+
allOf: [
|
|
4639
|
+
{
|
|
4640
|
+
$ref: "#/$defs/BaseMounts"
|
|
4641
|
+
},
|
|
4642
|
+
{
|
|
4643
|
+
type: "object",
|
|
4644
|
+
properties: {
|
|
4645
|
+
global: {
|
|
4646
|
+
type: "array",
|
|
4647
|
+
maxItems: 1,
|
|
4648
|
+
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.",
|
|
4649
|
+
items: {
|
|
4650
|
+
$ref: "#/$defs/GlobalMount"
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
],
|
|
4656
|
+
unevaluatedProperties: false
|
|
4657
|
+
},
|
|
4161
4658
|
NetworkMount: {
|
|
4162
4659
|
type: "object",
|
|
4163
4660
|
required: ["volumeId", "path"],
|
|
4164
4661
|
additionalProperties: false,
|
|
4165
|
-
description: "Reference to a NetworkVolume. Custom paths are honored at runtime on
|
|
4662
|
+
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.",
|
|
4166
4663
|
properties: {
|
|
4167
4664
|
volumeId: {
|
|
4168
4665
|
type: "string",
|
|
@@ -4180,7 +4677,7 @@ var generatedTools = [
|
|
|
4180
4677
|
type: "object",
|
|
4181
4678
|
required: ["size", "path"],
|
|
4182
4679
|
additionalProperties: false,
|
|
4183
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
4680
|
+
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.",
|
|
4184
4681
|
properties: {
|
|
4185
4682
|
size: {
|
|
4186
4683
|
type: "integer",
|
|
@@ -4205,7 +4702,7 @@ var generatedTools = [
|
|
|
4205
4702
|
properties: {
|
|
4206
4703
|
globalNetworking: {
|
|
4207
4704
|
type: "boolean",
|
|
4208
|
-
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).
|
|
4705
|
+
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)."
|
|
4209
4706
|
},
|
|
4210
4707
|
locked: {
|
|
4211
4708
|
type: "boolean",
|
|
@@ -4220,7 +4717,7 @@ var generatedTools = [
|
|
|
4220
4717
|
},
|
|
4221
4718
|
templateId: {
|
|
4222
4719
|
type: "string",
|
|
4223
|
-
description: "ID of a pod template whose container settings
|
|
4720
|
+
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.",
|
|
4224
4721
|
examples: ["30zmvf89kd"]
|
|
4225
4722
|
}
|
|
4226
4723
|
}
|
|
@@ -4250,6 +4747,7 @@ var generatedTools = [
|
|
|
4250
4747
|
idempotentHint: false,
|
|
4251
4748
|
openWorldHint: true
|
|
4252
4749
|
},
|
|
4750
|
+
schemaOnDemand: true,
|
|
4253
4751
|
inputSchema: {
|
|
4254
4752
|
type: "object",
|
|
4255
4753
|
properties: {
|
|
@@ -4267,7 +4765,7 @@ var generatedTools = [
|
|
|
4267
4765
|
type: "object",
|
|
4268
4766
|
additionalProperties: false,
|
|
4269
4767
|
minProperties: 1,
|
|
4270
|
-
description: "Only the provided fields are updated; at least one field is required
|
|
4768
|
+
description: "Only the provided fields are updated; at least one field is required. The secret's `name` is immutable.",
|
|
4271
4769
|
properties: {
|
|
4272
4770
|
value: {
|
|
4273
4771
|
type: "string",
|
|
@@ -4319,7 +4817,7 @@ var generatedTools = [
|
|
|
4319
4817
|
type: "string",
|
|
4320
4818
|
pattern: "^(ssh|ecdsa|sk)-[^\\s]+ [^\\s]+([ \\t][^\\n\\r]*)?$"
|
|
4321
4819
|
},
|
|
4322
|
-
description: "The full set of SSH public keys to register \u2014 this is a complete
|
|
4820
|
+
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.",
|
|
4323
4821
|
examples: [
|
|
4324
4822
|
[
|
|
4325
4823
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"
|
|
@@ -4350,6 +4848,7 @@ var generatedTools = [
|
|
|
4350
4848
|
idempotentHint: false,
|
|
4351
4849
|
openWorldHint: true
|
|
4352
4850
|
},
|
|
4851
|
+
schemaOnDemand: true,
|
|
4353
4852
|
inputSchema: {
|
|
4354
4853
|
type: "object",
|
|
4355
4854
|
properties: {
|
|
@@ -4364,11 +4863,10 @@ var generatedTools = [
|
|
|
4364
4863
|
$defs: {
|
|
4365
4864
|
BaseContainerConfig: {
|
|
4366
4865
|
type: "object",
|
|
4367
|
-
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",
|
|
4368
4866
|
properties: {
|
|
4369
4867
|
args: {
|
|
4370
4868
|
type: "string",
|
|
4371
|
-
description: 'The container\'s command
|
|
4869
|
+
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.',
|
|
4372
4870
|
examples: [
|
|
4373
4871
|
"--model meta-llama/Llama-3-8B --max-model-len 8192",
|
|
4374
4872
|
'{"entrypoint":["/bin/bash","-c"],"cmd":["python -u main.py"]}',
|
|
@@ -4380,7 +4878,7 @@ var generatedTools = [
|
|
|
4380
4878
|
items: {
|
|
4381
4879
|
type: "string"
|
|
4382
4880
|
},
|
|
4383
|
-
description: "Container CMD in exec form
|
|
4881
|
+
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.",
|
|
4384
4882
|
examples: [
|
|
4385
4883
|
["--model", "meta-llama/Llama-3-8B", "--max-model-len", "8192"]
|
|
4386
4884
|
]
|
|
@@ -4390,7 +4888,7 @@ var generatedTools = [
|
|
|
4390
4888
|
items: {
|
|
4391
4889
|
type: "string"
|
|
4392
4890
|
},
|
|
4393
|
-
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
|
|
4891
|
+
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.",
|
|
4394
4892
|
examples: [["/bin/bash", "-c"]]
|
|
4395
4893
|
},
|
|
4396
4894
|
disk: {
|
|
@@ -4427,7 +4925,6 @@ var generatedTools = [
|
|
|
4427
4925
|
}
|
|
4428
4926
|
},
|
|
4429
4927
|
ContainerConfig: {
|
|
4430
|
-
description: "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n",
|
|
4431
4928
|
allOf: [
|
|
4432
4929
|
{
|
|
4433
4930
|
$ref: "#/$defs/BaseContainerConfig"
|
|
@@ -4448,7 +4945,7 @@ var generatedTools = [
|
|
|
4448
4945
|
type: "object",
|
|
4449
4946
|
required: ["size", "path"],
|
|
4450
4947
|
additionalProperties: false,
|
|
4451
|
-
description: "Host-local persistent storage. Pinned to the pod's host machine \u2014 data
|
|
4948
|
+
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.",
|
|
4452
4949
|
properties: {
|
|
4453
4950
|
size: {
|
|
4454
4951
|
type: "integer",
|
|
@@ -4465,13 +4962,13 @@ var generatedTools = [
|
|
|
4465
4962
|
},
|
|
4466
4963
|
TemplateCategory: {
|
|
4467
4964
|
type: "string",
|
|
4468
|
-
description: "Controls how the template is grouped and filtered in the Runpod console
|
|
4965
|
+
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",
|
|
4469
4966
|
enum: ["CPU", "NVIDIA", "AMD"]
|
|
4470
4967
|
},
|
|
4471
4968
|
TemplateMounts: {
|
|
4472
4969
|
type: "object",
|
|
4473
4970
|
additionalProperties: false,
|
|
4474
|
-
description: "Storage mounts
|
|
4971
|
+
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.",
|
|
4475
4972
|
properties: {
|
|
4476
4973
|
persistent: {
|
|
4477
4974
|
$ref: "#/$defs/PersistentMount"
|
|
@@ -5220,6 +5717,8 @@ var listHubRepos = {
|
|
|
5220
5717
|
};
|
|
5221
5718
|
var deployHubRepo = {
|
|
5222
5719
|
name: "deploy-hub-repo",
|
|
5720
|
+
// Two sequential upstream calls: together they can outlast a client's request timeout.
|
|
5721
|
+
holdsResponse: true,
|
|
5223
5722
|
annotations: write,
|
|
5224
5723
|
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).",
|
|
5225
5724
|
inputSchema: {
|
|
@@ -5708,6 +6207,7 @@ var runEndpoint = {
|
|
|
5708
6207
|
};
|
|
5709
6208
|
var runsyncEndpoint = {
|
|
5710
6209
|
name: "runsync-endpoint",
|
|
6210
|
+
holdsResponse: true,
|
|
5711
6211
|
annotations: write,
|
|
5712
6212
|
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)."),
|
|
5713
6213
|
inputSchema: {
|
|
@@ -5752,6 +6252,7 @@ var runsyncEndpoint = {
|
|
|
5752
6252
|
};
|
|
5753
6253
|
var getJobStatus = {
|
|
5754
6254
|
name: "get-job-status",
|
|
6255
|
+
holdsResponse: true,
|
|
5755
6256
|
annotations: readOnly,
|
|
5756
6257
|
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.",
|
|
5757
6258
|
inputSchema: {
|
|
@@ -5800,6 +6301,7 @@ var getJobStatus = {
|
|
|
5800
6301
|
};
|
|
5801
6302
|
var streamJob = {
|
|
5802
6303
|
name: "stream-job",
|
|
6304
|
+
holdsResponse: true,
|
|
5803
6305
|
annotations: readOnly,
|
|
5804
6306
|
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.`,
|
|
5805
6307
|
inputSchema: {
|
|
@@ -6032,8 +6534,11 @@ function publicGraphqlBase(env) {
|
|
|
6032
6534
|
function authedGraphqlBase(env) {
|
|
6033
6535
|
return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
|
|
6034
6536
|
}
|
|
6537
|
+
function knowledgeSearchBase(env) {
|
|
6538
|
+
return pick(env.KNOWLEDGE_SEARCH_URL, "") || void 0;
|
|
6539
|
+
}
|
|
6035
6540
|
|
|
6036
|
-
// node_modules/.pnpm/@runpod+typescript-api-sdk@0.
|
|
6541
|
+
// node_modules/.pnpm/@runpod+typescript-api-sdk@0.3.0/node_modules/@runpod/typescript-api-sdk/dist/index.js
|
|
6037
6542
|
var PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
6038
6543
|
var supportsRequestInitExt = () => {
|
|
6039
6544
|
return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
|
|
@@ -6930,9 +7435,9 @@ function isDigit(char) {
|
|
|
6930
7435
|
return false;
|
|
6931
7436
|
return isDigitRegex.test(char);
|
|
6932
7437
|
}
|
|
6933
|
-
function parseRetryAfter(
|
|
6934
|
-
if (
|
|
6935
|
-
const value =
|
|
7438
|
+
function parseRetryAfter(header2, now = Date.now()) {
|
|
7439
|
+
if (header2 === null) return void 0;
|
|
7440
|
+
const value = header2.trim();
|
|
6936
7441
|
if (/^\d+$/.test(value)) {
|
|
6937
7442
|
const ms = Number(value) * 1e3;
|
|
6938
7443
|
return Number.isSafeInteger(ms) ? ms : void 0;
|
|
@@ -7437,6 +7942,7 @@ function logParams(args) {
|
|
|
7437
7942
|
}
|
|
7438
7943
|
var streamPodLogs = {
|
|
7439
7944
|
name: "stream-pod-logs",
|
|
7945
|
+
holdsResponse: true,
|
|
7440
7946
|
annotations: readOnly,
|
|
7441
7947
|
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.",
|
|
7442
7948
|
inputSchema: {
|
|
@@ -7459,6 +7965,7 @@ var streamPodLogs = {
|
|
|
7459
7965
|
};
|
|
7460
7966
|
var streamWorkerLogs = {
|
|
7461
7967
|
name: "stream-worker-logs",
|
|
7968
|
+
holdsResponse: true,
|
|
7462
7969
|
annotations: readOnly,
|
|
7463
7970
|
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.",
|
|
7464
7971
|
inputSchema: {
|
|
@@ -7721,6 +8228,7 @@ var source = {
|
|
|
7721
8228
|
var listGuides = {
|
|
7722
8229
|
name: "list-guides",
|
|
7723
8230
|
annotations: bundledRead,
|
|
8231
|
+
recordedArguments: ["kind", "query", "concept"],
|
|
7724
8232
|
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.",
|
|
7725
8233
|
inputSchema: {
|
|
7726
8234
|
type: "object",
|
|
@@ -7756,6 +8264,8 @@ var listGuides = {
|
|
|
7756
8264
|
var readGuide = {
|
|
7757
8265
|
name: "read-guide",
|
|
7758
8266
|
annotations: bundledRead,
|
|
8267
|
+
recordedArguments: ["id"],
|
|
8268
|
+
recordedGuideKind: (args) => knowledge.guides.find((guide) => guide.id === String(args.id).trim())?.kind,
|
|
7759
8269
|
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").',
|
|
7760
8270
|
inputSchema: {
|
|
7761
8271
|
type: "object",
|
|
@@ -7793,6 +8303,7 @@ var readGuide = {
|
|
|
7793
8303
|
var lookupConcept = {
|
|
7794
8304
|
name: "lookup-concept",
|
|
7795
8305
|
annotations: bundledRead,
|
|
8306
|
+
recordedArguments: ["concept"],
|
|
7796
8307
|
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".',
|
|
7797
8308
|
inputSchema: {
|
|
7798
8309
|
type: "object",
|
|
@@ -7845,6 +8356,7 @@ var lookupConcept = {
|
|
|
7845
8356
|
var searchConcepts = {
|
|
7846
8357
|
name: "search-concepts",
|
|
7847
8358
|
annotations: bundledRead,
|
|
8359
|
+
recordedArguments: ["query", "limit"],
|
|
7848
8360
|
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.',
|
|
7849
8361
|
inputSchema: {
|
|
7850
8362
|
type: "object",
|
|
@@ -7909,9 +8421,143 @@ var guideResources = knowledge.guides.map((guide) => ({
|
|
|
7909
8421
|
text: guide.body
|
|
7910
8422
|
}));
|
|
7911
8423
|
|
|
8424
|
+
// src/specgen/prose.ts
|
|
8425
|
+
var ABBREVIATIONS = ["e.g.", "i.e.", "etc.", "vs."];
|
|
8426
|
+
var DOT = "\0";
|
|
8427
|
+
function splitSentences(text) {
|
|
8428
|
+
let guarded = text;
|
|
8429
|
+
for (const abbreviation of ABBREVIATIONS) {
|
|
8430
|
+
guarded = guarded.replaceAll(
|
|
8431
|
+
abbreviation,
|
|
8432
|
+
abbreviation.replaceAll(".", DOT)
|
|
8433
|
+
);
|
|
8434
|
+
}
|
|
8435
|
+
return guarded.split(/(?<=[.!?])\s+(?=[A-Z`"'([])/).map((sentence) => sentence.replaceAll(DOT, ".").trim()).filter(Boolean);
|
|
8436
|
+
}
|
|
8437
|
+
function leadSentence(text) {
|
|
8438
|
+
return splitSentences(text)[0] ?? text;
|
|
8439
|
+
}
|
|
8440
|
+
|
|
8441
|
+
// src/specgen/on-demand.ts
|
|
8442
|
+
var DESCRIBE_TOOL_NAME = "describe-tool";
|
|
8443
|
+
var ON_DEMAND_POINTER = ` Call ${DESCRIBE_TOOL_NAME} for the full argument schema before the first use.`;
|
|
8444
|
+
function listedAnnotations(annotations) {
|
|
8445
|
+
const { idempotentHint, ...listed } = annotations;
|
|
8446
|
+
return idempotentHint ? annotations : listed;
|
|
8447
|
+
}
|
|
8448
|
+
function listTool(tool) {
|
|
8449
|
+
const { name, description, inputSchema } = tool;
|
|
8450
|
+
const annotations = listedAnnotations(tool.annotations);
|
|
8451
|
+
if (!tool.schemaOnDemand)
|
|
8452
|
+
return { name, description, inputSchema, annotations };
|
|
8453
|
+
return {
|
|
8454
|
+
name,
|
|
8455
|
+
description: description + ON_DEMAND_POINTER,
|
|
8456
|
+
inputSchema: callShape(inputSchema),
|
|
8457
|
+
annotations
|
|
8458
|
+
};
|
|
8459
|
+
}
|
|
8460
|
+
function callShape(schema) {
|
|
8461
|
+
const defs = schema.$defs ?? {};
|
|
8462
|
+
const resolve = (node) => {
|
|
8463
|
+
if (typeof node.$ref !== "string") return node;
|
|
8464
|
+
const name = node.$ref.split("/").pop() ?? "";
|
|
8465
|
+
return defs[name] ?? {};
|
|
8466
|
+
};
|
|
8467
|
+
const properties = Object.fromEntries(
|
|
8468
|
+
Object.entries(schema.properties ?? {}).map(
|
|
8469
|
+
([key, value]) => [key, shallowProperty(resolve(value), resolve)]
|
|
8470
|
+
)
|
|
8471
|
+
);
|
|
8472
|
+
return {
|
|
8473
|
+
type: "object",
|
|
8474
|
+
properties,
|
|
8475
|
+
...schema.required ? { required: schema.required } : {}
|
|
8476
|
+
};
|
|
8477
|
+
}
|
|
8478
|
+
function shallowProperty(node, resolve) {
|
|
8479
|
+
const out = {};
|
|
8480
|
+
const type = schemaType(node, resolve);
|
|
8481
|
+
if (type !== void 0) out.type = type;
|
|
8482
|
+
if (type === "array") {
|
|
8483
|
+
const items = resolve(node.items ?? {});
|
|
8484
|
+
const itemType = schemaType(items, resolve);
|
|
8485
|
+
if (itemType !== void 0) out.items = { type: itemType };
|
|
8486
|
+
}
|
|
8487
|
+
if (Array.isArray(node.enum)) out.enum = node.enum;
|
|
8488
|
+
if (typeof node.description === "string")
|
|
8489
|
+
out.description = leadSentence(node.description);
|
|
8490
|
+
return out;
|
|
8491
|
+
}
|
|
8492
|
+
function schemaType(node, resolve) {
|
|
8493
|
+
if (node.type !== void 0) return node.type;
|
|
8494
|
+
if (node.properties || node.allOf) return "object";
|
|
8495
|
+
const branches2 = node.anyOf ?? node.oneOf;
|
|
8496
|
+
const allObjects = branches2?.every(
|
|
8497
|
+
(branch) => schemaType(resolve(branch), resolve) === "object"
|
|
8498
|
+
) ?? false;
|
|
8499
|
+
return allObjects ? "object" : void 0;
|
|
8500
|
+
}
|
|
8501
|
+
|
|
8502
|
+
// src/specgen/tools/describe.ts
|
|
8503
|
+
function createDescribeTool(served) {
|
|
8504
|
+
return {
|
|
8505
|
+
name: DESCRIBE_TOOL_NAME,
|
|
8506
|
+
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.",
|
|
8507
|
+
inputSchema: {
|
|
8508
|
+
type: "object",
|
|
8509
|
+
properties: {
|
|
8510
|
+
name: {
|
|
8511
|
+
type: "string",
|
|
8512
|
+
description: "A tool name exactly as this server's tool list spells it."
|
|
8513
|
+
}
|
|
8514
|
+
},
|
|
8515
|
+
required: ["name"]
|
|
8516
|
+
},
|
|
8517
|
+
annotations: {
|
|
8518
|
+
readOnlyHint: true,
|
|
8519
|
+
destructiveHint: false,
|
|
8520
|
+
idempotentHint: true,
|
|
8521
|
+
openWorldHint: false
|
|
8522
|
+
},
|
|
8523
|
+
handler: async (_ctx, args) => {
|
|
8524
|
+
const name = String(args.name ?? "");
|
|
8525
|
+
const tools = served();
|
|
8526
|
+
const tool = tools.find((candidate) => candidate.name === name);
|
|
8527
|
+
if (!tool) {
|
|
8528
|
+
return {
|
|
8529
|
+
ok: false,
|
|
8530
|
+
status: 404,
|
|
8531
|
+
payload: {
|
|
8532
|
+
error: `No tool named ${name}.`,
|
|
8533
|
+
suggestions: similarNames(
|
|
8534
|
+
name,
|
|
8535
|
+
tools.map((candidate) => candidate.name)
|
|
8536
|
+
),
|
|
8537
|
+
hint: "Tool names are exactly as this server lists them; the suggestions share a word with the name you sent."
|
|
8538
|
+
}
|
|
8539
|
+
};
|
|
8540
|
+
}
|
|
8541
|
+
const { description, inputSchema, annotations } = tool;
|
|
8542
|
+
return ok({ name: tool.name, description, inputSchema, annotations });
|
|
8543
|
+
}
|
|
8544
|
+
};
|
|
8545
|
+
}
|
|
8546
|
+
function similarNames(query, names) {
|
|
8547
|
+
const wanted = new Set(words2(query));
|
|
8548
|
+
return names.map((name) => {
|
|
8549
|
+
const own = new Set(words2(name));
|
|
8550
|
+
const shared = [...own].filter((word) => wanted.has(word)).length;
|
|
8551
|
+
return { name, score: shared / (/* @__PURE__ */ new Set([...own, ...wanted])).size };
|
|
8552
|
+
}).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.name.localeCompare(b.name)).slice(0, 8).map((entry) => entry.name);
|
|
8553
|
+
}
|
|
8554
|
+
function words2(name) {
|
|
8555
|
+
return name.toLowerCase().split(/[-_\s]+/).filter(Boolean).map((word) => word.replace(/s$/, ""));
|
|
8556
|
+
}
|
|
8557
|
+
|
|
7912
8558
|
// src/server.ts
|
|
7913
8559
|
var SERVER_NAME = "Runpod API Server";
|
|
7914
|
-
var SERVER_VERSION = true ? "4.
|
|
8560
|
+
var SERVER_VERSION = true ? "4.4.0" : "dev";
|
|
7915
8561
|
|
|
7916
8562
|
// src/specgen/analytics.ts
|
|
7917
8563
|
var import_node_crypto = require("crypto");
|
|
@@ -7927,7 +8573,22 @@ function analyticsCallerId(apiKey, accountId) {
|
|
|
7927
8573
|
const prefix = accountId ? "a:" : "k:";
|
|
7928
8574
|
return prefix + (0, import_node_crypto.createHmac)("sha256", salt).update(identity).digest("hex").slice(0, 16);
|
|
7929
8575
|
}
|
|
7930
|
-
|
|
8576
|
+
var MAX_RECORDED_VALUE_LENGTH = 200;
|
|
8577
|
+
function bounded(value) {
|
|
8578
|
+
return value.slice(0, MAX_RECORDED_VALUE_LENGTH);
|
|
8579
|
+
}
|
|
8580
|
+
function recordedArgumentValues(names, args) {
|
|
8581
|
+
if (!names?.length) return void 0;
|
|
8582
|
+
const values = {};
|
|
8583
|
+
for (const name of names) {
|
|
8584
|
+
const value = args[name];
|
|
8585
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
8586
|
+
values[name] = bounded(String(value).trim());
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
return Object.keys(values).length ? values : void 0;
|
|
8590
|
+
}
|
|
8591
|
+
function capture(event, distinctId, properties) {
|
|
7931
8592
|
const posthogKey = process.env.POSTHOG_API_KEY;
|
|
7932
8593
|
if (!posthogKey) return;
|
|
7933
8594
|
void fetch(`${posthogHost()}/capture/`, {
|
|
@@ -7935,18 +8596,12 @@ function captureToolCall(apiKey, event) {
|
|
|
7935
8596
|
headers: { "Content-Type": "application/json" },
|
|
7936
8597
|
body: JSON.stringify({
|
|
7937
8598
|
api_key: posthogKey,
|
|
7938
|
-
event
|
|
7939
|
-
distinct_id:
|
|
8599
|
+
event,
|
|
8600
|
+
distinct_id: distinctId,
|
|
7940
8601
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7941
8602
|
properties: {
|
|
7942
|
-
|
|
7943
|
-
ok: event.ok,
|
|
7944
|
-
status: event.status,
|
|
7945
|
-
duration_ms: event.durationMs,
|
|
7946
|
-
transport: event.transport,
|
|
7947
|
-
server_version: event.serverVersion,
|
|
8603
|
+
...properties,
|
|
7948
8604
|
surface_version: SURFACE_VERSION,
|
|
7949
|
-
...event.clientName ? { client_name: event.clientName } : {},
|
|
7950
8605
|
$process_person_profile: false
|
|
7951
8606
|
}
|
|
7952
8607
|
}),
|
|
@@ -7954,6 +8609,63 @@ function captureToolCall(apiKey, event) {
|
|
|
7954
8609
|
}).catch(() => {
|
|
7955
8610
|
});
|
|
7956
8611
|
}
|
|
8612
|
+
function captureToolCall(apiKey, event) {
|
|
8613
|
+
const args = Object.fromEntries(
|
|
8614
|
+
Object.entries(event.args ?? {}).map(([name, value]) => [
|
|
8615
|
+
`arg_${name}`,
|
|
8616
|
+
value
|
|
8617
|
+
])
|
|
8618
|
+
);
|
|
8619
|
+
capture("runpod_mcp_tool_call", analyticsCallerId(apiKey, event.accountId), {
|
|
8620
|
+
tool: event.tool,
|
|
8621
|
+
ok: event.ok,
|
|
8622
|
+
status: event.status,
|
|
8623
|
+
duration_ms: event.durationMs,
|
|
8624
|
+
transport: event.transport,
|
|
8625
|
+
server_version: event.serverVersion,
|
|
8626
|
+
...event.clientName ? { client_name: event.clientName } : {},
|
|
8627
|
+
...event.guideKind ? { guide_kind: event.guideKind } : {},
|
|
8628
|
+
...event.blockedBy ? { blocked_by: event.blockedBy } : {},
|
|
8629
|
+
...args
|
|
8630
|
+
});
|
|
8631
|
+
}
|
|
8632
|
+
function captureLoopBlocked(apiKey, event) {
|
|
8633
|
+
capture(
|
|
8634
|
+
"runpod_mcp_loop_blocked",
|
|
8635
|
+
analyticsCallerId(apiKey, event.accountId),
|
|
8636
|
+
{
|
|
8637
|
+
tool: event.tool,
|
|
8638
|
+
blocked_for_s: event.blockedForS,
|
|
8639
|
+
transport: event.transport,
|
|
8640
|
+
server_version: event.serverVersion,
|
|
8641
|
+
...event.clientName ? { client_name: event.clientName } : {}
|
|
8642
|
+
}
|
|
8643
|
+
);
|
|
8644
|
+
}
|
|
8645
|
+
function captureResourceCall(apiKey, event) {
|
|
8646
|
+
capture(
|
|
8647
|
+
"runpod_mcp_resource_call",
|
|
8648
|
+
analyticsCallerId(apiKey, event.accountId),
|
|
8649
|
+
{
|
|
8650
|
+
method: event.method,
|
|
8651
|
+
uri: bounded(event.uri),
|
|
8652
|
+
ok: event.ok,
|
|
8653
|
+
transport: event.transport,
|
|
8654
|
+
server_version: event.serverVersion,
|
|
8655
|
+
...event.clientName ? { client_name: event.clientName } : {}
|
|
8656
|
+
}
|
|
8657
|
+
);
|
|
8658
|
+
}
|
|
8659
|
+
|
|
8660
|
+
// src/alp/ingest.ts
|
|
8661
|
+
function isSinkUrl(value) {
|
|
8662
|
+
try {
|
|
8663
|
+
const url = new URL(value);
|
|
8664
|
+
return url.protocol === "https:" && url.hostname.endsWith(".convex.site") && url.pathname === "/alp/submit";
|
|
8665
|
+
} catch {
|
|
8666
|
+
return false;
|
|
8667
|
+
}
|
|
8668
|
+
}
|
|
7957
8669
|
|
|
7958
8670
|
// src/alp/read.ts
|
|
7959
8671
|
var DEFAULT_JOURNAL_LIMIT = 20;
|
|
@@ -8175,6 +8887,177 @@ function createAlpTools(opts) {
|
|
|
8175
8887
|
return [reportFeedback, saveToJournal, askQuestion, readJournalTool];
|
|
8176
8888
|
}
|
|
8177
8889
|
|
|
8890
|
+
// src/search/knowledge.ts
|
|
8891
|
+
var SEARCH_NAMESPACES = ["docs", "knowledge", "blog", "site"];
|
|
8892
|
+
var MAX_QUERY_CHARS = 2e3;
|
|
8893
|
+
var MAX_SEARCH_LIMIT = 20;
|
|
8894
|
+
var ATTEMPTS = 7;
|
|
8895
|
+
var BASE_DELAY_MS = 250;
|
|
8896
|
+
var ATTEMPT_TIMEOUT_MS = 1e4;
|
|
8897
|
+
var RETRY_DEADLINE_MS = 3e4;
|
|
8898
|
+
var PLATFORM_LIMIT = /TooManyConcurrentRequests|Too many concurrent requests/;
|
|
8899
|
+
var AT_CAPACITY = {
|
|
8900
|
+
status: 503,
|
|
8901
|
+
body: {
|
|
8902
|
+
error: "Runpod knowledge search is at capacity.",
|
|
8903
|
+
hint: "Retry the same call in a few seconds."
|
|
8904
|
+
}
|
|
8905
|
+
};
|
|
8906
|
+
var UNREACHABLE = {
|
|
8907
|
+
status: 504,
|
|
8908
|
+
body: {
|
|
8909
|
+
error: "Runpod knowledge search did not respond.",
|
|
8910
|
+
hint: "Retry the same call once."
|
|
8911
|
+
}
|
|
8912
|
+
};
|
|
8913
|
+
function searchConfigured(env = process.env) {
|
|
8914
|
+
return Boolean(knowledgeSearchBase(env) && env.RUNPOD_ASSISTANT_API_KEY);
|
|
8915
|
+
}
|
|
8916
|
+
function parseSearchRequest(raw) {
|
|
8917
|
+
if (typeof raw.query !== "string" || !raw.query.trim()) {
|
|
8918
|
+
return { error: "query must be a non-empty string." };
|
|
8919
|
+
}
|
|
8920
|
+
if (raw.query.length > MAX_QUERY_CHARS) {
|
|
8921
|
+
return { error: `query exceeds ${MAX_QUERY_CHARS} characters.` };
|
|
8922
|
+
}
|
|
8923
|
+
const request = { query: raw.query };
|
|
8924
|
+
if (raw.namespaces !== void 0) {
|
|
8925
|
+
if (!Array.isArray(raw.namespaces) || raw.namespaces.length === 0 || !raw.namespaces.every(
|
|
8926
|
+
(ns) => SEARCH_NAMESPACES.includes(ns)
|
|
8927
|
+
)) {
|
|
8928
|
+
return {
|
|
8929
|
+
error: `namespaces must be a non-empty list of: ${SEARCH_NAMESPACES.join(", ")}.`
|
|
8930
|
+
};
|
|
8931
|
+
}
|
|
8932
|
+
request.namespaces = raw.namespaces;
|
|
8933
|
+
}
|
|
8934
|
+
if (raw.limit !== void 0) {
|
|
8935
|
+
if (typeof raw.limit !== "number" || !Number.isInteger(raw.limit) || raw.limit < 1 || raw.limit > MAX_SEARCH_LIMIT) {
|
|
8936
|
+
return {
|
|
8937
|
+
error: `limit must be an integer from 1 to ${MAX_SEARCH_LIMIT}.`
|
|
8938
|
+
};
|
|
8939
|
+
}
|
|
8940
|
+
request.limit = raw.limit;
|
|
8941
|
+
}
|
|
8942
|
+
return { request };
|
|
8943
|
+
}
|
|
8944
|
+
async function searchKnowledge(request, opts = {}) {
|
|
8945
|
+
const env = opts.env ?? process.env;
|
|
8946
|
+
const doFetch = opts.fetch ?? fetch;
|
|
8947
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
8948
|
+
const now = opts.now ?? Date.now;
|
|
8949
|
+
if (!searchConfigured(env)) {
|
|
8950
|
+
return {
|
|
8951
|
+
status: 503,
|
|
8952
|
+
body: { error: "Knowledge search is not configured on this server." }
|
|
8953
|
+
};
|
|
8954
|
+
}
|
|
8955
|
+
const url = `${knowledgeSearchBase(env)}/v1/search`;
|
|
8956
|
+
const init = {
|
|
8957
|
+
method: "POST",
|
|
8958
|
+
headers: {
|
|
8959
|
+
Authorization: `Bearer ${env.RUNPOD_ASSISTANT_API_KEY}`,
|
|
8960
|
+
"Content-Type": "application/json"
|
|
8961
|
+
},
|
|
8962
|
+
body: JSON.stringify({ ...request, source: "runpod-mcp" })
|
|
8963
|
+
};
|
|
8964
|
+
const startedAt = now();
|
|
8965
|
+
for (let attempt = 1; ; attempt++) {
|
|
8966
|
+
try {
|
|
8967
|
+
const res = await doFetch(url, {
|
|
8968
|
+
...init,
|
|
8969
|
+
signal: AbortSignal.timeout(ATTEMPT_TIMEOUT_MS)
|
|
8970
|
+
});
|
|
8971
|
+
if (res.ok) {
|
|
8972
|
+
const data = await res.json().catch(() => null);
|
|
8973
|
+
if (!data) {
|
|
8974
|
+
console.warn("knowledge_search_failed status=200 invalid_json");
|
|
8975
|
+
return {
|
|
8976
|
+
status: 502,
|
|
8977
|
+
body: { error: "Runpod knowledge search failed." }
|
|
8978
|
+
};
|
|
8979
|
+
}
|
|
8980
|
+
return {
|
|
8981
|
+
status: 200,
|
|
8982
|
+
body: {
|
|
8983
|
+
text: String(data.text ?? ""),
|
|
8984
|
+
totalResults: Number(data.totalResults ?? 0),
|
|
8985
|
+
failedNamespaces: Array.isArray(data.failedNamespaces) ? data.failedNamespaces : []
|
|
8986
|
+
}
|
|
8987
|
+
};
|
|
8988
|
+
}
|
|
8989
|
+
const text = await res.text();
|
|
8990
|
+
const retryable = res.status === 503 || res.status === 429 || PLATFORM_LIMIT.test(text);
|
|
8991
|
+
if (!retryable) {
|
|
8992
|
+
console.warn(`knowledge_search_failed status=${res.status}`);
|
|
8993
|
+
return res.status === 400 ? { status: 400, body: { error: errorField(text) } } : { status: 502, body: { error: "Runpod knowledge search failed." } };
|
|
8994
|
+
}
|
|
8995
|
+
} catch (error) {
|
|
8996
|
+
console.warn(
|
|
8997
|
+
`knowledge_search_unreachable ${error instanceof Error ? error.name : "error"}`
|
|
8998
|
+
);
|
|
8999
|
+
return UNREACHABLE;
|
|
9000
|
+
}
|
|
9001
|
+
const delay = Math.random() * BASE_DELAY_MS * 2 ** (attempt - 1);
|
|
9002
|
+
if (attempt >= ATTEMPTS || now() - startedAt + delay > RETRY_DEADLINE_MS) {
|
|
9003
|
+
return AT_CAPACITY;
|
|
9004
|
+
}
|
|
9005
|
+
await sleep2(delay);
|
|
9006
|
+
}
|
|
9007
|
+
}
|
|
9008
|
+
function errorField(text) {
|
|
9009
|
+
try {
|
|
9010
|
+
const parsed = JSON.parse(text);
|
|
9011
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
9012
|
+
} catch {
|
|
9013
|
+
}
|
|
9014
|
+
return "Invalid search request.";
|
|
9015
|
+
}
|
|
9016
|
+
|
|
9017
|
+
// src/specgen/tools/search.ts
|
|
9018
|
+
function createSearchDocsTool(search) {
|
|
9019
|
+
return {
|
|
9020
|
+
name: "search-docs",
|
|
9021
|
+
annotations: readOnly,
|
|
9022
|
+
recordedArguments: ["limit"],
|
|
9023
|
+
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.',
|
|
9024
|
+
inputSchema: {
|
|
9025
|
+
type: "object",
|
|
9026
|
+
properties: {
|
|
9027
|
+
query: {
|
|
9028
|
+
type: "string",
|
|
9029
|
+
maxLength: MAX_QUERY_CHARS,
|
|
9030
|
+
description: "The question, in natural language."
|
|
9031
|
+
},
|
|
9032
|
+
namespaces: {
|
|
9033
|
+
type: "array",
|
|
9034
|
+
items: { type: "string", enum: [...SEARCH_NAMESPACES] },
|
|
9035
|
+
minItems: 1,
|
|
9036
|
+
description: "Sources to search: docs (docs.runpod.io), knowledge (curated support answers), blog, site (runpod.io pages). Default: docs, knowledge, blog."
|
|
9037
|
+
},
|
|
9038
|
+
limit: {
|
|
9039
|
+
type: "integer",
|
|
9040
|
+
minimum: 1,
|
|
9041
|
+
maximum: MAX_SEARCH_LIMIT,
|
|
9042
|
+
description: "Most passages to return. Default 8."
|
|
9043
|
+
}
|
|
9044
|
+
},
|
|
9045
|
+
required: ["query"],
|
|
9046
|
+
additionalProperties: false
|
|
9047
|
+
},
|
|
9048
|
+
handler: async (ctx, args) => {
|
|
9049
|
+
const parsed = parseSearchRequest(args);
|
|
9050
|
+
if ("error" in parsed) return badRequest(parsed.error);
|
|
9051
|
+
const outcome = await search(parsed.request, ctx.apiKey);
|
|
9052
|
+
return {
|
|
9053
|
+
ok: outcome.status === 200,
|
|
9054
|
+
status: outcome.status,
|
|
9055
|
+
payload: outcome.body
|
|
9056
|
+
};
|
|
9057
|
+
}
|
|
9058
|
+
};
|
|
9059
|
+
}
|
|
9060
|
+
|
|
8178
9061
|
// src/specgen/ops.ts
|
|
8179
9062
|
var import_node_crypto2 = require("crypto");
|
|
8180
9063
|
var SALT = (0, import_node_crypto2.randomBytes)(16).toString("hex");
|
|
@@ -8199,6 +9082,9 @@ var curatedTools = [
|
|
|
8199
9082
|
listPublicEndpoints,
|
|
8200
9083
|
...knowledgeTools
|
|
8201
9084
|
];
|
|
9085
|
+
var responseHoldingTools = new Set(
|
|
9086
|
+
curatedTools.filter((tool) => tool.holdsResponse).map((tool) => tool.name)
|
|
9087
|
+
);
|
|
8202
9088
|
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.
|
|
8203
9089
|
|
|
8204
9090
|
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.
|
|
@@ -8215,14 +9101,22 @@ PLAYBOOKS \u2014 READ BEFORE ACTING. Each Runpod task has a journey playbook car
|
|
|
8215
9101
|
|
|
8216
9102
|
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.
|
|
8217
9103
|
|
|
8218
|
-
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.`;
|
|
9104
|
+
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.`;
|
|
8219
9105
|
var ALP_INSTRUCTIONS = `
|
|
8220
9106
|
|
|
8221
9107
|
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.`;
|
|
8222
9108
|
function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
8223
9109
|
const rateLimiter = opts.rateLimiter ?? noopRateLimiter;
|
|
8224
9110
|
const caller = callerId(ctx.apiKey);
|
|
8225
|
-
const servedCuratedTools =
|
|
9111
|
+
const servedCuratedTools = [
|
|
9112
|
+
...curatedTools,
|
|
9113
|
+
...opts.search ? [createSearchDocsTool(opts.search)] : [],
|
|
9114
|
+
...opts.alp ? createAlpTools(opts.alp) : [],
|
|
9115
|
+
createDescribeTool(() => [...servedCuratedTools, ...generatedTools])
|
|
9116
|
+
];
|
|
9117
|
+
const callShapeOnlyTools = new Set(
|
|
9118
|
+
[...servedCuratedTools, ...generatedTools].filter((tool) => tool.schemaOnDemand).map((tool) => tool.name)
|
|
9119
|
+
);
|
|
8226
9120
|
const server = new import_server.Server(
|
|
8227
9121
|
{ name: SERVER_NAME, version: `${version} [specgen]` },
|
|
8228
9122
|
{
|
|
@@ -8241,24 +9135,7 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8241
9135
|
}
|
|
8242
9136
|
};
|
|
8243
9137
|
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({
|
|
8244
|
-
tools: [
|
|
8245
|
-
...servedCuratedTools.map(
|
|
8246
|
-
({ name, description, inputSchema, annotations }) => ({
|
|
8247
|
-
name,
|
|
8248
|
-
description,
|
|
8249
|
-
inputSchema,
|
|
8250
|
-
annotations
|
|
8251
|
-
})
|
|
8252
|
-
),
|
|
8253
|
-
...generatedTools.map(
|
|
8254
|
-
({ name, description, inputSchema, annotations }) => ({
|
|
8255
|
-
name,
|
|
8256
|
-
description,
|
|
8257
|
-
inputSchema,
|
|
8258
|
-
annotations
|
|
8259
|
-
})
|
|
8260
|
-
)
|
|
8261
|
-
]
|
|
9138
|
+
tools: [...servedCuratedTools, ...generatedTools].map(listTool)
|
|
8262
9139
|
}));
|
|
8263
9140
|
server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => ({
|
|
8264
9141
|
resources: guideResources.map(({ text: _text, ...resource }) => resource)
|
|
@@ -8270,6 +9147,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8270
9147
|
const guide = guideResources.find(
|
|
8271
9148
|
(candidate) => candidate.uri === request.params.uri
|
|
8272
9149
|
);
|
|
9150
|
+
if (opts.analytics) {
|
|
9151
|
+
captureResourceCall(ctx.apiKey, {
|
|
9152
|
+
method: "resources/read",
|
|
9153
|
+
uri: guide ? guide.uri : "unknown",
|
|
9154
|
+
ok: Boolean(guide),
|
|
9155
|
+
...opts.analytics
|
|
9156
|
+
});
|
|
9157
|
+
}
|
|
8273
9158
|
if (!guide) {
|
|
8274
9159
|
throw new Error(
|
|
8275
9160
|
`Unknown resource ${request.params.uri}. Resources are the plugin guides under ${GUIDE_URI_PREFIX}; call list-guides for the guide ids.`
|
|
@@ -8292,6 +9177,16 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8292
9177
|
status: 429,
|
|
8293
9178
|
durationMs: 0
|
|
8294
9179
|
});
|
|
9180
|
+
if (opts.analytics) {
|
|
9181
|
+
captureToolCall(ctx.apiKey, {
|
|
9182
|
+
tool: request.params.name,
|
|
9183
|
+
ok: false,
|
|
9184
|
+
status: 429,
|
|
9185
|
+
durationMs: 0,
|
|
9186
|
+
...verdict.reason ? { blockedBy: verdict.reason } : {},
|
|
9187
|
+
...opts.analytics
|
|
9188
|
+
});
|
|
9189
|
+
}
|
|
8295
9190
|
return {
|
|
8296
9191
|
content: [
|
|
8297
9192
|
{
|
|
@@ -8329,11 +9224,14 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8329
9224
|
ok: result.ok,
|
|
8330
9225
|
status: result.status,
|
|
8331
9226
|
durationMs: Date.now() - startedAt,
|
|
9227
|
+
args: recordedArgumentValues(curated?.recordedArguments, args),
|
|
9228
|
+
guideKind: curated?.recordedGuideKind?.(args),
|
|
8332
9229
|
...opts.analytics
|
|
8333
9230
|
});
|
|
8334
9231
|
}
|
|
9232
|
+
opts.onToolResult?.(request.params.name, result.status);
|
|
8335
9233
|
if (!result.ok && result.status === 401) opts.onUnauthorized?.();
|
|
8336
|
-
const payload = result.ok ? result.payload : withRecoveryHint(result);
|
|
9234
|
+
const payload = result.ok ? result.payload : withRecoveryHint(result, callShapeOnlyTools.has(request.params.name));
|
|
8337
9235
|
return {
|
|
8338
9236
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
8339
9237
|
isError: !result.ok
|
|
@@ -8351,9 +9249,29 @@ function createSpecgenServer(ctx, version = "0.1.0", opts = {}) {
|
|
|
8351
9249
|
}
|
|
8352
9250
|
return server;
|
|
8353
9251
|
}
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
9252
|
+
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.";
|
|
9253
|
+
var DETAIL_HINTS = [
|
|
9254
|
+
[
|
|
9255
|
+
/no longer any instances available|not enough free GPUs/i,
|
|
9256
|
+
"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."
|
|
9257
|
+
],
|
|
9258
|
+
[
|
|
9259
|
+
/at least \$\d|insufficient (?:funds|balance)|\bbalance\b/i,
|
|
9260
|
+
"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."
|
|
9261
|
+
],
|
|
9262
|
+
[
|
|
9263
|
+
/mutually exclusive|cannot be combined with/i,
|
|
9264
|
+
"Two arguments conflict: send only one of them and leave the other out entirely. Do not change anything else."
|
|
9265
|
+
]
|
|
9266
|
+
];
|
|
9267
|
+
function errorHint(status, detail) {
|
|
9268
|
+
if (status === 400 && detail) {
|
|
9269
|
+
for (const [pattern, hint] of DETAIL_HINTS)
|
|
9270
|
+
if (pattern.test(detail)) return hint;
|
|
9271
|
+
if (/^unauthorized$/i.test(detail.trim()))
|
|
9272
|
+
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.";
|
|
9273
|
+
}
|
|
9274
|
+
if (status === 400 || status === 422) return SHAPE_HINT;
|
|
8357
9275
|
if (status === 401) return "The Runpod API key is missing or invalid.";
|
|
8358
9276
|
if (status === 402)
|
|
8359
9277
|
return "Check your account balance in the Runpod console before retrying billable operations; list-billing shows the recent spend behind it.";
|
|
@@ -8367,13 +9285,23 @@ function errorHint(status) {
|
|
|
8367
9285
|
return "Upstream Runpod error: retry once; if it persists, report it as an API-side failure.";
|
|
8368
9286
|
return void 0;
|
|
8369
9287
|
}
|
|
8370
|
-
|
|
9288
|
+
var CALL_SHAPE_ONLY_HINT = `This tool lists its call shape only; ${DESCRIBE_TOOL_NAME} serves the full argument schema.`;
|
|
9289
|
+
function withRecoveryHint(result, listsCallShapeOnly = false) {
|
|
8371
9290
|
const payload = asRecord(result.payload) ?? { error: result.payload };
|
|
9291
|
+
const hint = payload.hint ?? asRecord(payload.detail)?.hint ?? errorHint(result.status, detailText(payload));
|
|
9292
|
+
const shapeRejected = result.status === 400 || result.status === 422;
|
|
8372
9293
|
return {
|
|
8373
9294
|
...payload,
|
|
8374
|
-
hint:
|
|
9295
|
+
hint: listsCallShapeOnly && shapeRejected ? [hint, CALL_SHAPE_ONLY_HINT].filter(Boolean).join(" ") : hint
|
|
8375
9296
|
};
|
|
8376
9297
|
}
|
|
9298
|
+
function detailText(payload) {
|
|
9299
|
+
if (Array.isArray(payload.errors) && payload.errors.length) return void 0;
|
|
9300
|
+
const detail = payload.detail ?? payload.error;
|
|
9301
|
+
if (typeof detail === "string") return detail;
|
|
9302
|
+
const nested = asRecord(detail);
|
|
9303
|
+
return typeof nested?.detail === "string" ? nested.detail : void 0;
|
|
9304
|
+
}
|
|
8377
9305
|
function asRecord(value) {
|
|
8378
9306
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
8379
9307
|
}
|
|
@@ -8539,6 +9467,58 @@ function createToolContext(options = {}) {
|
|
|
8539
9467
|
};
|
|
8540
9468
|
}
|
|
8541
9469
|
|
|
9470
|
+
// src/specgen/not-found-limiter.ts
|
|
9471
|
+
var SINK_TIMEOUT_MS = 3e3;
|
|
9472
|
+
var NOT_FOUND_LOOP = "not_found_loop";
|
|
9473
|
+
var blocked = /* @__PURE__ */ new Map();
|
|
9474
|
+
function notFoundSinkUrl(submitUrl) {
|
|
9475
|
+
if (!isSinkUrl(submitUrl)) return null;
|
|
9476
|
+
const url = new URL(submitUrl);
|
|
9477
|
+
url.pathname = "/ratelimit/not-found";
|
|
9478
|
+
return url.toString();
|
|
9479
|
+
}
|
|
9480
|
+
function createNotFoundLimiter(opts) {
|
|
9481
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
9482
|
+
const now = opts.now ?? Date.now;
|
|
9483
|
+
return {
|
|
9484
|
+
rateLimiter: async (_caller, tool) => {
|
|
9485
|
+
const pair = `${opts.key}|${tool}`;
|
|
9486
|
+
const until = blocked.get(pair);
|
|
9487
|
+
if (until === void 0) return { allowed: true };
|
|
9488
|
+
if (until <= now()) {
|
|
9489
|
+
blocked.delete(pair);
|
|
9490
|
+
return { allowed: true };
|
|
9491
|
+
}
|
|
9492
|
+
return {
|
|
9493
|
+
allowed: false,
|
|
9494
|
+
retryAfterS: Math.ceil((until - now()) / 1e3),
|
|
9495
|
+
reason: NOT_FOUND_LOOP
|
|
9496
|
+
};
|
|
9497
|
+
},
|
|
9498
|
+
onToolResult: (tool, status) => {
|
|
9499
|
+
if (status !== 404) return;
|
|
9500
|
+
const pair = `${opts.key}|${tool}`;
|
|
9501
|
+
void fetchImpl(opts.sinkUrl, {
|
|
9502
|
+
method: "POST",
|
|
9503
|
+
headers: {
|
|
9504
|
+
"Content-Type": "application/json",
|
|
9505
|
+
"X-ALP-Secret": opts.secret
|
|
9506
|
+
},
|
|
9507
|
+
body: JSON.stringify({ key: pair }),
|
|
9508
|
+
signal: AbortSignal.timeout(SINK_TIMEOUT_MS)
|
|
9509
|
+
}).then((response) => response.ok ? response.json() : null).then((body) => {
|
|
9510
|
+
const reply = body;
|
|
9511
|
+
const until = reply?.blockedUntil;
|
|
9512
|
+
if (typeof until === "number" && until > now()) {
|
|
9513
|
+
blocked.set(pair, until);
|
|
9514
|
+
if (reply?.started === true) opts.onBlockStarted?.(tool, until);
|
|
9515
|
+
}
|
|
9516
|
+
}).catch(() => {
|
|
9517
|
+
});
|
|
9518
|
+
}
|
|
9519
|
+
};
|
|
9520
|
+
}
|
|
9521
|
+
|
|
8542
9522
|
// src/_shared/credential-check.ts
|
|
8543
9523
|
var import_node_crypto4 = require("crypto");
|
|
8544
9524
|
var VALID_TTL_MS = 6e4;
|
|
@@ -8650,8 +9630,7 @@ function extractBearerToken(req) {
|
|
|
8650
9630
|
return parts[1];
|
|
8651
9631
|
}
|
|
8652
9632
|
function analyticsOptedOut(req) {
|
|
8653
|
-
const
|
|
8654
|
-
const value = (Array.isArray(raw) ? raw[0] : raw)?.trim().toLowerCase();
|
|
9633
|
+
const value = header(req, "x-runpod-analytics")?.trim().toLowerCase();
|
|
8655
9634
|
return value === "off" || value === "0" || value === "false";
|
|
8656
9635
|
}
|
|
8657
9636
|
function getBaseUrl(req) {
|
|
@@ -8710,14 +9689,16 @@ function credentialCheckMayBeWrongEnvironment(env = process.env) {
|
|
|
8710
9689
|
);
|
|
8711
9690
|
return restMoved !== graphqlMoved;
|
|
8712
9691
|
}
|
|
8713
|
-
function
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
9692
|
+
function parseMcpMessages(body) {
|
|
9693
|
+
const elements = Array.isArray(body) ? body : [body];
|
|
9694
|
+
return elements.flatMap((element) => {
|
|
9695
|
+
const parsed = import_types2.JSONRPCMessageSchema.safeParse(element);
|
|
9696
|
+
return parsed.success ? [parsed.data] : [];
|
|
9697
|
+
});
|
|
8717
9698
|
}
|
|
9699
|
+
var invokesMethod = (message) => "method" in message;
|
|
8718
9700
|
function bodyIsCheckable(body) {
|
|
8719
|
-
|
|
8720
|
-
return messages.some(looksLikeMcpMessage);
|
|
9701
|
+
return parseMcpMessages(body).some(invokesMethod);
|
|
8721
9702
|
}
|
|
8722
9703
|
function isJsonContentType(req) {
|
|
8723
9704
|
const ct = req.headers["content-type"];
|
|
@@ -8755,17 +9736,79 @@ function earlyCredentialCheckSkip(req) {
|
|
|
8755
9736
|
if (credentialCheckMayBeWrongEnvironment()) return "skip_env_mismatch";
|
|
8756
9737
|
return null;
|
|
8757
9738
|
}
|
|
9739
|
+
var callsResponseHoldingTool = (message) => {
|
|
9740
|
+
const call = import_types2.CallToolRequestSchema.safeParse(message);
|
|
9741
|
+
return call.success && responseHoldingTools.has(call.data.params.name);
|
|
9742
|
+
};
|
|
9743
|
+
function prefersJsonResponse(messages) {
|
|
9744
|
+
return messages.length > 0 && !messages.some(callsResponseHoldingTool);
|
|
9745
|
+
}
|
|
9746
|
+
var DEFAULT_REQUEST_LOG_SAMPLE_RATE = 0.1;
|
|
9747
|
+
function requestLogSampleRate(env = process.env) {
|
|
9748
|
+
if (env.MCP_VERBOSE_LOGS === "true") return 1;
|
|
9749
|
+
const raw = env.MCP_REQUEST_LOG_SAMPLE_RATE;
|
|
9750
|
+
if (raw === void 0 || raw === "") return DEFAULT_REQUEST_LOG_SAMPLE_RATE;
|
|
9751
|
+
const parsed = Number(raw);
|
|
9752
|
+
if (!Number.isFinite(parsed)) return DEFAULT_REQUEST_LOG_SAMPLE_RATE;
|
|
9753
|
+
return Math.min(1, Math.max(0, parsed));
|
|
9754
|
+
}
|
|
9755
|
+
function summarizeRpc(messages) {
|
|
9756
|
+
const rpc = messages.map((message) => {
|
|
9757
|
+
const call = import_types2.CallToolRequestSchema.safeParse(message);
|
|
9758
|
+
if (call.success) return `tools/call:${call.data.params.name}`;
|
|
9759
|
+
return "method" in message ? message.method : "response";
|
|
9760
|
+
});
|
|
9761
|
+
const init = messages.map((message) => import_types2.InitializeRequestSchema.safeParse(message)).find((result) => result.success);
|
|
9762
|
+
const client = init?.success ? `${init.data.params.clientInfo.name}/${init.data.params.clientInfo.version}` : void 0;
|
|
9763
|
+
return { rpc: rpc.length > 0 ? rpc.join(",") : void 0, client };
|
|
9764
|
+
}
|
|
9765
|
+
function header(req, name) {
|
|
9766
|
+
const value = req.headers[name];
|
|
9767
|
+
return Array.isArray(value) ? value[0] : value;
|
|
9768
|
+
}
|
|
9769
|
+
function clientAddress(req) {
|
|
9770
|
+
return header(req, "x-real-ip") || header(req, "x-forwarded-for")?.split(",")[0].trim() || req.socket?.remoteAddress || void 0;
|
|
9771
|
+
}
|
|
9772
|
+
function startRequestLog(req, res, bearerToken) {
|
|
9773
|
+
const sampleRate = requestLogSampleRate();
|
|
9774
|
+
if (Math.random() >= sampleRate) return { note() {
|
|
9775
|
+
} };
|
|
9776
|
+
const startedAt = Date.now();
|
|
9777
|
+
let summary = {};
|
|
9778
|
+
const address = clientAddress(req);
|
|
9779
|
+
const userAgent = header(req, "user-agent");
|
|
9780
|
+
let emitted = false;
|
|
9781
|
+
const emit = () => {
|
|
9782
|
+
if (emitted) return;
|
|
9783
|
+
emitted = true;
|
|
9784
|
+
console.log("mcp_request", {
|
|
9785
|
+
method: req.method,
|
|
9786
|
+
url: req.url,
|
|
9787
|
+
status: res.writableFinished ? res.statusCode : void 0,
|
|
9788
|
+
durationMs: Date.now() - startedAt,
|
|
9789
|
+
rpc: summary.rpc,
|
|
9790
|
+
client: summary.client,
|
|
9791
|
+
ua: userAgent?.slice(0, 160),
|
|
9792
|
+
caller: callerId(bearerToken ?? void 0),
|
|
9793
|
+
ip: address ? callerId(address) : void 0,
|
|
9794
|
+
sampleRate
|
|
9795
|
+
});
|
|
9796
|
+
};
|
|
9797
|
+
res.on("finish", emit);
|
|
9798
|
+
res.on("close", emit);
|
|
9799
|
+
return {
|
|
9800
|
+
note(next) {
|
|
9801
|
+
summary = next;
|
|
9802
|
+
}
|
|
9803
|
+
};
|
|
9804
|
+
}
|
|
8758
9805
|
function logCredentialCheck(outcome) {
|
|
8759
9806
|
if (outcome === "pass" && process.env.MCP_VERBOSE_LOGS !== "true") return;
|
|
8760
9807
|
console.log("credential_check", { outcome });
|
|
8761
9808
|
}
|
|
8762
9809
|
async function handleMcpRequest(req, res, opts = {}) {
|
|
8763
9810
|
const bearerToken = extractBearerToken(req);
|
|
8764
|
-
|
|
8765
|
-
method: req.method,
|
|
8766
|
-
url: req.url,
|
|
8767
|
-
hasBearerToken: !!bearerToken
|
|
8768
|
-
});
|
|
9811
|
+
const requestLog = startRequestLog(req, res, bearerToken);
|
|
8769
9812
|
if (req.method === "GET") {
|
|
8770
9813
|
res.writeHead(405, {
|
|
8771
9814
|
Allow: "POST, DELETE",
|
|
@@ -8794,9 +9837,7 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8794
9837
|
let body = req.body;
|
|
8795
9838
|
let accountId;
|
|
8796
9839
|
const early = earlyCredentialCheckSkip(req);
|
|
8797
|
-
if (early) {
|
|
8798
|
-
logCredentialCheck(early);
|
|
8799
|
-
} else {
|
|
9840
|
+
if (!early) {
|
|
8800
9841
|
const read = await readJsonBody(req);
|
|
8801
9842
|
if (read === BODY_TOO_LARGE) {
|
|
8802
9843
|
res.writeHead(413, { "Content-Type": "application/json" });
|
|
@@ -8804,26 +9845,47 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8804
9845
|
return;
|
|
8805
9846
|
}
|
|
8806
9847
|
body = read;
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
9848
|
+
}
|
|
9849
|
+
const messages = parseMcpMessages(body);
|
|
9850
|
+
requestLog.note(summarizeRpc(messages));
|
|
9851
|
+
if (early) {
|
|
9852
|
+
logCredentialCheck(early);
|
|
9853
|
+
} else if (!messages.some(invokesMethod)) {
|
|
9854
|
+
logCredentialCheck("skip_not_mcp_body");
|
|
9855
|
+
} else {
|
|
9856
|
+
const verify = opts.verifyCredential ?? defaultCredentialChecker.verify;
|
|
9857
|
+
const verdict = await verify(bearerToken);
|
|
9858
|
+
if (verdict.status === "valid") accountId = verdict.accountId;
|
|
9859
|
+
logCredentialCheck(
|
|
9860
|
+
verdict.status === "invalid" ? "reject" : verdict.status === "valid" ? "pass" : "fail_open"
|
|
9861
|
+
);
|
|
9862
|
+
if (verdict.status === "invalid") {
|
|
9863
|
+
writeUnauthorized(
|
|
9864
|
+
req,
|
|
9865
|
+
res,
|
|
9866
|
+
`${verdict.reason} Re-authenticate to continue.`,
|
|
9867
|
+
true
|
|
8815
9868
|
);
|
|
8816
|
-
|
|
8817
|
-
writeUnauthorized(
|
|
8818
|
-
req,
|
|
8819
|
-
res,
|
|
8820
|
-
`${verdict.reason} Re-authenticate to continue.`,
|
|
8821
|
-
true
|
|
8822
|
-
);
|
|
8823
|
-
return;
|
|
8824
|
-
}
|
|
9869
|
+
return;
|
|
8825
9870
|
}
|
|
8826
9871
|
}
|
|
9872
|
+
const notFoundUrl = process.env.ALP_SINK_URL ? notFoundSinkUrl(process.env.ALP_SINK_URL) : null;
|
|
9873
|
+
const notFoundLimiter = bearerToken && notFoundUrl && process.env.ALP_SINK_SECRET ? createNotFoundLimiter({
|
|
9874
|
+
key: analyticsCallerId(bearerToken, accountId),
|
|
9875
|
+
sinkUrl: notFoundUrl,
|
|
9876
|
+
secret: process.env.ALP_SINK_SECRET,
|
|
9877
|
+
// One usage event per block, unless this client opted out.
|
|
9878
|
+
onBlockStarted: analyticsOptedOut(req) ? void 0 : (tool, blockedUntil) => captureLoopBlocked(bearerToken, {
|
|
9879
|
+
tool,
|
|
9880
|
+
blockedForS: Math.round((blockedUntil - Date.now()) / 1e3),
|
|
9881
|
+
transport: "http",
|
|
9882
|
+
serverVersion: opts.serverVersion ?? SERVER_VERSION,
|
|
9883
|
+
clientName: sanitizeUaToken(
|
|
9884
|
+
String(req.headers["user-agent"] ?? "unknown")
|
|
9885
|
+
),
|
|
9886
|
+
accountId
|
|
9887
|
+
})
|
|
9888
|
+
}) : null;
|
|
8827
9889
|
const server = createSpecgenServer(
|
|
8828
9890
|
createToolContext({
|
|
8829
9891
|
apiKey: bearerToken,
|
|
@@ -8864,6 +9926,13 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8864
9926
|
harnessSource: "user_agent"
|
|
8865
9927
|
}
|
|
8866
9928
|
} : {},
|
|
9929
|
+
// search-docs: listed only where the deployment holds the assistant's
|
|
9930
|
+
// service key; the search runs in-process with it.
|
|
9931
|
+
...searchConfigured() ? { search: (request) => searchKnowledge(request) } : {},
|
|
9932
|
+
...notFoundLimiter ? {
|
|
9933
|
+
rateLimiter: notFoundLimiter.rateLimiter,
|
|
9934
|
+
onToolResult: notFoundLimiter.onToolResult
|
|
9935
|
+
} : {},
|
|
8867
9936
|
// A tool call that 401s proves a cached "valid" verdict wrong before
|
|
8868
9937
|
// its TTL — drop it so the next request re-checks and re-auths.
|
|
8869
9938
|
onUnauthorized: () => (opts.invalidateCredential ?? defaultCredentialChecker.invalidate)(
|
|
@@ -8872,8 +9941,9 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8872
9941
|
}
|
|
8873
9942
|
);
|
|
8874
9943
|
const transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
8875
|
-
sessionIdGenerator: void 0
|
|
9944
|
+
sessionIdGenerator: void 0,
|
|
8876
9945
|
// stateless — no session persistence
|
|
9946
|
+
enableJsonResponse: prefersJsonResponse(messages)
|
|
8877
9947
|
});
|
|
8878
9948
|
res.on("close", () => {
|
|
8879
9949
|
transport.close().catch(() => {
|
|
@@ -8888,7 +9958,12 @@ async function handleMcpRequest(req, res, opts = {}) {
|
|
|
8888
9958
|
0 && (module.exports = {
|
|
8889
9959
|
bodyIsCheckable,
|
|
8890
9960
|
defaultCredentialChecker,
|
|
9961
|
+
extractBearerToken,
|
|
8891
9962
|
getBaseUrl,
|
|
8892
|
-
handleMcpRequest
|
|
9963
|
+
handleMcpRequest,
|
|
9964
|
+
parseMcpMessages,
|
|
9965
|
+
prefersJsonResponse,
|
|
9966
|
+
requestLogSampleRate,
|
|
9967
|
+
summarizeRpc
|
|
8893
9968
|
});
|
|
8894
9969
|
//# sourceMappingURL=http.cjs.map
|