Ollama
aimock implements Ollama's native /api/chat, /api/generate, and
/api/tags endpoints with NDJSON streaming, matching Ollama's wire format
including its key differences from OpenAI.
To send events or fields aimock does not model yet, use a
raw passthrough fixture with
wire: "ollama" for /api/chat or
wire: "ollama-generate" for /api/generate.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/chat | Chat completions (multi-turn, tool calls) |
| POST | /api/generate | Single-prompt text generation (no tool calls) |
| POST | /api/embed | Current embeddings API: input text or batch, embeddings matrix |
| POST | /api/embeddings | Legacy embeddings API: prompt text, single embedding vector |
| GET | /api/tags | List available models (derived from fixtures) |
If the client hangs up before the reply is complete, aimock stops delivery and journals
the request with interruptReason: "client aborted" (see
Client Disconnects). To delay
"stream": false replies, set
nonStreamingTimingAllProviders: true with a streamingProfile or
recordedTimings (see
All Providers).
Embeddings
Use the Ollama SDK's embed({ model, input }) with a string or array of
strings. /api/embed returns one vector per input in embeddings,
in input order. Unmatched inputs get separate, deterministic vectors;
dimensions sets their width (1–100,000, default 1,536). An embedding fixture
repeats its supplied vector for each input; match inputText against the
inputs joined by spaces. Recorded batches keep every vector and the upstream JSON metadata
for replay.
New /api/embed recordings also store match.embeddingRequest with
the operation, exact input shape and requested dimensions, plus match.model.
A batch such as ["first", "second"] therefore does not match the string
"first second", a different width, or another embedding operation. Re-record
older captures to add these keys. New legacy Ollama and OpenAI embedding recordings use
the same operation-specific match field. Handwritten embedding fixtures without
embeddingRequest keep their broad matching behavior.
The legacy SDK method embeddings({ model, prompt }) still uses
/api/embeddings and returns a single embedding array.
Key Differences from OpenAI
-
Defaults to streaming. Ollama treats
streamastruewhen absent — the opposite of OpenAI. Set"stream": falseexplicitly for non-streaming responses. - NDJSON, not SSE. Streaming uses newline-delimited JSON, not Server-Sent Events.
-
Tool call arguments are objects. Unlike OpenAI which sends stringified
JSON, Ollama sends parsed objects in
arguments. - Tool call IDs. This aimock adapter does not preserve native tool-call IDs; native Ollama can emit them.
-
Duration metadata. Responses include
done_reason,total_duration,eval_count, etc. on the final chunk. aimock sends zeroed values.
Quick Start
import { LLMock } from "@copilotkit/aimock";
const mock = new LLMock();
mock.onMessage("hello", { content: "Hi from Ollama!" });
await mock.start();
// Point the Ollama SDK at aimock
const res = await fetch(`${mock.url}/api/chat`, {
method: "POST",
body: JSON.stringify({
model: "llama3",
messages: [{ role: "user", content: "hello" }],
stream: false,
}),
});
Streaming Response Format (NDJSON)
When stream is true (the default), each line is a complete JSON
object separated by newlines:
{"model":"llama3","message":{"role":"assistant","content":"Hi"},"done":false}
{"model":"llama3","message":{"role":"assistant","content":" there"},"done":false}
{"model":"llama3","message":{"role":"assistant","content":""},"done":true,"done_reason":"stop","total_duration":0,"load_duration":0,"prompt_eval_count":0,"prompt_eval_duration":0,"eval_count":0,"eval_duration":0}
Non-Streaming Response
{
"model": "llama3",
"message": { "role": "assistant", "content": "Hi there!" },
"done": true,
"done_reason": "stop",
"total_duration": 0,
"load_duration": 0,
"prompt_eval_count": 0,
"prompt_eval_duration": 0,
"eval_count": 0,
"eval_duration": 0
}
Tool Calls
Tool calls in Ollama send arguments as a parsed object (not a JSON string).
aimock automatically converts fixture arguments strings into objects for the
Ollama wire format.
{
"fixtures": [
{
"match": { "userMessage": "weather" },
"response": {
"toolCalls": [
{ "name": "get_weather", "arguments": { "city": "NYC" } }
]
}
}
]
}
The Ollama streaming response wraps tool calls in a single chunk:
{"model":"llama3","message":{"role":"assistant","content":"","tool_calls":[{"function":{"name":"get_weather","arguments":{"city":"NYC"}}}]},"done":false}
{"model":"llama3","message":{"role":"assistant","content":""},"done":true,"done_reason":"stop","total_duration":0,"load_duration":0,"prompt_eval_count":0,"prompt_eval_duration":0,"eval_count":0,"eval_duration":0}
/api/generate Endpoint
The /api/generate endpoint takes a prompt string instead of a
messages array. The prompt is internally converted to a single user message
for fixture matching. Only text responses are supported (no tool calls).
{
"model": "llama3",
"prompt": "Tell me a joke",
"stream": false
}
{
"model": "llama3",
"created_at": "2025-01-01T00:00:00.000Z",
"response": "Why did the chicken cross the road?",
"done": true,
"done_reason": "stop",
"total_duration": 0,
"load_duration": 0,
"prompt_eval_count": 0,
"prompt_eval_duration": 0,
"eval_count": 0,
"eval_duration": 0,
"context": []
}
/api/tags Endpoint
GET /api/tags returns a list of available models, derived from the
model fields across all loaded fixtures. This lets Ollama clients discover
which models the mock server supports.
Request Translation
aimock internally translates Ollama requests to a unified
ChatCompletionRequest format for fixture matching. The
ollamaToCompletionRequest() function maps Ollama's
options.temperature to temperature and
options.num_predict to max_tokens, so the same fixtures work
across all providers.
Ordered blocks (tool-first)
A combined content + toolCalls fixture accepts an optional
blocks array to control stream order — see
Ordered blocks. Ollama support is
partial: a tool_calls chunk can be emitted before content on
the NDJSON wire, but some clients reassemble positionally, so tool-first is best-effort on
this provider.