~/tools / Run a local LLM on your server / Ollama Stream Reader

Ollama Stream Reader — Join a streamed Ollama response and see its speed and stop reason

Paste a streamed response from Ollama, from /api/chat, /api/generate or the OpenAI-compatible /v1/chat/completions, and the tool joins the pieces back into the full text, the thinking and the tool calls. It shows why the model stopped, how fast it generated and processed the prompt, and whether the stream was cut off, and gives you the assistant message to add to the next request. Nothing leaves your browser.

How to save a stream with curl

-N turns off curl's buffering, and > stream.txt saves the stream to a file. Replace the model and the message with your own.

curl -sN http://localhost:11434/api/chat -d '{"model":"qwen2.5:7b","messages":[{"role":"user","content":"Hello"}]}' > stream.txt

curl -sN http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"qwen2.5:7b","stream":true,"stream_options":{"include_usage":true},"messages":[{"role":"user","content":"Hello"}]}' > stream.txt

Read as an /api/chat stream (one JSON object per line).

Summary

Model
qwen2.5:7b
Stop reason
stop
Chunks
7
Generated tokens
7
Generation speed
10.4 tokens/s
Prompt tokens
35
Prompt speed (tokens not in the cache)
64.1 tokens/s
Model load time
4.923 s
Total time
6.310 s
First to last chunk
0.675 s

Text

Hello, nice to meet.

Assistant message for the next request

Add this to messages, followed by the results of the tool calls, if any.

{
  "role": "assistant",
  "content": "Hello, nice to meet."
}

eval_count also counts the tokens of tool calls, which are not streamed as text. In our test, one tool call came in a single chunk with eval_count 20.

Ollama's documentation says that prompt_eval_duration covers only the prompt tokens that were not in the cache. The prompt speed here divides only those tokens. All durations are in nanoseconds; in the OpenAI form, timings are in whole milliseconds.

In the OpenAI-compatible form, token counts are sent only with stream_options.include_usage, in an extra chunk before data: [DONE]. If the stream is cut off, that chunk does not arrive.

Formats from Ollama's streaming and usage documentation and its source code (v0.40.15), checked against real streams from Ollama 0.40.11 on 2026-11-07. Ollama: Streaming

Everything is done in your browser. The tool connects to nothing.

Ollama streams its answers by default. /api/chat and /api/generate send one JSON object per line (newline-delimited JSON): each line carries a few characters of the answer, and the last line has done set to true and carries the token counts and durations, in nanoseconds. The OpenAI-compatible /v1/chat/completions streams only when stream is true. It then sends server-sent events: lines that start with data:, a separate chunk with an empty delta and the finish_reason, and data: [DONE] at the end. Token counts come only if the request sets stream_options.include_usage, in an extra chunk with an empty choices list, and Ollama adds a timings object to it. This tool reads all three forms, including the output of curl -i with its HTTP headers, joins content, thinking (reasoning in the OpenAI form) and tool calls, and lists what is wrong: a stream with no done line or no [DONE] was cut off; a line {"error": …} means that Ollama stopped with an error after it had started sending; done_reason length means that num_predict or max_tokens was reached. The generation speed is eval_count divided by eval_duration. For the prompt, Ollama's documentation says that prompt_eval_duration covers only the prompt tokens that were not in the cache, so the tool divides only those tokens by it. In the OpenAI form, Ollama's own timings.prompt_per_second divides all prompt tokens, cached ones included, by that time. In our test it reported 360.8 tokens per second for a prompt where 34 of 35 tokens came from the cache and the one remaining token took 97 ms. Tool calls in the OpenAI form can arrive in pieces that share an index, so the tool joins the arguments by index; Ollama itself sends each tool call whole, in one chunk. We checked the tool against real streams from Ollama 0.40.11 with qwen2.5:7b, and the formats against Ollama's documentation and source code.

The core logic of this tool is open source under the MIT License. github.com/seigo5555/toolkitbox-lib/src/ollama-stream.ts

Use Cases

  • See the whole answer of a streamed request you made with curl, instead of reading it one piece per line
  • Find out whether a stream was cut off, stopped at the length limit or ended with an error
  • Measure the generation and prompt speed of a model on your machine or server

Usage

  1. Run your request with curl -sN and save the output to a file, or copy what your program received.
  2. Paste the whole stream. The tool detects whether it comes from /api/chat, /api/generate or /v1/chat/completions.
  3. Read the problems and the numbers, and copy the text or the assistant message for the next request.

FAQ

Why are there no token counts for my /v1/chat/completions stream?

In the OpenAI-compatible form, the counts are sent only when the request sets stream_options to {"include_usage": true}. They then come in an extra chunk with an empty choices list, just before data: [DONE]. /api/chat and /api/generate always put them on the last line.

Why is the prompt speed so different from timings.prompt_per_second?

Ollama's documentation says that prompt_eval_duration covers only the prompt tokens that were not in the cache. Ollama's timings.prompt_per_second divides all prompt tokens, cached ones included, by that time, so it looks much faster when the cache was used. The tool divides only the tokens that were not in the cache.

The model called a tool but eval_count is 20. Where are those tokens?

The text of a tool call is not streamed as content; Ollama turns it into tool_calls and sends it in one chunk. The tokens are still generated and counted. In our test, one tool call with one argument came in a single chunk with eval_count 20.

Why does /api/chat say stop when the model called a tool?

/api/chat keeps done_reason as stop. The OpenAI-compatible endpoint changes stop to tool_calls in finish_reason when a tool call was sent.

What should I do with the assistant message?

Ollama's documentation notes that you need to join the streamed pieces to keep the conversation history, which matters most for tool calls. Add the message to messages, add the result of each tool call as a message with the role tool, and send the next request.

Is my data sent anywhere?

No. The stream is read in your browser. The curl commands are only text for you to run.

Related articles

Related