Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion apps/web/docs/commands.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,22 @@ Models are fetched live from the AI Gateway.

Requests that exceed the per-command timeout are aborted automatically:

| Command | Timeout |
| Command | Default timeout |
| --- | --- |
| `text` | 120 seconds |
| `image` | 120 seconds |
| `video` | 300 seconds |

Video generation uses a longer timeout because models typically need more processing time.

Override the default with `--timeout <seconds>`. Useful for complex prompts where the default is too tight:

```bash
ai image "complex sprite atlas with 72 cells..." --timeout 600
ai text "long structured response..." --timeout 300
ai video "extended scene..." --timeout 900
```

## Exit codes

| Code | Meaning |
Expand Down
10 changes: 8 additions & 2 deletions apps/web/docs/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ Add the export to your shell profile (`~/.zshrc`, `~/.bashrc`) to persist across

Requests are aborted if they exceed the per-command timeout:

| Command | Timeout |
| Command | Default timeout |
| --- | --- |
| `text` | 120 seconds |
| `image` | 120 seconds |
| `video` | 300 seconds |

If you're consistently hitting timeouts, try a faster model variant (e.g. `bytedance/seedance-2.0-fast` instead of `bytedance/seedance-2.0`).
Two ways to handle them:

1. Bump the timeout per command with `--timeout <seconds>`:
```bash
ai image "complex sprite atlas..." --timeout 600
```
2. Try a faster model variant (e.g. `bytedance/seedance-2.0-fast` instead of `bytedance/seedance-2.0`).

## `--quality` / `--style` warning

Expand Down
9 changes: 8 additions & 1 deletion packages/ai-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,19 @@ The `-m` flag always takes priority over `AI_CLI_*_MODEL` env vars. The `-o` fla

Requests that exceed the timeout are aborted automatically:

| Command | Timeout |
| Command | Default timeout |
|---|---|
| `text` | 120 seconds |
| `image` | 120 seconds |
| `video` | 300 seconds |

Override with `--timeout <seconds>` per command. Useful for complex prompts (large images, long sprite atlases) where the default is too tight:

```bash
ai image "complex sprite atlas..." --timeout 600
ai video "longer scene..." --timeout 900
```

### Exit Codes

| Code | Meaning |
Expand Down
11 changes: 10 additions & 1 deletion packages/ai-cli/src/commands/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ImageOptions {
json?: boolean;
concurrency?: string;
preview?: boolean;
timeout?: string;
}

export function registerImageCommand(program: Command) {
Expand Down Expand Up @@ -48,6 +49,10 @@ export function registerImageCommand(program: Command) {
"-p, --concurrency <n>",
`Max parallel generations (default: ${DEFAULT_CONCURRENCY})`
)
.option(
"--timeout <seconds>",
`Per-request timeout in seconds (default: ${DEFAULT_TIMEOUT_MS / 1000})`
)
.action(async (rawPrompt: string | undefined, opts: ImageOptions) => {
const prompt = rawPrompt?.trim() || undefined;
const stdin = await readStdin();
Expand Down Expand Up @@ -88,10 +93,14 @@ export function registerImageCommand(program: Command) {

const jobs = buildJobs(models, countPerModel);

const timeoutMs = opts.timeout
? parsePositiveInt(opts.timeout, "timeout") * 1000
: DEFAULT_TIMEOUT_MS;

const { total, failed } = await runJobs(
jobs,
async (modelId) => {
const abort = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
const abort = AbortSignal.timeout(timeoutMs);

if (gatewayModels.languageImageModelIds.has(modelId)) {
const messageContent: Array<
Expand Down
11 changes: 10 additions & 1 deletion packages/ai-cli/src/commands/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface TextOptions {
concurrency?: string;
quiet?: boolean;
json?: boolean;
timeout?: string;
}

function resolveFormat(fmt?: string): OutputFormat {
Expand Down Expand Up @@ -50,6 +51,10 @@ export function registerTextCommand(program: Command) {
.option("-t, --temperature <n>", "Temperature (0-2)")
.option("-q, --quiet", "Suppress progress output")
.option("--json", "Output metadata as JSON")
.option(
"--timeout <seconds>",
`Per-request timeout in seconds (default: ${DEFAULT_TIMEOUT_MS / 1000})`
)
.action(async (rawPrompt: string | undefined, opts: TextOptions) => {
const prompt = rawPrompt?.trim() || undefined;
const stdin = await readStdin();
Expand Down Expand Up @@ -83,10 +88,14 @@ export function registerTextCommand(program: Command) {

const jobs = buildJobs(models, countPerModel);

const timeoutMs = opts.timeout
? parsePositiveInt(opts.timeout, "timeout") * 1000
: DEFAULT_TIMEOUT_MS;

const { total, failed } = await runJobs(
jobs,
async (modelId) => {
const abort = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
const abort = AbortSignal.timeout(timeoutMs);
const result = await generateText({
headers: {
"http-referer": "https://github.com/vercel-labs/ai-cli",
Expand Down
11 changes: 10 additions & 1 deletion packages/ai-cli/src/commands/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface VideoOptions {
json?: boolean;
concurrency?: string;
preview?: boolean;
timeout?: string;
}

export function registerVideoCommand(program: Command) {
Expand All @@ -48,6 +49,10 @@ export function registerVideoCommand(program: Command) {
"-p, --concurrency <n>",
`Max parallel generations (default: ${DEFAULT_CONCURRENCY})`
)
.option(
"--timeout <seconds>",
`Per-request timeout in seconds (default: ${DEFAULT_TIMEOUT_MS / 1000})`
)
.action(async (rawPrompt: string | undefined, opts: VideoOptions) => {
const prompt = rawPrompt?.trim() || undefined;
const stdin = await readStdin();
Expand Down Expand Up @@ -79,10 +84,14 @@ export function registerVideoCommand(program: Command) {

const jobs = buildJobs(models, countPerModel);

const timeoutMs = opts.timeout
? parsePositiveInt(opts.timeout, "timeout") * 1000
: DEFAULT_TIMEOUT_MS;

const { total, failed } = await runJobs(
jobs,
async (modelId) => {
const abort = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
const abort = AbortSignal.timeout(timeoutMs);
const result = await generateVideo({
headers: {
"http-referer": "https://github.com/vercel-labs/ai-cli",
Expand Down