ottoport 1.15.1 → 1.15.2
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/.claude-plugin/plugin.json +1 -1
- package/README.md +7 -1
- package/cli/ottoport.mjs +16 -6
- package/commands/image.md +8 -2
- package/commands/speech.md +1 -1
- package/mcp/server.mjs +10 -5
- package/package.json +1 -1
- package/skills/ottoport/SKILL.md +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ottoport",
|
|
3
3
|
"description": "One API for every model. Call chat, image, video, speech and music models through the OttoPort gateway \u2014 as MCP tools, slash commands, or the bundled CLI.",
|
|
4
|
-
"version": "1.15.
|
|
4
|
+
"version": "1.15.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LITBOX LLC",
|
|
7
7
|
"email": "support@ottoport.ai"
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ ottoport video "<prompt>" [--model kling-3.0] [--duration 5] [--resolution 1080p
|
|
|
29
29
|
[--webhook-url https://…] [--no-wait]
|
|
30
30
|
ottoport webhook status|retry <job-id> # delivery attempts / redeliver now
|
|
31
31
|
ottoport speech "<text>" [--model gpt-4o-mini-tts] [--voice alloy] [--out speech.mp3]
|
|
32
|
-
ottoport music "<prompt>" [--model suno-
|
|
32
|
+
ottoport music "<prompt>" [--model suno-v6] [--duration 15] [--out song.mp3]
|
|
33
33
|
ottoport music --model mirelo-sfx-2.0 --video <url> [--duration 8] # soundtrack for a video
|
|
34
34
|
|
|
35
35
|
ottoport install <host> # wire the MCP server into an agent
|
|
@@ -118,6 +118,12 @@ raster, from a prompt alone: `output_format: "gif"` is an animation (`frame_coun
|
|
|
118
118
|
request. A GIF picks its own frame size, so `size`, `resolution` and
|
|
119
119
|
`aspect_ratio` do not apply to it.
|
|
120
120
|
|
|
121
|
+
```sh
|
|
122
|
+
ottoport image "a paper boat bobbing on water, seamless loop" --format gif --wait --out boat.gif
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Asking for either format with no model named uses `gpt-image-2.6`.
|
|
126
|
+
|
|
121
127
|
Which modes and tiers a model accepts differs per model, so
|
|
122
128
|
`ottoport_list_models` — and `ottoport models` in the CLI — prints each one's
|
|
123
129
|
menu beside its price. For one model in full, including every parameter it
|
package/cli/ottoport.mjs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// ottoport image "prompt" [--model gpt-image-2] [--resolution 2k] [--ref a.png,b.png] [--out img.png]
|
|
10
10
|
// ottoport video "prompt" [--model kling-3.0] [--duration 5] [--out clip.mp4]
|
|
11
11
|
// ottoport speech "text" [--model gpt-4o-mini-tts] [--voice alloy] [--out speech.mp3]
|
|
12
|
-
// ottoport music "prompt" [--model suno-
|
|
12
|
+
// ottoport music "prompt" [--model suno-v6] [--duration 15] [--out song.mp3]
|
|
13
13
|
// ottoport music --model mirelo-sfx-2.0 --video <url> [--duration 8]
|
|
14
14
|
// ottoport collections [list | create "name"]
|
|
15
15
|
// ottoport mcp
|
|
@@ -116,6 +116,7 @@ async function cmdModel(id, flags) {
|
|
|
116
116
|
: caps.resolutions;
|
|
117
117
|
console.log(`resolution: ${tiers.join(", ")}${caps.base_resolution ? ` (base ${caps.base_resolution})` : ""}`);
|
|
118
118
|
}
|
|
119
|
+
if (caps?.outputFormats?.length) console.log(`outputs: ${caps.outputFormats.join(", ")}, besides images (--format)`);
|
|
119
120
|
console.log("parameters:");
|
|
120
121
|
for (const p of m.parameters ?? []) {
|
|
121
122
|
console.log(` ${String(p.name).padEnd(21)}${p.type}${p.required ? ", required" : ""} — ${p.note}`);
|
|
@@ -150,7 +151,8 @@ function capabilityLine(caps) {
|
|
|
150
151
|
return `accepts: ${caps.modes.join(", ")}${refs} · ${caps.resolutions.join("/")}`;
|
|
151
152
|
}
|
|
152
153
|
const inputs = caps.maxInputImages ? `up to ${caps.maxInputImages} input images` : "text only";
|
|
153
|
-
|
|
154
|
+
const formats = caps.outputFormats?.length ? ` · also outputs ${caps.outputFormats.join("/")}` : "";
|
|
155
|
+
return `accepts: ${inputs} · ${caps.resolutions.join("/")}${formats}`;
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
async function cmdChat(prompt, flags) {
|
|
@@ -300,9 +302,17 @@ async function cmdImage(prompt, flags) {
|
|
|
300
302
|
// A layer-decomposition model needs only --image; the prompt is a caption.
|
|
301
303
|
if (!prompt && !last(flags.image)) die("image requires a prompt: ottoport image \"a red fox\" (or --image <url> on a layer model)");
|
|
302
304
|
const { baseUrl, apiKey } = config(flags);
|
|
305
|
+
const format = last(flags.format);
|
|
306
|
+
const wantsFile = format === "gif" || format === "svg";
|
|
307
|
+
// Checked before anything is spent: the file would hold one format under another's name.
|
|
308
|
+
const outExtension = String(last(flags.out) ?? "").match(/\.(png|jpe?g|webp|gif|svg)$/i)?.[1].toLowerCase();
|
|
309
|
+
if (wantsFile && outExtension && outExtension !== format) {
|
|
310
|
+
die(`--format ${format} returns a .${format} file, but --out names a .${outExtension} one. Change one of them.`);
|
|
311
|
+
}
|
|
303
312
|
const body = {
|
|
304
313
|
async: true,
|
|
305
|
-
model
|
|
314
|
+
// The default model has no GIF or SVG output, so asking for one picks a model that does.
|
|
315
|
+
model: last(flags.model) || (wantsFile ? "gpt-image-2.6" : "gpt-image-2"),
|
|
306
316
|
...(prompt ? { prompt } : {}),
|
|
307
317
|
...(last(flags.layers) ? { num_layers: Number(last(flags.layers)) } : {}),
|
|
308
318
|
...(last(flags.size) ? { size: last(flags.size) } : {}),
|
|
@@ -437,7 +447,7 @@ async function cmdAudio(kind, prompt, flags) {
|
|
|
437
447
|
const { baseUrl, apiKey } = config(flags);
|
|
438
448
|
const body = {
|
|
439
449
|
async: true,
|
|
440
|
-
model: last(flags.model) || (kind === "speech" ? "gpt-4o-mini-tts" : "suno-
|
|
450
|
+
model: last(flags.model) || (kind === "speech" ? "gpt-4o-mini-tts" : "suno-v6"),
|
|
441
451
|
...(prompt ? { prompt } : {}),
|
|
442
452
|
...(video ? { video_url: video } : {}),
|
|
443
453
|
...(last(flags.voice) ? { voice: last(flags.voice) } : {}),
|
|
@@ -528,7 +538,7 @@ Usage:
|
|
|
528
538
|
ottoport image "<prompt>" [--model gpt-image-2] [--size 1024x1024 | --resolution 2k] [--quality high]
|
|
529
539
|
[--aspect-ratio 16:9] [--n 1] [--seed 7]
|
|
530
540
|
[--image <url>] [--ref <url>[,<url>…]] [--out file.png]
|
|
531
|
-
ottoport image "<prompt>" --model gpt-image-2.6
|
|
541
|
+
ottoport image "<prompt>" --format gif|svg [--model gpt-image-2.6] [--frames 8] [--frame-ms 200] [--wait --out loop.gif]
|
|
532
542
|
ottoport image --model qwen-image-layered --image <url> [--layers 4]
|
|
533
543
|
split one image into RGBA layers (prompt optional)
|
|
534
544
|
ottoport video "<prompt>" [--model kling-3.0] [--duration 5] [--resolution 1080p]
|
|
@@ -545,7 +555,7 @@ Usage:
|
|
|
545
555
|
ottoport webhook status <job-id> [--json] delivery attempts and responses
|
|
546
556
|
ottoport webhook retry <job-id> [--json] redeliver a finished job's webhook now
|
|
547
557
|
ottoport speech "<text>" [--model gpt-4o-mini-tts] [--voice alloy] [--format mp3] [--out speech.mp3]
|
|
548
|
-
ottoport music "<prompt>" [--model suno-
|
|
558
|
+
ottoport music "<prompt>" [--model suno-v6] [--duration 15] [--format mp3] [--out song.mp3]
|
|
549
559
|
ottoport music ["<prompt>"] --model mirelo-sfx-2.0 --video <url> [--duration 8] [--out sfx.wav]
|
|
550
560
|
a soundtrack synced to the video, dialogue kept;
|
|
551
561
|
set --duration to the clip's length (it bills)
|
package/commands/image.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Generate an image through the OttoPort gateway
|
|
3
|
-
argument-hint: "<prompt> [--model <id>] [--resolution 2k] [--quality high] [--ref <url>…]"
|
|
3
|
+
argument-hint: "<prompt> [--model <id>] [--resolution 2k] [--quality high] [--ref <url>…] [--format gif|svg]"
|
|
4
4
|
allowed-tools: mcp__ottoport__ottoport_generate_image, mcp__ottoport__ottoport_list_models, Bash(curl:*)
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -9,6 +9,12 @@ Generate an image with the `ottoport_generate_image` MCP tool.
|
|
|
9
9
|
Request: $ARGUMENTS
|
|
10
10
|
|
|
11
11
|
- Pass `model` only if the user named one; the tool defaults to `gpt-image-2`.
|
|
12
|
+
- An animated GIF or an SVG file comes from this tool, not from a video model:
|
|
13
|
+
set `output_format` to `gif` or `svg`, and the tool picks `gpt-image-2.6`. Only
|
|
14
|
+
that model and `gpt-image-2.6-flare` offer them, from a prompt alone, one file
|
|
15
|
+
per request. Put the motion and the loop in a GIF's prompt, and send no `size`,
|
|
16
|
+
`resolution` or `aspect_ratio` with it. `frame_count` is 2–16 (default 8; above
|
|
17
|
+
8 bills double) and `frame_duration_ms` is 20–2000.
|
|
12
18
|
- An edit of an existing image goes through `image_url`, not the prompt. Several
|
|
13
19
|
references at once — a character plus the scene, a product plus a style — go
|
|
14
20
|
through `reference_image_urls`.
|
|
@@ -16,7 +22,7 @@ Request: $ARGUMENTS
|
|
|
16
22
|
`size` instead when the user named exact pixels. A higher tier costs more, so
|
|
17
23
|
send one only when the request asks for it.
|
|
18
24
|
- On the GPT Image models, `quality` buys compute rather than pixels — `low`,
|
|
19
|
-
`medium` (the default), `high`, and `xhigh`/`max` on `gpt-image-2.5`. It is
|
|
25
|
+
`medium` (the default), `high`, and `xhigh`/`max` on `gpt-image-2.6` and `gpt-image-2.5`. It is
|
|
20
26
|
billed steeply, so send it only when the user asked for a draft or a finish.
|
|
21
27
|
- Models differ in how many references and which resolutions they take. If a
|
|
22
28
|
request needs more than one reference, or 4k, check `ottoport_list_models`
|
package/commands/speech.md
CHANGED
|
@@ -11,7 +11,7 @@ backing track — or for sound effects, ambience or a soundtrack for a video, wi
|
|
|
11
11
|
`model` `mirelo-sfx-2.0` (pass the video as `video_url`, and `duration` as its
|
|
12
12
|
length); otherwise use `ottoport_generate_speech` to read the text aloud.
|
|
13
13
|
Pass `voice` and `format` only when named — speech defaults to `gpt-4o-mini-tts`
|
|
14
|
-
with the `alloy` voice, music to `suno-
|
|
14
|
+
with the `alloy` voice, music to `suno-v6`.
|
|
15
15
|
|
|
16
16
|
Print the returned audio URL, and save it to disk with `curl -sSL` only if the
|
|
17
17
|
user asked for a file.
|
package/mcp/server.mjs
CHANGED
|
@@ -185,6 +185,9 @@ function accepts(capabilities) {
|
|
|
185
185
|
if (Array.isArray(capabilities.resolutions) && capabilities.resolutions.length) {
|
|
186
186
|
parts.push(capabilities.resolutions.join("/"));
|
|
187
187
|
}
|
|
188
|
+
if (Array.isArray(capabilities.outputFormats) && capabilities.outputFormats.length) {
|
|
189
|
+
parts.push(`output_format ${capabilities.outputFormats.join("/")}`);
|
|
190
|
+
}
|
|
188
191
|
return parts.length ? ` · accepts ${parts.join(", ")}` : "";
|
|
189
192
|
}
|
|
190
193
|
|
|
@@ -217,6 +220,7 @@ async function describeModel(id) {
|
|
|
217
220
|
: caps.resolutions;
|
|
218
221
|
lines.push(`Resolutions: ${tiers.join(", ")}${caps.base_resolution ? ` (base ${caps.base_resolution})` : ""}`);
|
|
219
222
|
}
|
|
223
|
+
if (caps?.outputFormats?.length) lines.push(`Output formats: ${caps.outputFormats.join(", ")}, besides images, via output_format`);
|
|
220
224
|
lines.push("Parameters:");
|
|
221
225
|
for (const p of m.parameters ?? []) {
|
|
222
226
|
lines.push(` ${p.name} (${p.type}${p.required ? ", required" : ""}) — ${p.note}`);
|
|
@@ -329,7 +333,8 @@ async function generateImage({ prompt, model, collection, wait = false, ...rest
|
|
|
329
333
|
// Queued as a job and polled: a 4K or layered image can take longer than
|
|
330
334
|
// a proxy in front of the gateway holds a request open, and the hold is
|
|
331
335
|
// then settled on what actually came back.
|
|
332
|
-
|
|
336
|
+
// The default model has no GIF or SVG output, so asking for one picks a model that does.
|
|
337
|
+
body: JSON.stringify({ model: model || (rest.output_format === "gif" || rest.output_format === "svg" ? "gpt-image-2.6" : "gpt-image-2"), ...(prompt ? { prompt } : {}), ...rest, ...withCollection(await collectionId(collection)), async: true }),
|
|
333
338
|
});
|
|
334
339
|
if (!res.ok) throw new Error(await gwError(res));
|
|
335
340
|
let json = await res.json();
|
|
@@ -397,7 +402,7 @@ async function generateAudio(kind, { prompt, model, voice, duration, format, vid
|
|
|
397
402
|
headers: { ...headers(), "idempotency-key": crypto.randomUUID() },
|
|
398
403
|
body: JSON.stringify({
|
|
399
404
|
async: true,
|
|
400
|
-
model: model || (kind === "tts" ? "gpt-4o-mini-tts" : "suno-
|
|
405
|
+
model: model || (kind === "tts" ? "gpt-4o-mini-tts" : "suno-v6"),
|
|
401
406
|
...(prompt ? { prompt } : {}),
|
|
402
407
|
...(voice ? { voice } : {}),
|
|
403
408
|
...(video_url ? { video_url } : {}),
|
|
@@ -459,13 +464,13 @@ const TOOLS = [
|
|
|
459
464
|
},
|
|
460
465
|
{
|
|
461
466
|
name: "ottoport_generate_image",
|
|
462
|
-
description: "Generate an image through an OttoPort image model (GPT Image, Nano Banana, …). Text-to-image, editing from one reference, or several references at once. Also layer decomposition: qwen-image-layered and seedream-5.0-layers take `image_url` alone and return the image split into RGBA layers, one URL per layer, billed per layer. Vectors: ideogram-vector-1 returns editable SVG from a prompt (shape it with `aspect_ratio`, not `size`), and ideogram-vector-1-vectorize takes `image_url` alone and returns it traced as SVG. Which a model accepts is in its capabilities — call ottoport_list_models. Defaults to asynchronous submission: returns job_id and polling instructions. Use ottoport_get_job for results.",
|
|
467
|
+
description: "Generate an image through an OttoPort image model (GPT Image, Nano Banana, …). Text-to-image, editing from one reference, or several references at once. Also layer decomposition: qwen-image-layered and seedream-5.0-layers take `image_url` alone and return the image split into RGBA layers, one URL per layer, billed per layer. Animated GIFs and SVG files from a prompt: set output_format on gpt-image-2.6 or its Flare tier, rather than generating a video. Vectors: ideogram-vector-1 returns editable SVG from a prompt (shape it with `aspect_ratio`, not `size`), and ideogram-vector-1-vectorize takes `image_url` alone and returns it traced as SVG. Which a model accepts is in its capabilities — call ottoport_list_models. Defaults to asynchronous submission: returns job_id and polling instructions. Use ottoport_get_job for results.",
|
|
463
468
|
inputSchema: {
|
|
464
469
|
type: "object",
|
|
465
470
|
properties: {
|
|
466
471
|
wait: { type: "boolean", description: "Default false: return job immediately. True waits up to 45 seconds, then returns the same job for polling." },
|
|
467
472
|
prompt: { type: "string", description: "What to generate. On a layer-decomposition model, an optional caption of the input image." },
|
|
468
|
-
model: { type: "string", description: "Model id, e.g. gpt-image-2, nano-banana-2.1, nano-banana-pro. Default gpt-image-2." },
|
|
473
|
+
model: { type: "string", description: "Model id, e.g. gpt-image-2, nano-banana-2.1, nano-banana-pro. Default gpt-image-2, or gpt-image-2.6 when output_format is gif or svg." },
|
|
469
474
|
size: { type: "string", description: 'Exact pixels, e.g. "1024x1024". Wins over `resolution`.' },
|
|
470
475
|
// No `enum`: the vocabulary is "1k"/"2k"/"4k", but which of them a given
|
|
471
476
|
// model actually offers differs per model, and an enum here reads as a
|
|
@@ -565,7 +570,7 @@ const TOOLS = [
|
|
|
565
570
|
properties: {
|
|
566
571
|
wait: { type: "boolean", description: "Default false: return job immediately. True waits up to 45 seconds, then returns the same job for polling." },
|
|
567
572
|
prompt: { type: "string", description: "Music-generation prompt, or the sounds to make. Optional with video_url." },
|
|
568
|
-
model: { type: "string", description: "Music model id. Default suno-
|
|
573
|
+
model: { type: "string", description: "Music model id. Default suno-v6; mirelo-sfx-2.0 for sound effects." },
|
|
569
574
|
duration: { type: "number", description: "Requested duration in seconds." },
|
|
570
575
|
video_url: { type: "string", description: "mirelo-sfx-2.0 only: an http(s) video to score. Set duration to its length — duration is what bills." },
|
|
571
576
|
format: { type: "string", description: 'e.g. "mp3" or "wav".' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ottoport",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.2",
|
|
4
4
|
"description": "Claude Code plugin, CLI and MCP server for OttoPort — one OpenAI-compatible API for every LLM, image, video, and speech model.",
|
|
5
5
|
"homepage": "https://ottoport.ai",
|
|
6
6
|
"repository": {
|
package/skills/ottoport/SKILL.md
CHANGED
|
@@ -89,9 +89,10 @@ sensible default.
|
|
|
89
89
|
| --- | --- | --- |
|
|
90
90
|
| chat | `claude-sonnet-5` | `claude-haiku-4.5` (cheap), `gpt-5.5`, `gemini-3.5-flash` |
|
|
91
91
|
| image | `gpt-image-2` | `nano-banana-2.1` (fast generation and edits), `nano-banana-pro` (high fidelity) |
|
|
92
|
+
| GIF or SVG file | `gpt-image-2.6`, with `output_format` on the image tool | `gpt-image-2.6-flare` (faster) |
|
|
92
93
|
| video | `kling-3.0` | `seedance-2.0-fast` (cheap), `veo-3.1` (with audio) |
|
|
93
94
|
| speech | `gpt-4o-mini-tts` | `eleven-v3` |
|
|
94
|
-
| music | `suno-
|
|
95
|
+
| music | `suno-v6` | `lyria-2`, `mirelo-sfx-2.0` (sound effects, or a soundtrack for a video) |
|
|
95
96
|
|
|
96
97
|
Never invent a model id. Call `ottoport_list_models` when unsure — the catalog
|
|
97
98
|
changes, and a wrong id is a failed billable call. Rates come back in credits (the unit the ledger
|