@warlock.js/ai-ollama 5.30.0 → 5.32.0
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/CHANGELOG.md +20 -0
- package/cjs/index.cjs +113 -16
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +3 -5
- package/esm/config.type.d.mts.map +1 -1
- package/esm/embedder.mjs.map +1 -1
- package/esm/index.d.mts +2 -1
- package/esm/model.mjs +43 -15
- package/esm/model.mjs.map +1 -1
- package/esm/provider-options.d.mts +8 -0
- package/esm/provider-options.d.mts.map +1 -0
- package/esm/provider-options.mjs +36 -0
- package/esm/provider-options.mjs.map +1 -0
- package/esm/sdk.d.mts +1 -3
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +6 -1
- package/esm/sdk.mjs.map +1 -1
- package/esm/utils/call-signal.mjs +40 -0
- package/esm/utils/call-signal.mjs.map +1 -0
- package/esm/utils/index.mjs +2 -1
- package/esm/utils/to-ollama-tools.mjs.map +1 -1
- package/llms-full.txt +69 -21
- package/llms.txt +1 -1
- package/package.json +3 -3
- package/skills/setup-ollama/SKILL.md +69 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-ollama
|
|
3
|
-
description: 'Wire @warlock.js/ai-ollama — new OllamaSDK({host?, headers?}) for local / self-hosted Ollama via the official ollama client (not OpenAI-compat). chat + embed, daemon-down error handling. .model({name, vision?, reasoning?}) with cost-truth capabilities — reasoning inferred from thinking-model tags (deepseek-r1/qwq/qwen3/gpt-oss…), promptCaching/audio/pdf honestly false; options.reasoning → Ollama native `think` flag; usage reasoningTokens/cachedTokens stay undefined (none reported). Triggers: `OllamaSDK`, `ollama.model`, `ollama.embedder`, `embedder.embedMany`, `ollama.count`, `host`, `headers`, `reasoning`, `think`, thinking models, `deepseek-r1`, `qwq`, `qwen3`, `gpt-oss`; "use ollama with warlock", "run llama3 locally", "self-hosted llama", "ollama reasoning / thinking models", "deepseek-r1 with warlock"; typical import `import { OllamaSDK } from "@warlock.js/ai-ollama"`. Skip: agent loop — the `run-ai-agent` topic of the `warlock-js-ai` skill; provider choice — the `pick-ai-provider` topic of the `warlock-js-ai` skill; embeddings core — the `embed-text` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`; raw `ollama` npm, Vercel `@ai-sdk/ollama`; OpenAI-compat gateway via `@warlock.js/ai-openai` `baseURL`.'
|
|
3
|
+
description: 'Wire @warlock.js/ai-ollama — new OllamaSDK({host?, headers?}) for local / self-hosted Ollama via the official ollama client (not OpenAI-compat). chat + embed, daemon-down error handling. .model({name, vision?, reasoning?}) with cost-truth capabilities — reasoning inferred from thinking-model tags (deepseek-r1/qwq/qwen3/gpt-oss…), promptCaching/audio/pdf honestly false; options.reasoning → Ollama native `think` flag; usage reasoningTokens/cachedTokens stay undefined (none reported). Triggers: `providerOptions`, `OllamaCallOptions`, `countTokens`, `OllamaSDK`, `ollama.model`, `ollama.embedder`, `embedder.embedMany`, `ollama.count`, `host`, `headers`, `reasoning`, `think`, thinking models, `streamChunks`, `message.thinking`, `deepseek-r1`, `qwq`, `qwen3`, `gpt-oss`; "use ollama with warlock", "run llama3 locally", "self-hosted llama", "ollama reasoning / thinking models", "deepseek-r1 with warlock"; typical import `import { OllamaSDK } from "@warlock.js/ai-ollama"`. Skip: agent loop — the `run-ai-agent` topic of the `warlock-js-ai` skill; provider choice — the `pick-ai-provider` topic of the `warlock-js-ai` skill; embeddings core — the `embed-text` topic of the `warlock-js-ai` skill; siblings `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-google`; raw `ollama` npm, Vercel `@ai-sdk/ollama`; OpenAI-compat gateway via `@warlock.js/ai-openai` `baseURL`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-ollama`
|
|
@@ -12,9 +12,9 @@ Provider adapter that turns a local (or self-hosted) Ollama server into a vendor
|
|
|
12
12
|
```ts
|
|
13
13
|
import { OllamaSDK } from "@warlock.js/ai-ollama";
|
|
14
14
|
|
|
15
|
-
const ollama = new OllamaSDK();
|
|
15
|
+
const ollama = new OllamaSDK(); // local default host
|
|
16
16
|
const remote = new OllamaSDK({ host: "http://gpu-box.internal:11434" });
|
|
17
|
-
const gated
|
|
17
|
+
const gated = new OllamaSDK({
|
|
18
18
|
host: "https://ollama.internal",
|
|
19
19
|
headers: { Authorization: `Bearer ${process.env.OLLAMA_TOKEN}` },
|
|
20
20
|
});
|
|
@@ -25,20 +25,20 @@ const gated = new OllamaSDK({
|
|
|
25
25
|
## Producing a model
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
ollama.model({ name: "llama3.1" })
|
|
29
|
-
ollama.model({ name: "qwen2.5:14b", temperature: 0.2 })
|
|
30
|
-
ollama.model({ name: "llama3.2-vision", maxTokens: 1024 })
|
|
28
|
+
ollama.model({ name: "llama3.1" });
|
|
29
|
+
ollama.model({ name: "qwen2.5:14b", temperature: 0.2 });
|
|
30
|
+
ollama.model({ name: "llama3.2-vision", maxTokens: 1024 });
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
## Capabilities — what's auto-set
|
|
34
34
|
|
|
35
|
-
| Flag
|
|
36
|
-
|
|
|
37
|
-
| `structuredOutput` | `true` (via Ollama's native `format` JSON-schema field)
|
|
38
|
-
| `vision`
|
|
39
|
-
| `reasoning`
|
|
40
|
-
| `promptCaching`
|
|
41
|
-
| `audio` / `pdf`
|
|
35
|
+
| Flag | Default |
|
|
36
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `structuredOutput` | `true` (via Ollama's native `format` JSON-schema field) |
|
|
38
|
+
| `vision` | Inferred from model tag substring. `true` for `llava`, `bakllava`, `*-vision`, `moondream`, `minicpm-v`, `qwen2-vl`, `qwen2.5-vl`, `llama4`, `gemma3`; `false` otherwise. |
|
|
39
|
+
| `reasoning` | Inferred from model tag substring. `true` for `deepseek-r1`, `qwq`, `qwen3`, `magistral`, `phi4-reasoning`, `phi4-mini-reasoning`, `cogito`, `smallthinker`, `exaone-deep`, `gpt-oss`; `false` otherwise. |
|
|
40
|
+
| `promptCaching` | `false` — Ollama has no provider-side prompt cache. |
|
|
41
|
+
| `audio` / `pdf` | `false` — the Ollama chat API takes no audio / PDF content parts. |
|
|
42
42
|
|
|
43
43
|
Explicit config always wins (`vision`, `structuredOutput`, `reasoning` overrides on `ollama.model({ … })`).
|
|
44
44
|
|
|
@@ -47,9 +47,9 @@ Explicit config always wins (`vision`, `structuredOutput`, `reasoning` overrides
|
|
|
47
47
|
For thinking-capable families the adapter maps `ModelCallOptions.reasoning` onto Ollama's `think` request flag (`boolean | 'low' | 'medium' | 'high'`):
|
|
48
48
|
|
|
49
49
|
```ts
|
|
50
|
-
ollama.model({ name: "deepseek-r1:7b" })
|
|
51
|
-
await model.complete(messages, { reasoning: { effort: "high" } });
|
|
52
|
-
await model.complete(messages, { reasoning: { maxTokens: 2048 } });
|
|
50
|
+
ollama.model({ name: "deepseek-r1:7b" });
|
|
51
|
+
await model.complete(messages, { reasoning: { effort: "high" } }); // → chat({ think: "high" })
|
|
52
|
+
await model.complete(messages, { reasoning: { maxTokens: 2048 } }); // → chat({ think: true })
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
- `reasoning.effort` (`low` / `medium` / `high`) passes straight through to `think`.
|
|
@@ -83,7 +83,17 @@ A multipart user message collapses to a single `content` string + an `images` ar
|
|
|
83
83
|
|
|
84
84
|
`model.stream()` drains `chat({ stream: true })` (an `AbortableAsyncIterator`). Each chunk's `message.content` → `{ type: "delta" }`; `message.tool_calls` are emitted as `{ type: "tool-call" }` **fully formed**. Terminal `{ type: "done", finishReason, usage }` — usage from the final (`done: true`) chunk's `prompt_eval_count` / `eval_count`.
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
Opt-in (`options.streamChunks`, set by `agent.stream()`): `{ type: "reasoning", delta }` per `message.thinking` piece when `think` is on:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
for await (const chunk of model.stream(messages, { reasoning: { effort: "high" }, streamChunks: { reasoning: true } })) {
|
|
90
|
+
if (chunk.type === "reasoning") process.stderr.write(chunk.delta);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Ollama's chat API has no built-in tools: an `ai.providerTool()` for another provider is left out with a warning.
|
|
95
|
+
|
|
96
|
+
**`options.signal` is honored** on `stream()` and `complete()`: a pre-aborted signal rejects without sending, and aborting mid-call cancels the HTTP request. The `ollama` client has no per-request signal, so `OllamaSDK` wraps its `fetch` (yours, when you pass `fetch`) to apply each call's signal from async context; the stream iterator's `abort()` is called too.
|
|
87
97
|
|
|
88
98
|
## Finish-reason mapping
|
|
89
99
|
|
|
@@ -94,7 +104,7 @@ A multipart user message collapses to a single `content` string + an `images` ar
|
|
|
94
104
|
```ts
|
|
95
105
|
const embedder = ollama.embedder({ name: "nomic-embed-text" });
|
|
96
106
|
const { vector } = await embedder.embed("Hello world");
|
|
97
|
-
const { vectors } = await embedder.embedMany(["a", "b"]);
|
|
107
|
+
const { vectors } = await embedder.embedMany(["a", "b"]); // single batched call
|
|
98
108
|
const truncated = ollama.embedder({ name: "mxbai-embed-large", dimensions: 512 });
|
|
99
109
|
```
|
|
100
110
|
|
|
@@ -116,14 +126,52 @@ Wrapped into the typed `@warlock.js/ai` `AIError` hierarchy. The `ollama` client
|
|
|
116
126
|
## Token counting & usage (cost-truth)
|
|
117
127
|
|
|
118
128
|
```ts
|
|
119
|
-
await ollama.count("some text")
|
|
129
|
+
await ollama.count("some text"); // approximate heuristic, offline
|
|
120
130
|
```
|
|
121
131
|
|
|
122
132
|
Per-call `Usage` comes from the chat response's `prompt_eval_count` (→ `input`) and `eval_count` (→ `output`); `total` is their sum. The adapter reports usage **truthfully** — it never fabricates a field Ollama doesn't return:
|
|
123
133
|
|
|
124
134
|
- `cachedTokens` / `cacheWriteTokens` — **always undefined**. Ollama has no provider prompt cache, so there is no cache-hit or cache-write accounting (honest absence, not a false `0`).
|
|
125
|
-
- `reasoningTokens` — **always undefined**. Reasoning models emit their thinking as the `message.thinking`
|
|
126
|
-
- `cost` —
|
|
135
|
+
- `reasoningTokens` — **always undefined**. Reasoning models emit their thinking as the `message.thinking` _string_, but the wire format carries **no separate reasoning-token count** — those tokens are already folded into `eval_count`. The adapter does not estimate a count from the thinking text.
|
|
136
|
+
- `cost` — attached to each `complete()` / streaming `done` usage only when a `ModelPricing` is configured. The adapter ships no price table (a local model costs nothing per token), so it is usually undefined; set `pricing` for chargeback or a hosted Ollama endpoint.
|
|
137
|
+
- `inputIncludesCache` — left unset: with no cache counters there is nothing to include or exclude.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { totalCost } from "@warlock.js/ai";
|
|
141
|
+
import { OllamaSDK } from "@warlock.js/ai-ollama";
|
|
142
|
+
|
|
143
|
+
const ollama = new OllamaSDK({ pricing: { "llama3.2": { input: 0.05, output: 0.1 } } }); // internal chargeback rate
|
|
144
|
+
const { usage } = await ollama
|
|
145
|
+
.model({ name: "llama3.2" })
|
|
146
|
+
.complete([{ role: "user", content: "hi" }]);
|
|
147
|
+
console.log(totalCost(usage.cost));
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Provider body options
|
|
151
|
+
|
|
152
|
+
Native body fields merge after neutral options. When both values are plain
|
|
153
|
+
objects, their immediate keys merge and caller-provided keys win; untouched
|
|
154
|
+
neutral fields remain. Arrays, scalars and `null` replace the field. This merge
|
|
155
|
+
is one level deep: a nested object explicitly supplied by the caller replaces
|
|
156
|
+
that nested value.
|
|
157
|
+
|
|
158
|
+
`providerOptions.ollama.body` adds native chat request fields after neutral
|
|
159
|
+
options, for completion and streaming:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
await model.complete(messages, {
|
|
163
|
+
providerOptions: { ollama: { body: { keep_alive: "10m", options: { top_k: 4 } } } },
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The key stays `ollama` for custom provider labels. Other provider keys are
|
|
168
|
+
ignored. `OllamaCallOptions` is exported. `model`, `messages`, `tools` and `stream`
|
|
169
|
+
are protected; replacing them throws `InvalidRequestError`. Fields merge
|
|
170
|
+
shallowly: a provider `options` object replaces the generated inference options,
|
|
171
|
+
so include any neutral sampling settings you want to retain in that object.
|
|
172
|
+
|
|
173
|
+
Ollama's chat transport has no native preflight token-count endpoint, so its
|
|
174
|
+
model has no `countTokens` method. `sdk.count(text)` remains an offline estimate.
|
|
127
175
|
|
|
128
176
|
## When NOT to use this skill
|
|
129
177
|
|