Skip to content

feat: stream ai text output as tokens arrive#43

Open
tmchow wants to merge 2 commits into
vercel-labs:mainfrom
tmchow:feat/streaming-text-output
Open

feat: stream ai text output as tokens arrive#43
tmchow wants to merge 2 commits into
vercel-labs:mainfrom
tmchow:feat/streaming-text-output

Conversation

@tmchow

@tmchow tmchow commented May 1, 2026

Copy link
Copy Markdown

Summary

ai text currently waits for the full response from generateText before printing. On a one-sentence prompt that's a 1s blank terminal so not a big deal, but on a long-form generation it's much worse.

AI SDK 6 already ships streamText. This PR uses it for the simple single-model interactive case so tokens appear in the terminal as they arrive.

Why this matters

The "agent-native CLI" tagline implies responsive feedback in interactive terminals. Buffered text feels broken on long prompts even when it's fast. Every comparable tool streams: MMX-CLI has --stream, aichat is built around streaming, Charm's mods streams by default. Streaming is also strictly cheaper for the user, since they can ctrl-C as soon as a response is going off track instead of paying for the full generation.

Demo

Live timing breakdown from a 5-sentence prompt against openai/gpt-4.1-mini (captured via PTY so stdout is treated as a TTY). Thought it'd be helpful to see the breakdown and not just the gif.

t= 1.07s  +  2b  'In'
t= 1.13s  +  4b  ''s'
t= 1.39s  + 10b  ' recursive'
t= 1.45s  +  4b  ' own'
t= 1.51s  +  4b  ' its'
t= 1.56s  +  6b  ' frame'
t= 1.72s  +  8b  ' silence'
...
t= 2.77s  + 48b  '\r\nGenerated text with openai/gpt-4.1-mini (2s)\r\n'

Total chunks:  154
Total bytes:   830
First byte at: 1.07s
Last byte at:  2.77s
Span:          1.70s

154 small chunks over 1.7 seconds, instead of one ~2-second blank-then-dump.

ai-text-streaming

Testing

bun run typecheck   # passes
bun test            # 73 tests, 0 fail (3 new in text.test.ts)
bun run check       # 17 pre-existing format issues outside this change (was 19 on upstream/main)

Manual: streaming verified live against openai/gpt-4.1-mini and anthropic/claude-3.5-haiku via AI Gateway. --json, multi-model, and piped paths confirmed unchanged via PTY-instrumented runs.

Compound Engineering

tmchow added 2 commits May 1, 2026 14:54
Switches single-model interactive `ai text` runs to `streamText` so tokens
appear in the terminal as they're generated. The fast path is gated on
`models.length === 1 && countPerModel === 1 && !output && !AI_CLI_OUTPUT_DIR
&& !json && process.stdout.isTTY` -- multi-model, capture, --json, and piped
stdout all stay on the existing `generateText` + `runJobs` path.

The progress line moves to stderr in the streaming path so it doesn't
pollute the streamed stdout. `-q` suppresses it (matching existing behavior).

README and skills/ai-cli/SKILL.md updated. Tests cover both the streaming
fast path and the buffered --json fallback.
streamText's textStream only yields text deltas; provider errors are
emitted as error parts that the for-await loop silently ignores. Without
this, a failed generation prints "Generated text..." and exits 0.

Awaiting result.finishReason after the loop propagates any swallowed
error as an exception, which the top-level commander catch handles
(prints "Error: ..." to stderr, exits 1).

Adds a regression test that mocks streamText with a rejecting
finishReason and asserts the error surfaces.
@vercel

vercel Bot commented May 1, 2026

Copy link
Copy Markdown

@tmchow is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@tmchow

tmchow commented May 23, 2026

Copy link
Copy Markdown
Author

@ctate any feedback on this? Happy to adjust it if I should approach another way. Lmk!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant