ai-sdk-ollama 0.2.0 โ†’ 0.4.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 CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **Reasoning Support**: Added support for reasoning (chain-of-thought) output
8
+ - ๐Ÿง  **Reasoning Content**: Models that support reasoning can now output their thinking process
9
+ - ๐Ÿ“ **Content Types**: Support for `LanguageModelV2Reasoning` content type in both non-streaming and streaming responses
10
+ - ๐Ÿ”„ **Streaming Support**: Full streaming support with `reasoning-start`, `reasoning-delta`, and `reasoning-end` events
11
+ - โš™๏ธ **Configurable**: Enable reasoning with `{ reasoning: true }` setting
12
+ - ๐Ÿงช **Comprehensive Testing**: Added unit tests for reasoning functionality
13
+ - ๐Ÿ“š **Documentation**: Updated README and examples with reasoning usage
14
+ - ๐ŸŽฏ **Backward Compatible**: Reasoning is disabled by default, existing code continues to work
15
+
16
+ ### Technical Improvements
17
+
18
+ - Added `reasoning` setting to `OllamaChatSettings` interface
19
+ - Enhanced `doGenerate` method to handle `thinking` field from Ollama responses
20
+ - Enhanced `doStream` method to emit reasoning stream parts
21
+ - Added reasoning support to content conversion logic
22
+ - Updated type definitions to include reasoning content types
23
+
24
+ ## 0.3.0
25
+
26
+ ### Minor Changes
27
+
28
+ - **Auto-Structured Outputs**: Enhanced structured outputs with intelligent auto-detection
29
+ - ๐ŸŽฏ **Smart Auto-Detection**: Automatically enables structured outputs when JSON schema is provided
30
+ - ๐Ÿ”ง **Backward Compatibility**: Explicit `structuredOutputs: true/false` settings are still respected
31
+ - โš ๏ธ **User-Friendly Warnings**: Clear warnings when auto-enabling structured outputs
32
+ - ๐Ÿ“š **Enhanced Documentation**: Updated examples and README with auto-detection guidance
33
+ - ๐Ÿงช **Comprehensive Testing**: Added integration tests for auto-detection scenarios
34
+ - ๐Ÿ› ๏ธ **Improved Developer Experience**: No need to manually set `structuredOutputs: true` for object generation
35
+
36
+ ### Technical Improvements
37
+
38
+ - Enhanced `shouldEnableStructuredOutputs()` method for intelligent auto-detection
39
+ - Improved schema validation and error handling
40
+ - Updated README with auto-detection examples and best practices
41
+ - Added comprehensive integration tests for edge cases
42
+ - Streamlined configuration for common use cases
43
+
3
44
  ## 0.2.0
4
45
 
5
46
  ### Minor Changes
@@ -79,7 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
79
120
 
80
121
  ### Supported Models
81
122
 
82
- - **Chat Models**: llama3.2, llama3.1, mistral, phi4-mini, qwen2.5, codellama, and all Ollama chat models
123
+ - **Chat Models**: llama3.2, mistral, phi4-mini, qwen2.5, codellama, and all Ollama chat models
83
124
  - **Vision Models**: llava, bakllava, llama3.2-vision, minicpm-v
84
125
  - **Embedding Models**: nomic-embed-text, all-minilm, mxbai-embed-large, and all Ollama embedding models
85
126
 
package/README.md CHANGED
@@ -19,12 +19,14 @@ A Vercel AI SDK v5+ provider for Ollama built on the official `ollama` package.
19
19
  - [Cross Provider Compatibility](#cross-provider-compatibility)
20
20
  - [Native Ollama Power](#native-ollama-power)
21
21
  - [Tool Calling Support](#tool-calling-support)
22
- - [Smart Model Intelligence](#smart-model-intelligence)
22
+ - [Simple and Predictable](#simple-and-predictable)
23
23
  - [Advanced Features](#advanced-features)
24
24
  - [Custom Ollama Instance](#custom-ollama-instance)
25
25
  - [Structured Output](#structured-output)
26
+ - [Auto-Detection of Structured Outputs](#auto-detection-of-structured-outputs)
26
27
  - [Common Issues](#common-issues)
27
28
  - [Supported Models](#supported-models)
29
+ - [Testing](#testing)
28
30
  - [Learn More](#learn-more)
29
31
  - [License](#license)
30
32
 
@@ -223,8 +225,9 @@ const { text } = await generateText({
223
225
  import { generateObject } from 'ai';
224
226
  import { z } from 'zod';
225
227
 
228
+ // Auto-detection: structuredOutputs is automatically enabled for object generation
226
229
  const { object } = await generateObject({
227
- model: ollama('llama3.2', { structuredOutputs: true }),
230
+ model: ollama('llama3.2'), // No need to set structuredOutputs: true
228
231
  schema: z.object({
229
232
  name: z.string(),
230
233
  age: z.number(),
@@ -235,8 +238,84 @@ const { object } = await generateObject({
235
238
 
236
239
  console.log(object);
237
240
  // { name: "Alice", age: 28, interests: ["reading", "hiking"] }
241
+
242
+ // Explicit setting still works
243
+ const { object: explicitObject } = await generateObject({
244
+ model: ollama('llama3.2', { structuredOutputs: true }), // Explicit
245
+ schema: z.object({
246
+ name: z.string(),
247
+ age: z.number(),
248
+ }),
249
+ prompt: 'Generate a person',
250
+ });
251
+ ```
252
+
253
+ ### Auto-Detection of Structured Outputs
254
+
255
+ The provider automatically detects when structured outputs are needed:
256
+
257
+ - **Object Generation**: `generateObject` and `streamObject` automatically enable `structuredOutputs: true`
258
+ - **Text Generation**: `generateText` and `streamText` require explicit `structuredOutputs: true` for JSON output
259
+ - **Backward Compatibility**: Explicit settings are respected, with warnings when overridden
260
+ - **No Breaking Changes**: Existing code continues to work as expected
261
+
262
+ ```typescript
263
+ // This works without explicit structuredOutputs: true
264
+ const { object } = await generateObject({
265
+ model: ollama('llama3.2'),
266
+ schema: z.object({ name: z.string() }),
267
+ prompt: 'Generate a name',
268
+ });
269
+
270
+ // This still requires explicit setting for JSON output
271
+ const { text } = await generateText({
272
+ model: ollama('llama3.2', { structuredOutputs: true }),
273
+ prompt: 'Generate JSON with a message field',
274
+ });
238
275
  ```
239
276
 
277
+ ### Reasoning Support
278
+
279
+ Some models like DeepSeek-R1 support reasoning (chain-of-thought) output. Enable this feature to see the model's thinking process:
280
+
281
+ ```typescript
282
+ // Enable reasoning for models that support it (e.g., deepseek-r1:7b)
283
+ const model = ollama('deepseek-r1:7b', { reasoning: true });
284
+
285
+ // Generate text with reasoning
286
+ const { text } = await generateText({
287
+ model,
288
+ prompt:
289
+ 'Solve: If I have 3 boxes, each with 4 smaller boxes, and each smaller box has 5 items, how many items total?',
290
+ });
291
+
292
+ console.log('Answer:', text);
293
+ // DeepSeek-R1 includes reasoning in the output with <think> tags:
294
+ // <think>
295
+ // First, I'll calculate the number of smaller boxes: 3 ร— 4 = 12
296
+ // Then, the total items: 12 ร— 5 = 60
297
+ // </think>
298
+ // You have 60 items in total.
299
+
300
+ // Compare with reasoning disabled
301
+ const modelNoReasoning = ollama('deepseek-r1:7b', { reasoning: false });
302
+ const { text: noReasoningText } = await generateText({
303
+ model: modelNoReasoning,
304
+ prompt: 'Calculate 3 ร— 4 ร— 5',
305
+ });
306
+ // Output: 60 (without showing the thinking process)
307
+ ```
308
+
309
+ **Recommended Reasoning Models**:
310
+
311
+ - `deepseek-r1:7b` - Balanced performance and reasoning capability (5GB)
312
+ - `deepseek-r1:1.5b` - Lightweight option (2.5GB)
313
+ - `deepseek-r1:8b` - Llama-based distilled version (5.5GB)
314
+
315
+ Install with: `ollama pull deepseek-r1:7b`
316
+
317
+ **Note**: The reasoning feature is model-dependent. Models without reasoning support will work normally without showing thinking process.
318
+
240
319
  ## Common Issues
241
320
 
242
321
  - **Make sure Ollama is running** - Run `ollama serve` before using the provider
@@ -250,9 +329,29 @@ console.log(object);
250
329
 
251
330
  Works with any model in your Ollama installation:
252
331
 
253
- - **Chat**: `llama3.2`, `llama3.1`, `mistral`, `phi4-mini`, `qwen2.5`, `codellama`
332
+ - **Chat**: `llama3.2`, `mistral`, `phi4-mini`, `qwen2.5`, `codellama`
254
333
  - **Vision**: `llava`, `bakllava`, `llama3.2-vision`, `minicpm-v`
255
334
  - **Embeddings**: `nomic-embed-text`, `all-minilm`, `mxbai-embed-large`
335
+ - **Reasoning**: `deepseek-r1:7b`, `deepseek-r1:1.5b`, `deepseek-r1:8b`
336
+
337
+ ## Testing
338
+
339
+ The project includes unit and integration tests:
340
+
341
+ ```bash
342
+ # Run unit tests only (fast, no external dependencies)
343
+ npm test
344
+
345
+ # Run all tests (unit + integration)
346
+ npm run test:all
347
+
348
+ # Run integration tests only (requires Ollama running)
349
+ npm run test:integration
350
+ ```
351
+
352
+ > **Note**: Integration tests may occasionally fail due to the non-deterministic nature of AI model outputs. This is expected behavior - the tests use loose assertions to account for LLM output variability. Some tests may also skip if required models aren't available locally.
353
+
354
+ For detailed testing information, see [Integration Tests Documentation](./src/integration-tests/README.md).
256
355
 
257
356
  ## Learn More
258
357
 
package/dist/index.cjs CHANGED
@@ -54,27 +54,43 @@ function convertToOllamaChatMessages(prompt) {
54
54
  const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
55
55
  const imageParts = message.content.filter(
56
56
  (part) => part.type === "file"
57
- ).filter((part) => part.mediaType.startsWith("image/")).map((part) => {
58
- if (part.data instanceof URL) {
59
- return part.data.href;
60
- } else if (typeof part.data === "string") {
61
- if (part.data.startsWith("data:")) {
62
- const base64Match = part.data.match(/data:[^;]+;base64,(.+)/);
57
+ ).filter((part) => {
58
+ return part.mediaType?.startsWith("image/") || false;
59
+ }).map((part) => {
60
+ const imageData = part.data;
61
+ if (imageData instanceof URL) {
62
+ if (imageData.protocol === "data:") {
63
+ const base64Match = imageData.href.match(
64
+ /data:[^;]+;base64,(.+)/
65
+ );
63
66
  if (base64Match) {
64
67
  return base64Match[1];
65
68
  }
69
+ return imageData.href;
66
70
  }
67
- return part.data;
68
- } else if (part.data instanceof Uint8Array) {
69
- return Buffer.from(part.data).toString("base64");
71
+ return imageData.href;
72
+ } else if (typeof imageData === "string") {
73
+ if (imageData.startsWith("data:")) {
74
+ const base64Match = imageData.match(/data:[^;]+;base64,(.+)/);
75
+ if (base64Match) {
76
+ return base64Match[1];
77
+ }
78
+ }
79
+ return imageData;
80
+ } else if (imageData instanceof Uint8Array) {
81
+ return Buffer.from(imageData).toString("base64");
70
82
  } else {
71
- return String(part.data);
83
+ console.warn(
84
+ `Unsupported image data type: ${typeof imageData}`
85
+ );
86
+ return null;
72
87
  }
73
- });
88
+ }).filter((img) => img !== null);
74
89
  messages.push({
75
90
  role: "user",
76
- content: textParts,
77
- images: imageParts.length > 0 ? imageParts.filter((img) => img !== void 0) : void 0
91
+ content: textParts || "",
92
+ // Ensure content is never undefined
93
+ images: imageParts.length > 0 ? imageParts : void 0
78
94
  });
79
95
  }
80
96
  break;
@@ -84,7 +100,9 @@ function convertToOllamaChatMessages(prompt) {
84
100
  if (typeof message.content === "string") {
85
101
  content = message.content;
86
102
  } else {
87
- content = message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
103
+ const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
104
+ const reasoningParts = message.content.filter((part) => part.type === "reasoning").map((part) => part.text).join("\n");
105
+ content = [textParts, reasoningParts].filter(Boolean).join("\n");
88
106
  const toolCalls = message.content.filter(
89
107
  (part) => part.type === "tool-call"
90
108
  );
@@ -98,20 +116,38 @@ ${toolCallText}` : toolCallText;
98
116
  }
99
117
  messages.push({
100
118
  role: "assistant",
101
- content
119
+ content: content || ""
120
+ // Ensure content is never undefined
102
121
  });
103
122
  break;
104
123
  }
105
124
  case "tool": {
106
- messages.push({
107
- role: "user",
108
- content: `[Tool Result]`
109
- });
125
+ if (typeof message.content === "string") {
126
+ messages.push({
127
+ role: "user",
128
+ // Ollama doesn't have native tool role, so we use user
129
+ content: `[Tool Result]: ${message.content}`
130
+ });
131
+ } else {
132
+ const toolResultParts = message.content.filter((part) => part.type === "tool-result").map((part) => {
133
+ if (part.output.type === "text") {
134
+ return part.output.value;
135
+ } else if (part.output.type === "json") {
136
+ return JSON.stringify(part.output.value);
137
+ }
138
+ return String(part.output.value);
139
+ }).join("\n");
140
+ messages.push({
141
+ role: "user",
142
+ content: `[Tool Result]: ${toolResultParts || ""}`
143
+ });
144
+ }
110
145
  break;
111
146
  }
112
147
  default: {
148
+ const role = message.role;
113
149
  throw new Error(
114
- `Unsupported message role: ${message.role}`
150
+ `Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`
115
151
  );
116
152
  }
117
153
  }
@@ -163,19 +199,50 @@ var OllamaChatLanguageModel = class {
163
199
  }
164
200
  specificationVersion = "v2";
165
201
  defaultObjectGenerationMode = "json";
166
- supportsImages = false;
202
+ supportsImages = true;
203
+ // โœ… Ollama supports images (URLs, files, base64)
167
204
  supportsVideoURLs = false;
205
+ // โŒ Not supported by Ollama API
168
206
  supportsAudioURLs = false;
207
+ // โŒ Not supported by Ollama API
169
208
  supportsVideoFile = false;
209
+ // โŒ Not supported by Ollama API
170
210
  supportsAudioFile = false;
211
+ // โŒ Not supported by Ollama API
171
212
  supportsImageFile = true;
172
- supportedUrls = {};
213
+ // โœ… Already correct
214
+ supportedUrls = {
215
+ // Support common image URL patterns
216
+ image: [
217
+ /^https?:\/\/.*\.(jpg|jpeg|png|gif|webp|bmp|svg)(\?.*)?$/i,
218
+ /^data:image\/[^;]+;base64,/i
219
+ // Data URLs
220
+ ]
221
+ };
173
222
  get provider() {
174
223
  return this.config.provider;
175
224
  }
176
225
  get supportsStructuredOutputs() {
177
226
  return this.settings.structuredOutputs ?? false;
178
227
  }
228
+ /**
229
+ * Check if structured outputs should be enabled based on the call options
230
+ * This is used internally to auto-detect when structured outputs are needed
231
+ */
232
+ shouldEnableStructuredOutputs(options) {
233
+ if (options.responseFormat?.type === "json" && options.responseFormat.schema) {
234
+ if (this.settings.structuredOutputs === false) {
235
+ console.warn(
236
+ "Ollama: structuredOutputs was set to false but auto-enabled for object generation. This ensures generateObject and streamObject work correctly."
237
+ );
238
+ }
239
+ return true;
240
+ }
241
+ if (this.settings.structuredOutputs !== void 0) {
242
+ return this.settings.structuredOutputs;
243
+ }
244
+ return false;
245
+ }
179
246
  getCallOptions(options) {
180
247
  const {
181
248
  prompt,
@@ -191,7 +258,8 @@ var OllamaChatLanguageModel = class {
191
258
  tools
192
259
  } = options;
193
260
  const warnings = [];
194
- if (responseFormat?.type === "json" && responseFormat.schema && !this.supportsStructuredOutputs) {
261
+ const needsStructuredOutputs = this.shouldEnableStructuredOutputs(options);
262
+ if (responseFormat?.type === "json" && responseFormat.schema && !needsStructuredOutputs) {
195
263
  throw new Error(
196
264
  "JSON schema is only supported when structuredOutputs is enabled"
197
265
  );
@@ -262,7 +330,7 @@ var OllamaChatLanguageModel = class {
262
330
  }
263
331
  let format;
264
332
  if (responseFormat?.type === "json") {
265
- format = "json";
333
+ format = responseFormat.schema && needsStructuredOutputs ? responseFormat.schema : "json";
266
334
  }
267
335
  const messages = convertToOllamaChatMessages(prompt);
268
336
  return {
@@ -292,7 +360,11 @@ var OllamaChatLanguageModel = class {
292
360
  });
293
361
  const text = response.message.content;
294
362
  const toolCalls = response.message.tool_calls;
363
+ const thinking = response.message.thinking;
295
364
  const content = [];
365
+ if (thinking && this.settings.reasoning) {
366
+ content.push({ type: "reasoning", text: thinking });
367
+ }
296
368
  if (text) {
297
369
  content.push({ type: "text", text });
298
370
  }
@@ -372,6 +444,7 @@ var OllamaChatLanguageModel = class {
372
444
  totalTokens: 0
373
445
  };
374
446
  let finishReason = "unknown";
447
+ const reasoningEnabled = this.settings.reasoning;
375
448
  const transformStream = new TransformStream({
376
449
  async transform(chunk, controller) {
377
450
  if (!chunk || typeof chunk !== "object") {
@@ -392,6 +465,21 @@ var OllamaChatLanguageModel = class {
392
465
  usage
393
466
  });
394
467
  } else {
468
+ if (chunk.message.thinking && reasoningEnabled) {
469
+ controller.enqueue({
470
+ type: "reasoning-start",
471
+ id: crypto.randomUUID()
472
+ });
473
+ controller.enqueue({
474
+ type: "reasoning-delta",
475
+ id: crypto.randomUUID(),
476
+ delta: chunk.message.thinking
477
+ });
478
+ controller.enqueue({
479
+ type: "reasoning-end",
480
+ id: crypto.randomUUID()
481
+ });
482
+ }
395
483
  if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
396
484
  for (const toolCall of chunk.message.tool_calls) {
397
485
  const toolInput = toolCall.function.arguments || {};
@@ -403,7 +491,8 @@ var OllamaChatLanguageModel = class {
403
491
  input: JSON.stringify(toolInput)
404
492
  });
405
493
  }
406
- } else if (chunk.message.content && typeof chunk.message.content === "string") {
494
+ }
495
+ if (chunk.message.content && typeof chunk.message.content === "string" && chunk.message.content.length > 0) {
407
496
  controller.enqueue({
408
497
  type: "text-delta",
409
498
  id: crypto.randomUUID(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/provider.ts","../src/utils/convert-to-ollama-messages.ts","../src/utils/map-ollama-finish-reason.ts","../src/utils/ollama-error.ts","../src/models/chat-language-model.ts","../src/models/embedding-model.ts"],"sourcesContent":["export {\n createOllama,\n ollama,\n type OllamaProvider,\n type OllamaProviderSettings,\n type OllamaChatSettings,\n type OllamaEmbeddingSettings,\n type OllamaProviderOptions,\n type OllamaChatProviderOptions,\n type OllamaEmbeddingProviderOptions,\n} from './provider';\n\nexport { OllamaChatLanguageModel } from './models/chat-language-model';\nexport type { OllamaChatConfig } from './models/chat-language-model';\nexport { OllamaEmbeddingModel } from './models/embedding-model';\nexport type { OllamaEmbeddingConfig } from './models/embedding-model';\nexport { OllamaError } from './utils/ollama-error';\nexport type { OllamaErrorData } from './utils/ollama-error';\n\n","import {\n LanguageModelV2,\n EmbeddingModelV2,\n ProviderV2,\n NoSuchModelError,\n} from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaChatLanguageModel } from './models/chat-language-model';\nimport { OllamaEmbeddingModel } from './models/embedding-model';\n\nexport interface OllamaProviderSettings {\n /**\n * Base URL for the Ollama API (defaults to http://127.0.0.1:11434)\n */\n baseURL?: string;\n\n /**\n * Custom headers for API requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\nexport interface OllamaProvider extends ProviderV2 {\n /**\n * Create a language model instance\n */\n (modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `chat` method\n */\n chat(modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `languageModel` method\n */\n languageModel(\n modelId: string,\n settings?: OllamaChatSettings,\n ): LanguageModelV2;\n\n /**\n * Create an embedding model instance\n */\n embedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbedding` method\n */\n textEmbedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbeddingModel` method\n */\n textEmbeddingModel(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n}\n\nexport interface OllamaChatSettings {\n /**\n * Enable structured output mode\n */\n structuredOutputs?: boolean;\n\n /**\n * Additional model parameters\n */\n options?: {\n num_ctx?: number;\n num_predict?: number;\n temperature?: number;\n top_k?: number;\n top_p?: number;\n min_p?: number;\n seed?: number;\n stop?: string[];\n num_keep?: number;\n typical_p?: number;\n repeat_last_n?: number;\n repeat_penalty?: number;\n presence_penalty?: number;\n frequency_penalty?: number;\n mirostat?: number;\n mirostat_tau?: number;\n mirostat_eta?: number;\n penalize_newline?: boolean;\n numa?: boolean;\n num_thread?: number;\n num_gpu?: number;\n main_gpu?: number;\n low_vram?: boolean;\n f16_kv?: boolean;\n vocab_only?: boolean;\n use_mmap?: boolean;\n use_mlock?: boolean;\n };\n}\n\nexport interface OllamaEmbeddingSettings {\n /**\n * Additional embedding parameters\n */\n options?: {\n num_thread?: number;\n };\n}\n\n/**\n * Options for configuring Ollama provider calls\n */\nexport interface OllamaProviderOptions {\n /**\n * Additional headers to include in requests\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Options for configuring Ollama chat model calls\n */\nexport interface OllamaChatProviderOptions extends OllamaProviderOptions {\n /**\n * Enable structured output mode for object generation\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Options for configuring Ollama embedding model calls\n */\nexport interface OllamaEmbeddingProviderOptions extends OllamaProviderOptions {\n /**\n * Maximum number of embeddings to process in a single call\n */\n maxEmbeddingsPerCall?: number;\n}\n\n/**\n * Create an Ollama provider instance\n */\nexport function createOllama(\n options: OllamaProviderSettings = {},\n): OllamaProvider {\n const client = new Ollama({\n host: options.baseURL,\n fetch: options.fetch,\n headers: options.headers,\n });\n\n const createChatModel = (\n modelId: string,\n settings: OllamaChatSettings = {},\n ) => {\n return new OllamaChatLanguageModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const createEmbeddingModel = (\n modelId: string,\n settings: OllamaEmbeddingSettings = {},\n ) => {\n return new OllamaEmbeddingModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const provider = function (modelId: string, settings?: OllamaChatSettings) {\n if (new.target) {\n throw new Error(\n 'The Ollama provider cannot be called with the new keyword.',\n );\n }\n return createChatModel(modelId, settings);\n };\n\n provider.chat = createChatModel;\n provider.languageModel = createChatModel;\n provider.embedding = createEmbeddingModel;\n provider.textEmbedding = createEmbeddingModel;\n provider.textEmbeddingModel = createEmbeddingModel;\n provider.imageModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'imageModel',\n message: 'Image generation is not supported by Ollama',\n });\n };\n\n return provider as OllamaProvider;\n}\n\n/**\n * Default Ollama provider instance\n */\nexport const ollama = createOllama();\n","import { LanguageModelV2Prompt } from '@ai-sdk/provider';\nimport { Message as OllamaMessage } from 'ollama';\n\nexport function convertToOllamaChatMessages(\n prompt: LanguageModelV2Prompt,\n): OllamaMessage[] {\n const messages: OllamaMessage[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case 'system': {\n messages.push({\n role: 'system',\n content: message.content,\n });\n break;\n }\n\n case 'user': {\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user',\n content: message.content,\n });\n } else {\n // Handle multi-part content\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n\n const imageParts = message.content\n .filter(\n (part): part is Extract<typeof part, { type: 'file' }> =>\n part.type === 'file',\n )\n .filter((part) => part.mediaType.startsWith('image/'))\n .map((part) => {\n if (part.data instanceof URL) {\n return part.data.href;\n } else if (typeof part.data === 'string') {\n // If it's already a data URL, extract just the base64 part\n if (part.data.startsWith('data:')) {\n const base64Match = part.data.match(/data:[^;]+;base64,(.+)/);\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n }\n return part.data;\n } else if (part.data instanceof Uint8Array) {\n // Handle Uint8Array by converting to base64 (without data URL prefix)\n return Buffer.from(part.data).toString('base64');\n } else {\n // Fallback for other types\n return String(part.data);\n }\n });\n\n messages.push({\n role: 'user',\n content: textParts,\n images:\n imageParts.length > 0\n ? imageParts.filter((img): img is string => img !== undefined)\n : undefined,\n });\n }\n break;\n }\n\n case 'assistant': {\n let content = '';\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Combine text parts\n content = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('');\n\n // Handle tool calls if present\n const toolCalls = message.content.filter(\n (part) => part.type === 'tool-call',\n );\n if (toolCalls.length > 0) {\n // For now, we'll append tool calls as text since Ollama doesn't have native support\n const toolCallText = toolCalls\n .map((tc) => `[Tool Call: ${tc.toolName}]`)\n .join('\\n');\n if (toolCallText) {\n content = content ? `${content}\\n${toolCallText}` : toolCallText;\n }\n }\n }\n\n messages.push({\n role: 'assistant',\n content,\n });\n break;\n }\n\n case 'tool': {\n // Ollama doesn't have native tool result support, so we'll add it as a user message\n messages.push({\n role: 'user',\n content: `[Tool Result]`,\n });\n break;\n }\n\n default: {\n // Handle unknown message roles\n throw new Error(\n `Unsupported message role: ${(message as { role: string }).role}`,\n );\n }\n }\n }\n\n return messages;\n}\n","import { LanguageModelV2FinishReason } from '@ai-sdk/provider';\n\nexport function mapOllamaFinishReason(\n reason?: string | null,\n): LanguageModelV2FinishReason {\n if (!reason) return 'unknown';\n\n switch (reason) {\n case 'stop': {\n return 'stop';\n }\n case 'length': {\n return 'length';\n }\n default: {\n return 'unknown';\n }\n }\n}\n","export interface OllamaErrorData {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport class OllamaError extends Error {\n readonly cause?: unknown;\n readonly data?: OllamaErrorData;\n\n constructor({\n message,\n cause,\n data,\n }: {\n message: string;\n cause?: unknown;\n data?: OllamaErrorData;\n }) {\n super(message);\n this.name = 'OllamaError';\n this.cause = cause;\n this.data = data;\n }\n\n static isOllamaError(error: unknown): error is OllamaError {\n return error instanceof OllamaError;\n }\n}\n","import {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2CallWarning,\n LanguageModelV2FinishReason,\n LanguageModelV2StreamPart,\n LanguageModelV2Usage,\n LanguageModelV2Content,\n JSONValue,\n} from '@ai-sdk/provider';\nimport { Ollama, Message as OllamaMessage, ChatResponse, Tool } from 'ollama';\nimport { OllamaChatSettings } from '../provider';\nimport { convertToOllamaChatMessages } from '../utils/convert-to-ollama-messages';\nimport { mapOllamaFinishReason } from '../utils/map-ollama-finish-reason';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaChatConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaChatLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly defaultObjectGenerationMode = 'json';\n readonly supportsImages = false;\n readonly supportsVideoURLs = false;\n readonly supportsAudioURLs = false;\n readonly supportsVideoFile = false;\n readonly supportsAudioFile = false;\n readonly supportsImageFile = true;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n constructor(\n public readonly modelId: string,\n public readonly settings: OllamaChatSettings,\n private readonly config: OllamaChatConfig,\n ) {}\n\n get provider(): string {\n return this.config.provider;\n }\n\n get supportsStructuredOutputs(): boolean {\n return this.settings.structuredOutputs ?? false;\n }\n\n private getCallOptions(options: LanguageModelV2CallOptions): {\n messages: OllamaMessage[];\n options: Record<string, unknown>;\n format?: string;\n tools?: Tool[];\n warnings: LanguageModelV2CallWarning[];\n } {\n const {\n prompt,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n seed,\n responseFormat,\n tools,\n } = options;\n\n const warnings: LanguageModelV2CallWarning[] = [];\n\n // Check for unsupported features and throw errors\n if (\n responseFormat?.type === 'json' &&\n responseFormat.schema &&\n !this.supportsStructuredOutputs\n ) {\n throw new Error(\n 'JSON schema is only supported when structuredOutputs is enabled',\n );\n }\n\n // Convert AI SDK tools to Ollama format (error already thrown if unsupported)\n const ollamaTools: Tool[] | undefined = tools\n ? tools.map((tool): Tool => {\n if (tool.type === 'function') {\n // The inputSchema from AI SDK should already be a JSON schema\n // when tools are passed to providers\n let jsonSchema: Record<string, unknown>;\n\n // Check if we have a Zod schema (has parse method) or a JSON schema\n if (tool.inputSchema && typeof tool.inputSchema === 'object') {\n if (\n 'parse' in tool.inputSchema &&\n typeof tool.inputSchema.parse === 'function'\n ) {\n // It's a Zod schema - we need to convert it\n // For now, we'll use a basic fallback since zod-to-json-schema has version issues\n console.warn(\n `Tool ${tool.name} is using a Zod schema directly. Schema conversion may not work properly due to Zod version mismatch.`,\n );\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n } else if (\n 'properties' in tool.inputSchema ||\n 'type' in tool.inputSchema\n ) {\n // It looks like a JSON schema already\n jsonSchema = tool.inputSchema as Record<string, unknown>;\n } else {\n // Unknown schema format\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n } else {\n // No schema provided\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n },\n };\n }\n // Provider-defined tools not supported by Ollama\n throw new Error(\n `Provider-defined tools are not supported by Ollama. Use function tools instead.`,\n );\n })\n : undefined;\n\n // Build options with correct precedence:\n // 1. AI SDK call parameters (mapped to Ollama equivalents)\n // 2. Model settings (Ollama options) override AI SDK parameters when both are specified\n const ollamaOptions: Record<string, unknown> = {\n // Start with AI SDK parameters mapped to Ollama names\n ...(temperature !== undefined && { temperature }),\n ...(maxOutputTokens !== undefined && { num_predict: maxOutputTokens }),\n ...(topP !== undefined && { top_p: topP }),\n ...(topK !== undefined && { top_k: topK }),\n ...(frequencyPenalty !== undefined && {\n frequency_penalty: frequencyPenalty,\n }),\n ...(presencePenalty !== undefined && {\n presence_penalty: presencePenalty,\n }),\n ...(stopSequences !== undefined && { stop: stopSequences }),\n ...(seed !== undefined && { seed }),\n // Ollama model options override AI SDK parameters\n ...this.settings.options,\n };\n\n // Remove undefined values\n for (const key of Object.keys(ollamaOptions)) {\n if (ollamaOptions[key] === undefined) {\n delete ollamaOptions[key];\n }\n }\n\n let format: string | undefined;\n if (responseFormat?.type === 'json') {\n format = 'json';\n }\n\n const messages = convertToOllamaChatMessages(prompt);\n\n return {\n messages,\n options: ollamaOptions,\n format,\n tools: ollamaTools,\n warnings,\n };\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n providerMetadata?: Record<string, Record<string, JSONValue>>;\n request?: { body: string };\n response?: { id?: string; timestamp?: Date; modelId?: string };\n warnings: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const response = (await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: false,\n })) as ChatResponse;\n\n const text = response.message.content;\n const toolCalls = response.message.tool_calls;\n\n // Convert content based on whether we have tool calls\n const content: LanguageModelV2Content[] = [];\n\n if (text) {\n content.push({ type: 'text', text });\n }\n\n if (toolCalls && toolCalls.length > 0) {\n for (const toolCall of toolCalls) {\n const toolInput = toolCall.function.arguments || {};\n\n content.push({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n return {\n content,\n finishReason: mapOllamaFinishReason(\n response.done_reason,\n ) as LanguageModelV2FinishReason,\n usage: {\n inputTokens: response.prompt_eval_count || 0,\n outputTokens: response.eval_count || 0,\n totalTokens:\n (response.prompt_eval_count || 0) + (response.eval_count || 0),\n },\n providerMetadata: {\n ollama: {\n model: response.model,\n created_at: response.created_at\n ? new Date(response.created_at).toISOString()\n : undefined,\n total_duration: response.total_duration,\n load_duration: response.load_duration,\n eval_duration: response.eval_duration,\n } as Record<string, JSONValue>,\n },\n request: {\n body: JSON.stringify({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n }),\n },\n response: {\n timestamp: new Date(),\n modelId: this.modelId,\n },\n warnings,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const stream = await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: true,\n });\n\n let usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n const transformStream = new TransformStream<\n ChatResponse,\n LanguageModelV2StreamPart\n >({\n async transform(chunk: ChatResponse, controller) {\n // Validate chunk\n if (!chunk || typeof chunk !== 'object') {\n return; // Skip invalid chunks\n }\n\n // Regular chunk with content\n if (chunk.done) {\n // Final chunk with metadata\n usage = {\n inputTokens: chunk.prompt_eval_count || 0,\n outputTokens: chunk.eval_count || 0,\n totalTokens:\n (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),\n };\n finishReason = mapOllamaFinishReason(\n chunk.done_reason,\n ) as LanguageModelV2FinishReason;\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n } else {\n // Handle tool calls in streaming\n if (\n chunk.message.tool_calls &&\n chunk.message.tool_calls.length > 0\n ) {\n for (const toolCall of chunk.message.tool_calls) {\n const toolInput = toolCall.function.arguments || {};\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n } else if (\n chunk.message.content &&\n typeof chunk.message.content === 'string'\n ) {\n controller.enqueue({\n type: 'text-delta',\n id: crypto.randomUUID(), // Generate unique ID for each text chunk\n delta: chunk.message.content,\n });\n }\n }\n },\n });\n\n // Create a readable stream from the async generator\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n // Ensure chunk is valid before enqueuing\n if (chunk && typeof chunk === 'object') {\n controller.enqueue(chunk);\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return {\n stream: readableStream.pipeThrough(transformStream),\n rawCall: {\n rawPrompt: messages,\n rawSettings: {\n model: this.modelId,\n options: ollamaOptions,\n format,\n tools,\n },\n },\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n","import { EmbeddingModelV2, EmbeddingModelV2Embedding } from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaEmbeddingSettings } from '../provider';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaEmbeddingConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaEmbeddingModel implements EmbeddingModelV2<string> {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly maxEmbeddingsPerCall = 2048;\n readonly supportsParallelCalls = true;\n\n constructor(\n modelId: string,\n private readonly settings: OllamaEmbeddingSettings,\n private readonly config: OllamaEmbeddingConfig,\n ) {\n this.modelId = modelId;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n async doEmbed(params: {\n values: string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n embeddings: EmbeddingModelV2Embedding[];\n }> {\n const { values, abortSignal } = params;\n if (values.length > this.maxEmbeddingsPerCall) {\n throw new OllamaError({\n message: `Too many values to embed. Maximum: ${this.maxEmbeddingsPerCall}, Received: ${values.length}`,\n });\n }\n\n // Handle empty array case\n if (values.length === 0) {\n return { embeddings: [] };\n }\n\n try {\n const embeddings: EmbeddingModelV2Embedding[] = [];\n\n // Ollama's embed API currently only supports single prompts\n // So we need to make multiple requests\n for (const value of values) {\n // Skip undefined values (AI SDK interface issue workaround)\n if (value === undefined || value === null) {\n continue;\n }\n\n const response = await this.config.client.embed({\n model: this.modelId,\n input: value,\n options: this.settings.options,\n });\n\n if (!response.embeddings) {\n throw new OllamaError({\n message: `No embeddings field in response`,\n });\n }\n\n if (response.embeddings.length === 0) {\n throw new OllamaError({\n message: `Empty embeddings array returned`,\n });\n }\n\n embeddings.push(response.embeddings[0] as number[]);\n\n // Check if we should abort\n if (abortSignal?.aborted) {\n throw new Error('Embedding generation aborted');\n }\n }\n\n if (embeddings.length === 0) {\n throw new OllamaError({\n message: `No valid values provided for embedding (all were undefined/null)`,\n });\n }\n\n return {\n embeddings,\n };\n } catch (error) {\n if (error instanceof OllamaError) {\n throw error;\n }\n\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/provider.ts","../src/utils/convert-to-ollama-messages.ts","../src/utils/map-ollama-finish-reason.ts","../src/utils/ollama-error.ts","../src/models/chat-language-model.ts","../src/models/embedding-model.ts"],"sourcesContent":["export {\n createOllama,\n ollama,\n type OllamaProvider,\n type OllamaProviderSettings,\n type OllamaChatSettings,\n type OllamaEmbeddingSettings,\n type OllamaProviderOptions,\n type OllamaChatProviderOptions,\n type OllamaEmbeddingProviderOptions,\n} from './provider';\n\nexport { OllamaChatLanguageModel } from './models/chat-language-model';\nexport type { OllamaChatConfig } from './models/chat-language-model';\nexport { OllamaEmbeddingModel } from './models/embedding-model';\nexport type { OllamaEmbeddingConfig } from './models/embedding-model';\nexport { OllamaError } from './utils/ollama-error';\nexport type { OllamaErrorData } from './utils/ollama-error';\n","import {\n LanguageModelV2,\n EmbeddingModelV2,\n ProviderV2,\n NoSuchModelError,\n} from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaChatLanguageModel } from './models/chat-language-model';\nimport { OllamaEmbeddingModel } from './models/embedding-model';\n\nexport interface OllamaProviderSettings {\n /**\n * Base URL for the Ollama API (defaults to http://127.0.0.1:11434)\n */\n baseURL?: string;\n\n /**\n * Custom headers for API requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\nexport interface OllamaProvider extends ProviderV2 {\n /**\n * Create a language model instance\n */\n (modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `chat` method\n */\n chat(modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `languageModel` method\n */\n languageModel(\n modelId: string,\n settings?: OllamaChatSettings,\n ): LanguageModelV2;\n\n /**\n * Create an embedding model instance\n */\n embedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbedding` method\n */\n textEmbedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbeddingModel` method\n */\n textEmbeddingModel(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n}\n\nexport interface OllamaChatSettings {\n /**\n * Enable structured output mode\n */\n structuredOutputs?: boolean;\n\n /**\n * Enable reasoning support for models that support it\n */\n reasoning?: boolean;\n\n /**\n * Additional model parameters\n */\n options?: {\n num_ctx?: number;\n num_predict?: number;\n temperature?: number;\n top_k?: number;\n top_p?: number;\n min_p?: number;\n seed?: number;\n stop?: string[];\n num_keep?: number;\n typical_p?: number;\n repeat_last_n?: number;\n repeat_penalty?: number;\n presence_penalty?: number;\n frequency_penalty?: number;\n mirostat?: number;\n mirostat_tau?: number;\n mirostat_eta?: number;\n penalize_newline?: boolean;\n numa?: boolean;\n num_thread?: number;\n num_gpu?: number;\n main_gpu?: number;\n low_vram?: boolean;\n f16_kv?: boolean;\n vocab_only?: boolean;\n use_mmap?: boolean;\n use_mlock?: boolean;\n };\n}\n\nexport interface OllamaEmbeddingSettings {\n /**\n * Additional embedding parameters\n */\n options?: {\n num_thread?: number;\n };\n}\n\n/**\n * Options for configuring Ollama provider calls\n */\nexport interface OllamaProviderOptions {\n /**\n * Additional headers to include in requests\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Options for configuring Ollama chat model calls\n */\nexport interface OllamaChatProviderOptions extends OllamaProviderOptions {\n /**\n * Enable structured output mode for object generation\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Options for configuring Ollama embedding model calls\n */\nexport interface OllamaEmbeddingProviderOptions extends OllamaProviderOptions {\n /**\n * Maximum number of embeddings to process in a single call\n */\n maxEmbeddingsPerCall?: number;\n}\n\n/**\n * Create an Ollama provider instance\n */\nexport function createOllama(\n options: OllamaProviderSettings = {},\n): OllamaProvider {\n const client = new Ollama({\n host: options.baseURL,\n fetch: options.fetch,\n headers: options.headers,\n });\n\n const createChatModel = (\n modelId: string,\n settings: OllamaChatSettings = {},\n ) => {\n return new OllamaChatLanguageModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const createEmbeddingModel = (\n modelId: string,\n settings: OllamaEmbeddingSettings = {},\n ) => {\n return new OllamaEmbeddingModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const provider = function (modelId: string, settings?: OllamaChatSettings) {\n if (new.target) {\n throw new Error(\n 'The Ollama provider cannot be called with the new keyword.',\n );\n }\n return createChatModel(modelId, settings);\n };\n\n provider.chat = createChatModel;\n provider.languageModel = createChatModel;\n provider.embedding = createEmbeddingModel;\n provider.textEmbedding = createEmbeddingModel;\n provider.textEmbeddingModel = createEmbeddingModel;\n provider.imageModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'imageModel',\n message: 'Image generation is not supported by Ollama',\n });\n };\n\n return provider as OllamaProvider;\n}\n\n/**\n * Default Ollama provider instance\n */\nexport const ollama = createOllama();\n","import { LanguageModelV2Prompt } from '@ai-sdk/provider';\nimport { Message as OllamaMessage } from 'ollama';\n\n/**\n * Enhanced message conversion that supports all Ollama capabilities\n * and handles edge cases better than the referenced implementation\n */\nexport function convertToOllamaChatMessages(\n prompt: LanguageModelV2Prompt,\n): OllamaMessage[] {\n const messages: OllamaMessage[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case 'system': {\n messages.push({\n role: 'system',\n content: message.content,\n });\n break;\n }\n\n case 'user': {\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user',\n content: message.content,\n });\n } else {\n // Handle multi-part content with enhanced image support\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n\n const imageParts = message.content\n .filter(\n (part): part is Extract<typeof part, { type: 'file' }> =>\n part.type === 'file',\n )\n .filter((part) => {\n // Support image files only\n return part.mediaType?.startsWith('image/') || false;\n })\n .map((part) => {\n const imageData = part.data;\n\n if (imageData instanceof URL) {\n // Handle image URLs - extract base64 from data URLs or use URL directly\n if (imageData.protocol === 'data:') {\n const base64Match = imageData.href.match(\n /data:[^;]+;base64,(.+)/,\n );\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n // If no base64 match, return the full data URL\n return imageData.href;\n }\n // For HTTP URLs, return as-is (Ollama will handle them)\n return imageData.href;\n } else if (typeof imageData === 'string') {\n // Handle base64 strings\n if (imageData.startsWith('data:')) {\n const base64Match = imageData.match(/data:[^;]+;base64,(.+)/);\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n }\n return imageData;\n } else if (imageData instanceof Uint8Array) {\n // Handle Uint8Array by converting to base64\n return Buffer.from(imageData).toString('base64');\n } else {\n // Fallback for other types\n console.warn(\n `Unsupported image data type: ${typeof imageData}`,\n );\n return null;\n }\n })\n .filter((img): img is string => img !== null);\n\n messages.push({\n role: 'user',\n content: textParts || '', // Ensure content is never undefined\n images: imageParts.length > 0 ? imageParts : undefined,\n });\n }\n break;\n }\n\n case 'assistant': {\n let content = '';\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Enhanced content handling with better tool call support\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('');\n\n const reasoningParts = message.content\n .filter((part) => part.type === 'reasoning')\n .map((part) => part.text)\n .join('\\n');\n\n // Combine text and reasoning\n content = [textParts, reasoningParts].filter(Boolean).join('\\n');\n\n // Handle tool calls if present\n const toolCalls = message.content.filter(\n (part) => part.type === 'tool-call',\n );\n if (toolCalls.length > 0) {\n // For now, we'll append tool calls as text since Ollama doesn't have native support\n const toolCallText = toolCalls\n .map((tc) => `[Tool Call: ${tc.toolName}]`)\n .join('\\n');\n if (toolCallText) {\n content = content ? `${content}\\n${toolCallText}` : toolCallText;\n }\n }\n }\n\n messages.push({\n role: 'assistant',\n content: content || '', // Ensure content is never undefined\n });\n break;\n }\n\n case 'tool': {\n // Enhanced tool result handling\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user', // Ollama doesn't have native tool role, so we use user\n content: `[Tool Result]: ${message.content}`,\n });\n } else {\n // Handle multi-part tool results\n const toolResultParts = message.content\n .filter((part) => part.type === 'tool-result')\n .map((part) => {\n if (part.output.type === 'text') {\n return part.output.value;\n } else if (part.output.type === 'json') {\n return JSON.stringify(part.output.value);\n }\n return String(part.output.value);\n })\n .join('\\n');\n\n messages.push({\n role: 'user',\n content: `[Tool Result]: ${toolResultParts || ''}`,\n });\n }\n break;\n }\n\n default: {\n // Enhanced error handling with more descriptive messages\n const role = (message as { role: string }).role;\n throw new Error(\n `Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`,\n );\n }\n }\n }\n\n return messages;\n}\n","import { LanguageModelV2FinishReason } from '@ai-sdk/provider';\n\nexport function mapOllamaFinishReason(\n reason?: string | null,\n): LanguageModelV2FinishReason {\n if (!reason) return 'unknown';\n\n switch (reason) {\n case 'stop': {\n return 'stop';\n }\n case 'length': {\n return 'length';\n }\n default: {\n return 'unknown';\n }\n }\n}\n","export interface OllamaErrorData {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport class OllamaError extends Error {\n readonly cause?: unknown;\n readonly data?: OllamaErrorData;\n\n constructor({\n message,\n cause,\n data,\n }: {\n message: string;\n cause?: unknown;\n data?: OllamaErrorData;\n }) {\n super(message);\n this.name = 'OllamaError';\n this.cause = cause;\n this.data = data;\n }\n\n static isOllamaError(error: unknown): error is OllamaError {\n return error instanceof OllamaError;\n }\n}\n","import {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2CallWarning,\n LanguageModelV2FinishReason,\n LanguageModelV2StreamPart,\n LanguageModelV2Usage,\n LanguageModelV2Content,\n JSONValue,\n} from '@ai-sdk/provider';\nimport { Ollama, Message as OllamaMessage, ChatResponse, Tool } from 'ollama';\nimport { OllamaChatSettings } from '../provider';\nimport { convertToOllamaChatMessages } from '../utils/convert-to-ollama-messages';\nimport { mapOllamaFinishReason } from '../utils/map-ollama-finish-reason';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaChatConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaChatLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly defaultObjectGenerationMode = 'json';\n readonly supportsImages = true; // โœ… Ollama supports images (URLs, files, base64)\n readonly supportsVideoURLs = false; // โŒ Not supported by Ollama API\n readonly supportsAudioURLs = false; // โŒ Not supported by Ollama API\n readonly supportsVideoFile = false; // โŒ Not supported by Ollama API\n readonly supportsAudioFile = false; // โŒ Not supported by Ollama API\n readonly supportsImageFile = true; // โœ… Already correct\n readonly supportedUrls: Record<string, RegExp[]> = {\n // Support common image URL patterns\n image: [\n /^https?:\\/\\/.*\\.(jpg|jpeg|png|gif|webp|bmp|svg)(\\?.*)?$/i,\n /^data:image\\/[^;]+;base64,/i, // Data URLs\n ],\n };\n\n constructor(\n public readonly modelId: string,\n public readonly settings: OllamaChatSettings,\n private readonly config: OllamaChatConfig,\n ) {}\n\n get provider(): string {\n return this.config.provider;\n }\n\n get supportsStructuredOutputs(): boolean {\n // Auto-detect structured outputs when JSON schema is provided\n // This allows generateObject and streamObject to work without explicit structuredOutputs: true\n return this.settings.structuredOutputs ?? false;\n }\n\n /**\n * Check if structured outputs should be enabled based on the call options\n * This is used internally to auto-detect when structured outputs are needed\n */\n private shouldEnableStructuredOutputs(\n options: LanguageModelV2CallOptions,\n ): boolean {\n // Auto-detect: if we have a JSON schema, we need structured outputs\n // This overrides explicit settings to ensure object generation works\n if (\n options.responseFormat?.type === 'json' &&\n options.responseFormat.schema\n ) {\n // Warn if structuredOutputs was explicitly set to false but we're auto-enabling it\n if (this.settings.structuredOutputs === false) {\n console.warn(\n 'Ollama: structuredOutputs was set to false but auto-enabled for object generation. ' +\n 'This ensures generateObject and streamObject work correctly.',\n );\n }\n return true;\n }\n\n // If explicitly set, use that value (for text generation)\n if (this.settings.structuredOutputs !== undefined) {\n return this.settings.structuredOutputs;\n }\n\n // Default to false for regular text generation\n return false;\n }\n\n private getCallOptions(options: LanguageModelV2CallOptions): {\n messages: OllamaMessage[];\n options: Record<string, unknown>;\n format?: string | Record<string, unknown>;\n tools?: Tool[];\n warnings: LanguageModelV2CallWarning[];\n } {\n const {\n prompt,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n seed,\n responseFormat,\n tools,\n } = options;\n\n const warnings: LanguageModelV2CallWarning[] = [];\n\n // Auto-detect structured outputs when JSON schema is provided\n const needsStructuredOutputs = this.shouldEnableStructuredOutputs(options);\n\n // Check for unsupported features and throw errors\n if (\n responseFormat?.type === 'json' &&\n responseFormat.schema &&\n !needsStructuredOutputs\n ) {\n throw new Error(\n 'JSON schema is only supported when structuredOutputs is enabled',\n );\n }\n\n // Convert AI SDK tools to Ollama format (error already thrown if unsupported)\n const ollamaTools: Tool[] | undefined = tools\n ? tools.map((tool): Tool => {\n if (tool.type === 'function') {\n // The inputSchema from AI SDK should already be a JSON schema\n // when tools are passed to providers\n let jsonSchema: Record<string, unknown>;\n\n // Check if we have a Zod schema (has parse method) or a JSON schema\n if (tool.inputSchema && typeof tool.inputSchema === 'object') {\n if (\n 'parse' in tool.inputSchema &&\n typeof tool.inputSchema.parse === 'function'\n ) {\n // It's a Zod schema - we need to convert it\n // For now, we'll use a basic fallback since zod-to-json-schema has version issues\n console.warn(\n `Tool ${tool.name} is using a Zod schema directly. Schema conversion may not work properly due to Zod version mismatch.`,\n );\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n } else if (\n 'properties' in tool.inputSchema ||\n 'type' in tool.inputSchema\n ) {\n // It looks like a JSON schema already\n jsonSchema = tool.inputSchema as Record<string, unknown>;\n } else {\n // Unknown schema format\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n } else {\n // No schema provided\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n },\n };\n }\n // Provider-defined tools not supported by Ollama\n throw new Error(\n `Provider-defined tools are not supported by Ollama. Use function tools instead.`,\n );\n })\n : undefined;\n\n // Build options with correct precedence:\n // 1. AI SDK call parameters (mapped to Ollama equivalents)\n // 2. Model settings (Ollama options) override AI SDK parameters when both are specified\n const ollamaOptions: Record<string, unknown> = {\n // Start with AI SDK parameters mapped to Ollama names\n ...(temperature !== undefined && { temperature }),\n ...(maxOutputTokens !== undefined && { num_predict: maxOutputTokens }),\n ...(topP !== undefined && { top_p: topP }),\n ...(topK !== undefined && { top_k: topK }),\n ...(frequencyPenalty !== undefined && {\n frequency_penalty: frequencyPenalty,\n }),\n ...(presencePenalty !== undefined && {\n presence_penalty: presencePenalty,\n }),\n ...(stopSequences !== undefined && { stop: stopSequences }),\n ...(seed !== undefined && { seed }),\n // Ollama model options override AI SDK parameters\n ...this.settings.options,\n };\n\n // Remove undefined values\n for (const key of Object.keys(ollamaOptions)) {\n if (ollamaOptions[key] === undefined) {\n delete ollamaOptions[key];\n }\n }\n\n let format: string | Record<string, unknown> | undefined;\n if (responseFormat?.type === 'json') {\n format =\n responseFormat.schema && needsStructuredOutputs\n ? (responseFormat.schema as Record<string, unknown>)\n : 'json';\n }\n\n const messages = convertToOllamaChatMessages(prompt);\n\n return {\n messages,\n options: ollamaOptions,\n format,\n tools: ollamaTools,\n warnings,\n };\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n providerMetadata?: Record<string, Record<string, JSONValue>>;\n request?: { body: string };\n response?: { id?: string; timestamp?: Date; modelId?: string };\n warnings: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const response = (await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: false,\n })) as ChatResponse;\n\n const text = response.message.content;\n const toolCalls = response.message.tool_calls;\n const thinking = response.message.thinking;\n\n // Convert content based on whether we have tool calls, reasoning, or text\n const content: LanguageModelV2Content[] = [];\n\n // Add reasoning content if present and enabled\n if (thinking && this.settings.reasoning) {\n content.push({ type: 'reasoning', text: thinking });\n }\n\n // Add text content if present\n if (text) {\n content.push({ type: 'text', text });\n }\n\n // Add tool calls if present\n if (toolCalls && toolCalls.length > 0) {\n for (const toolCall of toolCalls) {\n const toolInput = toolCall.function.arguments || {};\n\n content.push({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n return {\n content,\n finishReason: mapOllamaFinishReason(\n response.done_reason,\n ) as LanguageModelV2FinishReason,\n usage: {\n inputTokens: response.prompt_eval_count || 0,\n outputTokens: response.eval_count || 0,\n totalTokens:\n (response.prompt_eval_count || 0) + (response.eval_count || 0),\n },\n providerMetadata: {\n ollama: {\n model: response.model,\n created_at: response.created_at\n ? new Date(response.created_at).toISOString()\n : undefined,\n total_duration: response.total_duration,\n load_duration: response.load_duration,\n eval_duration: response.eval_duration,\n } as Record<string, JSONValue>,\n },\n request: {\n body: JSON.stringify({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n }),\n },\n response: {\n timestamp: new Date(),\n modelId: this.modelId,\n },\n warnings,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const stream = await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: true,\n });\n\n let usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n // Capture settings for use in transform function\n const reasoningEnabled = this.settings.reasoning;\n\n const transformStream = new TransformStream<\n ChatResponse,\n LanguageModelV2StreamPart\n >({\n async transform(chunk: ChatResponse, controller) {\n // Validate chunk\n if (!chunk || typeof chunk !== 'object') {\n return; // Skip invalid chunks\n }\n\n // Regular chunk with content\n if (chunk.done) {\n // Final chunk with metadata\n usage = {\n inputTokens: chunk.prompt_eval_count || 0,\n outputTokens: chunk.eval_count || 0,\n totalTokens:\n (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),\n };\n finishReason = mapOllamaFinishReason(\n chunk.done_reason,\n ) as LanguageModelV2FinishReason;\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n } else {\n // Handle reasoning in streaming\n if (chunk.message.thinking && reasoningEnabled) {\n // For reasoning, we'll emit it as a single reasoning content\n // since Ollama doesn't stream reasoning in chunks\n controller.enqueue({\n type: 'reasoning-start',\n id: crypto.randomUUID(),\n });\n\n controller.enqueue({\n type: 'reasoning-delta',\n id: crypto.randomUUID(),\n delta: chunk.message.thinking,\n });\n\n controller.enqueue({\n type: 'reasoning-end',\n id: crypto.randomUUID(),\n });\n }\n\n // Handle tool calls in streaming\n if (\n chunk.message.tool_calls &&\n chunk.message.tool_calls.length > 0\n ) {\n for (const toolCall of chunk.message.tool_calls) {\n const toolInput = toolCall.function.arguments || {};\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n // Handle text content in streaming (always emit if present)\n if (\n chunk.message.content &&\n typeof chunk.message.content === 'string' &&\n chunk.message.content.length > 0\n ) {\n controller.enqueue({\n type: 'text-delta',\n id: crypto.randomUUID(), // Generate unique ID for each text chunk\n delta: chunk.message.content,\n });\n }\n }\n },\n });\n\n // Create a readable stream from the async generator\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n // Ensure chunk is valid before enqueuing\n if (chunk && typeof chunk === 'object') {\n controller.enqueue(chunk);\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return {\n stream: readableStream.pipeThrough(transformStream),\n rawCall: {\n rawPrompt: messages,\n rawSettings: {\n model: this.modelId,\n options: ollamaOptions,\n format,\n tools,\n },\n },\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n","import { EmbeddingModelV2, EmbeddingModelV2Embedding } from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaEmbeddingSettings } from '../provider';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaEmbeddingConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaEmbeddingModel implements EmbeddingModelV2<string> {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly maxEmbeddingsPerCall = 2048;\n readonly supportsParallelCalls = true;\n\n constructor(\n modelId: string,\n private readonly settings: OllamaEmbeddingSettings,\n private readonly config: OllamaEmbeddingConfig,\n ) {\n this.modelId = modelId;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n async doEmbed(params: {\n values: string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n embeddings: EmbeddingModelV2Embedding[];\n }> {\n const { values, abortSignal } = params;\n if (values.length > this.maxEmbeddingsPerCall) {\n throw new OllamaError({\n message: `Too many values to embed. Maximum: ${this.maxEmbeddingsPerCall}, Received: ${values.length}`,\n });\n }\n\n // Handle empty array case\n if (values.length === 0) {\n return { embeddings: [] };\n }\n\n try {\n const embeddings: EmbeddingModelV2Embedding[] = [];\n\n // Ollama's embed API currently only supports single prompts\n // So we need to make multiple requests\n for (const value of values) {\n // Skip undefined values (AI SDK interface issue workaround)\n if (value === undefined || value === null) {\n continue;\n }\n\n const response = await this.config.client.embed({\n model: this.modelId,\n input: value,\n options: this.settings.options,\n });\n\n if (!response.embeddings) {\n throw new OllamaError({\n message: `No embeddings field in response`,\n });\n }\n\n if (response.embeddings.length === 0) {\n throw new OllamaError({\n message: `Empty embeddings array returned`,\n });\n }\n\n embeddings.push(response.embeddings[0] as number[]);\n\n // Check if we should abort\n if (abortSignal?.aborted) {\n throw new Error('Embedding generation aborted');\n }\n }\n\n if (embeddings.length === 0) {\n throw new OllamaError({\n message: `No valid values provided for embedding (all were undefined/null)`,\n });\n }\n\n return {\n embeddings,\n };\n } catch (error) {\n if (error instanceof OllamaError) {\n throw error;\n }\n\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -46,6 +46,10 @@ interface OllamaChatSettings {
46
46
  * Enable structured output mode
47
47
  */
48
48
  structuredOutputs?: boolean;
49
+ /**
50
+ * Enable reasoning support for models that support it
51
+ */
52
+ reasoning?: boolean;
49
53
  /**
50
54
  * Additional model parameters
51
55
  */
@@ -133,7 +137,7 @@ declare class OllamaChatLanguageModel implements LanguageModelV2 {
133
137
  private readonly config;
134
138
  readonly specificationVersion: "v2";
135
139
  readonly defaultObjectGenerationMode = "json";
136
- readonly supportsImages = false;
140
+ readonly supportsImages = true;
137
141
  readonly supportsVideoURLs = false;
138
142
  readonly supportsAudioURLs = false;
139
143
  readonly supportsVideoFile = false;
@@ -143,6 +147,11 @@ declare class OllamaChatLanguageModel implements LanguageModelV2 {
143
147
  constructor(modelId: string, settings: OllamaChatSettings, config: OllamaChatConfig);
144
148
  get provider(): string;
145
149
  get supportsStructuredOutputs(): boolean;
150
+ /**
151
+ * Check if structured outputs should be enabled based on the call options
152
+ * This is used internally to auto-detect when structured outputs are needed
153
+ */
154
+ private shouldEnableStructuredOutputs;
146
155
  private getCallOptions;
147
156
  doGenerate(options: LanguageModelV2CallOptions): Promise<{
148
157
  content: LanguageModelV2Content[];
package/dist/index.d.ts CHANGED
@@ -46,6 +46,10 @@ interface OllamaChatSettings {
46
46
  * Enable structured output mode
47
47
  */
48
48
  structuredOutputs?: boolean;
49
+ /**
50
+ * Enable reasoning support for models that support it
51
+ */
52
+ reasoning?: boolean;
49
53
  /**
50
54
  * Additional model parameters
51
55
  */
@@ -133,7 +137,7 @@ declare class OllamaChatLanguageModel implements LanguageModelV2 {
133
137
  private readonly config;
134
138
  readonly specificationVersion: "v2";
135
139
  readonly defaultObjectGenerationMode = "json";
136
- readonly supportsImages = false;
140
+ readonly supportsImages = true;
137
141
  readonly supportsVideoURLs = false;
138
142
  readonly supportsAudioURLs = false;
139
143
  readonly supportsVideoFile = false;
@@ -143,6 +147,11 @@ declare class OllamaChatLanguageModel implements LanguageModelV2 {
143
147
  constructor(modelId: string, settings: OllamaChatSettings, config: OllamaChatConfig);
144
148
  get provider(): string;
145
149
  get supportsStructuredOutputs(): boolean;
150
+ /**
151
+ * Check if structured outputs should be enabled based on the call options
152
+ * This is used internally to auto-detect when structured outputs are needed
153
+ */
154
+ private shouldEnableStructuredOutputs;
146
155
  private getCallOptions;
147
156
  doGenerate(options: LanguageModelV2CallOptions): Promise<{
148
157
  content: LanguageModelV2Content[];
package/dist/index.js CHANGED
@@ -26,27 +26,43 @@ function convertToOllamaChatMessages(prompt) {
26
26
  const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
27
27
  const imageParts = message.content.filter(
28
28
  (part) => part.type === "file"
29
- ).filter((part) => part.mediaType.startsWith("image/")).map((part) => {
30
- if (part.data instanceof URL) {
31
- return part.data.href;
32
- } else if (typeof part.data === "string") {
33
- if (part.data.startsWith("data:")) {
34
- const base64Match = part.data.match(/data:[^;]+;base64,(.+)/);
29
+ ).filter((part) => {
30
+ return part.mediaType?.startsWith("image/") || false;
31
+ }).map((part) => {
32
+ const imageData = part.data;
33
+ if (imageData instanceof URL) {
34
+ if (imageData.protocol === "data:") {
35
+ const base64Match = imageData.href.match(
36
+ /data:[^;]+;base64,(.+)/
37
+ );
35
38
  if (base64Match) {
36
39
  return base64Match[1];
37
40
  }
41
+ return imageData.href;
38
42
  }
39
- return part.data;
40
- } else if (part.data instanceof Uint8Array) {
41
- return Buffer.from(part.data).toString("base64");
43
+ return imageData.href;
44
+ } else if (typeof imageData === "string") {
45
+ if (imageData.startsWith("data:")) {
46
+ const base64Match = imageData.match(/data:[^;]+;base64,(.+)/);
47
+ if (base64Match) {
48
+ return base64Match[1];
49
+ }
50
+ }
51
+ return imageData;
52
+ } else if (imageData instanceof Uint8Array) {
53
+ return Buffer.from(imageData).toString("base64");
42
54
  } else {
43
- return String(part.data);
55
+ console.warn(
56
+ `Unsupported image data type: ${typeof imageData}`
57
+ );
58
+ return null;
44
59
  }
45
- });
60
+ }).filter((img) => img !== null);
46
61
  messages.push({
47
62
  role: "user",
48
- content: textParts,
49
- images: imageParts.length > 0 ? imageParts.filter((img) => img !== void 0) : void 0
63
+ content: textParts || "",
64
+ // Ensure content is never undefined
65
+ images: imageParts.length > 0 ? imageParts : void 0
50
66
  });
51
67
  }
52
68
  break;
@@ -56,7 +72,9 @@ function convertToOllamaChatMessages(prompt) {
56
72
  if (typeof message.content === "string") {
57
73
  content = message.content;
58
74
  } else {
59
- content = message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
75
+ const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
76
+ const reasoningParts = message.content.filter((part) => part.type === "reasoning").map((part) => part.text).join("\n");
77
+ content = [textParts, reasoningParts].filter(Boolean).join("\n");
60
78
  const toolCalls = message.content.filter(
61
79
  (part) => part.type === "tool-call"
62
80
  );
@@ -70,20 +88,38 @@ ${toolCallText}` : toolCallText;
70
88
  }
71
89
  messages.push({
72
90
  role: "assistant",
73
- content
91
+ content: content || ""
92
+ // Ensure content is never undefined
74
93
  });
75
94
  break;
76
95
  }
77
96
  case "tool": {
78
- messages.push({
79
- role: "user",
80
- content: `[Tool Result]`
81
- });
97
+ if (typeof message.content === "string") {
98
+ messages.push({
99
+ role: "user",
100
+ // Ollama doesn't have native tool role, so we use user
101
+ content: `[Tool Result]: ${message.content}`
102
+ });
103
+ } else {
104
+ const toolResultParts = message.content.filter((part) => part.type === "tool-result").map((part) => {
105
+ if (part.output.type === "text") {
106
+ return part.output.value;
107
+ } else if (part.output.type === "json") {
108
+ return JSON.stringify(part.output.value);
109
+ }
110
+ return String(part.output.value);
111
+ }).join("\n");
112
+ messages.push({
113
+ role: "user",
114
+ content: `[Tool Result]: ${toolResultParts || ""}`
115
+ });
116
+ }
82
117
  break;
83
118
  }
84
119
  default: {
120
+ const role = message.role;
85
121
  throw new Error(
86
- `Unsupported message role: ${message.role}`
122
+ `Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`
87
123
  );
88
124
  }
89
125
  }
@@ -135,19 +171,50 @@ var OllamaChatLanguageModel = class {
135
171
  }
136
172
  specificationVersion = "v2";
137
173
  defaultObjectGenerationMode = "json";
138
- supportsImages = false;
174
+ supportsImages = true;
175
+ // โœ… Ollama supports images (URLs, files, base64)
139
176
  supportsVideoURLs = false;
177
+ // โŒ Not supported by Ollama API
140
178
  supportsAudioURLs = false;
179
+ // โŒ Not supported by Ollama API
141
180
  supportsVideoFile = false;
181
+ // โŒ Not supported by Ollama API
142
182
  supportsAudioFile = false;
183
+ // โŒ Not supported by Ollama API
143
184
  supportsImageFile = true;
144
- supportedUrls = {};
185
+ // โœ… Already correct
186
+ supportedUrls = {
187
+ // Support common image URL patterns
188
+ image: [
189
+ /^https?:\/\/.*\.(jpg|jpeg|png|gif|webp|bmp|svg)(\?.*)?$/i,
190
+ /^data:image\/[^;]+;base64,/i
191
+ // Data URLs
192
+ ]
193
+ };
145
194
  get provider() {
146
195
  return this.config.provider;
147
196
  }
148
197
  get supportsStructuredOutputs() {
149
198
  return this.settings.structuredOutputs ?? false;
150
199
  }
200
+ /**
201
+ * Check if structured outputs should be enabled based on the call options
202
+ * This is used internally to auto-detect when structured outputs are needed
203
+ */
204
+ shouldEnableStructuredOutputs(options) {
205
+ if (options.responseFormat?.type === "json" && options.responseFormat.schema) {
206
+ if (this.settings.structuredOutputs === false) {
207
+ console.warn(
208
+ "Ollama: structuredOutputs was set to false but auto-enabled for object generation. This ensures generateObject and streamObject work correctly."
209
+ );
210
+ }
211
+ return true;
212
+ }
213
+ if (this.settings.structuredOutputs !== void 0) {
214
+ return this.settings.structuredOutputs;
215
+ }
216
+ return false;
217
+ }
151
218
  getCallOptions(options) {
152
219
  const {
153
220
  prompt,
@@ -163,7 +230,8 @@ var OllamaChatLanguageModel = class {
163
230
  tools
164
231
  } = options;
165
232
  const warnings = [];
166
- if (responseFormat?.type === "json" && responseFormat.schema && !this.supportsStructuredOutputs) {
233
+ const needsStructuredOutputs = this.shouldEnableStructuredOutputs(options);
234
+ if (responseFormat?.type === "json" && responseFormat.schema && !needsStructuredOutputs) {
167
235
  throw new Error(
168
236
  "JSON schema is only supported when structuredOutputs is enabled"
169
237
  );
@@ -234,7 +302,7 @@ var OllamaChatLanguageModel = class {
234
302
  }
235
303
  let format;
236
304
  if (responseFormat?.type === "json") {
237
- format = "json";
305
+ format = responseFormat.schema && needsStructuredOutputs ? responseFormat.schema : "json";
238
306
  }
239
307
  const messages = convertToOllamaChatMessages(prompt);
240
308
  return {
@@ -264,7 +332,11 @@ var OllamaChatLanguageModel = class {
264
332
  });
265
333
  const text = response.message.content;
266
334
  const toolCalls = response.message.tool_calls;
335
+ const thinking = response.message.thinking;
267
336
  const content = [];
337
+ if (thinking && this.settings.reasoning) {
338
+ content.push({ type: "reasoning", text: thinking });
339
+ }
268
340
  if (text) {
269
341
  content.push({ type: "text", text });
270
342
  }
@@ -344,6 +416,7 @@ var OllamaChatLanguageModel = class {
344
416
  totalTokens: 0
345
417
  };
346
418
  let finishReason = "unknown";
419
+ const reasoningEnabled = this.settings.reasoning;
347
420
  const transformStream = new TransformStream({
348
421
  async transform(chunk, controller) {
349
422
  if (!chunk || typeof chunk !== "object") {
@@ -364,6 +437,21 @@ var OllamaChatLanguageModel = class {
364
437
  usage
365
438
  });
366
439
  } else {
440
+ if (chunk.message.thinking && reasoningEnabled) {
441
+ controller.enqueue({
442
+ type: "reasoning-start",
443
+ id: crypto.randomUUID()
444
+ });
445
+ controller.enqueue({
446
+ type: "reasoning-delta",
447
+ id: crypto.randomUUID(),
448
+ delta: chunk.message.thinking
449
+ });
450
+ controller.enqueue({
451
+ type: "reasoning-end",
452
+ id: crypto.randomUUID()
453
+ });
454
+ }
367
455
  if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
368
456
  for (const toolCall of chunk.message.tool_calls) {
369
457
  const toolInput = toolCall.function.arguments || {};
@@ -375,7 +463,8 @@ var OllamaChatLanguageModel = class {
375
463
  input: JSON.stringify(toolInput)
376
464
  });
377
465
  }
378
- } else if (chunk.message.content && typeof chunk.message.content === "string") {
466
+ }
467
+ if (chunk.message.content && typeof chunk.message.content === "string" && chunk.message.content.length > 0) {
379
468
  controller.enqueue({
380
469
  type: "text-delta",
381
470
  id: crypto.randomUUID(),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.ts","../src/utils/convert-to-ollama-messages.ts","../src/utils/map-ollama-finish-reason.ts","../src/utils/ollama-error.ts","../src/models/chat-language-model.ts","../src/models/embedding-model.ts"],"sourcesContent":["import {\n LanguageModelV2,\n EmbeddingModelV2,\n ProviderV2,\n NoSuchModelError,\n} from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaChatLanguageModel } from './models/chat-language-model';\nimport { OllamaEmbeddingModel } from './models/embedding-model';\n\nexport interface OllamaProviderSettings {\n /**\n * Base URL for the Ollama API (defaults to http://127.0.0.1:11434)\n */\n baseURL?: string;\n\n /**\n * Custom headers for API requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\nexport interface OllamaProvider extends ProviderV2 {\n /**\n * Create a language model instance\n */\n (modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `chat` method\n */\n chat(modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `languageModel` method\n */\n languageModel(\n modelId: string,\n settings?: OllamaChatSettings,\n ): LanguageModelV2;\n\n /**\n * Create an embedding model instance\n */\n embedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbedding` method\n */\n textEmbedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbeddingModel` method\n */\n textEmbeddingModel(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n}\n\nexport interface OllamaChatSettings {\n /**\n * Enable structured output mode\n */\n structuredOutputs?: boolean;\n\n /**\n * Additional model parameters\n */\n options?: {\n num_ctx?: number;\n num_predict?: number;\n temperature?: number;\n top_k?: number;\n top_p?: number;\n min_p?: number;\n seed?: number;\n stop?: string[];\n num_keep?: number;\n typical_p?: number;\n repeat_last_n?: number;\n repeat_penalty?: number;\n presence_penalty?: number;\n frequency_penalty?: number;\n mirostat?: number;\n mirostat_tau?: number;\n mirostat_eta?: number;\n penalize_newline?: boolean;\n numa?: boolean;\n num_thread?: number;\n num_gpu?: number;\n main_gpu?: number;\n low_vram?: boolean;\n f16_kv?: boolean;\n vocab_only?: boolean;\n use_mmap?: boolean;\n use_mlock?: boolean;\n };\n}\n\nexport interface OllamaEmbeddingSettings {\n /**\n * Additional embedding parameters\n */\n options?: {\n num_thread?: number;\n };\n}\n\n/**\n * Options for configuring Ollama provider calls\n */\nexport interface OllamaProviderOptions {\n /**\n * Additional headers to include in requests\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Options for configuring Ollama chat model calls\n */\nexport interface OllamaChatProviderOptions extends OllamaProviderOptions {\n /**\n * Enable structured output mode for object generation\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Options for configuring Ollama embedding model calls\n */\nexport interface OllamaEmbeddingProviderOptions extends OllamaProviderOptions {\n /**\n * Maximum number of embeddings to process in a single call\n */\n maxEmbeddingsPerCall?: number;\n}\n\n/**\n * Create an Ollama provider instance\n */\nexport function createOllama(\n options: OllamaProviderSettings = {},\n): OllamaProvider {\n const client = new Ollama({\n host: options.baseURL,\n fetch: options.fetch,\n headers: options.headers,\n });\n\n const createChatModel = (\n modelId: string,\n settings: OllamaChatSettings = {},\n ) => {\n return new OllamaChatLanguageModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const createEmbeddingModel = (\n modelId: string,\n settings: OllamaEmbeddingSettings = {},\n ) => {\n return new OllamaEmbeddingModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const provider = function (modelId: string, settings?: OllamaChatSettings) {\n if (new.target) {\n throw new Error(\n 'The Ollama provider cannot be called with the new keyword.',\n );\n }\n return createChatModel(modelId, settings);\n };\n\n provider.chat = createChatModel;\n provider.languageModel = createChatModel;\n provider.embedding = createEmbeddingModel;\n provider.textEmbedding = createEmbeddingModel;\n provider.textEmbeddingModel = createEmbeddingModel;\n provider.imageModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'imageModel',\n message: 'Image generation is not supported by Ollama',\n });\n };\n\n return provider as OllamaProvider;\n}\n\n/**\n * Default Ollama provider instance\n */\nexport const ollama = createOllama();\n","import { LanguageModelV2Prompt } from '@ai-sdk/provider';\nimport { Message as OllamaMessage } from 'ollama';\n\nexport function convertToOllamaChatMessages(\n prompt: LanguageModelV2Prompt,\n): OllamaMessage[] {\n const messages: OllamaMessage[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case 'system': {\n messages.push({\n role: 'system',\n content: message.content,\n });\n break;\n }\n\n case 'user': {\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user',\n content: message.content,\n });\n } else {\n // Handle multi-part content\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n\n const imageParts = message.content\n .filter(\n (part): part is Extract<typeof part, { type: 'file' }> =>\n part.type === 'file',\n )\n .filter((part) => part.mediaType.startsWith('image/'))\n .map((part) => {\n if (part.data instanceof URL) {\n return part.data.href;\n } else if (typeof part.data === 'string') {\n // If it's already a data URL, extract just the base64 part\n if (part.data.startsWith('data:')) {\n const base64Match = part.data.match(/data:[^;]+;base64,(.+)/);\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n }\n return part.data;\n } else if (part.data instanceof Uint8Array) {\n // Handle Uint8Array by converting to base64 (without data URL prefix)\n return Buffer.from(part.data).toString('base64');\n } else {\n // Fallback for other types\n return String(part.data);\n }\n });\n\n messages.push({\n role: 'user',\n content: textParts,\n images:\n imageParts.length > 0\n ? imageParts.filter((img): img is string => img !== undefined)\n : undefined,\n });\n }\n break;\n }\n\n case 'assistant': {\n let content = '';\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Combine text parts\n content = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('');\n\n // Handle tool calls if present\n const toolCalls = message.content.filter(\n (part) => part.type === 'tool-call',\n );\n if (toolCalls.length > 0) {\n // For now, we'll append tool calls as text since Ollama doesn't have native support\n const toolCallText = toolCalls\n .map((tc) => `[Tool Call: ${tc.toolName}]`)\n .join('\\n');\n if (toolCallText) {\n content = content ? `${content}\\n${toolCallText}` : toolCallText;\n }\n }\n }\n\n messages.push({\n role: 'assistant',\n content,\n });\n break;\n }\n\n case 'tool': {\n // Ollama doesn't have native tool result support, so we'll add it as a user message\n messages.push({\n role: 'user',\n content: `[Tool Result]`,\n });\n break;\n }\n\n default: {\n // Handle unknown message roles\n throw new Error(\n `Unsupported message role: ${(message as { role: string }).role}`,\n );\n }\n }\n }\n\n return messages;\n}\n","import { LanguageModelV2FinishReason } from '@ai-sdk/provider';\n\nexport function mapOllamaFinishReason(\n reason?: string | null,\n): LanguageModelV2FinishReason {\n if (!reason) return 'unknown';\n\n switch (reason) {\n case 'stop': {\n return 'stop';\n }\n case 'length': {\n return 'length';\n }\n default: {\n return 'unknown';\n }\n }\n}\n","export interface OllamaErrorData {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport class OllamaError extends Error {\n readonly cause?: unknown;\n readonly data?: OllamaErrorData;\n\n constructor({\n message,\n cause,\n data,\n }: {\n message: string;\n cause?: unknown;\n data?: OllamaErrorData;\n }) {\n super(message);\n this.name = 'OllamaError';\n this.cause = cause;\n this.data = data;\n }\n\n static isOllamaError(error: unknown): error is OllamaError {\n return error instanceof OllamaError;\n }\n}\n","import {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2CallWarning,\n LanguageModelV2FinishReason,\n LanguageModelV2StreamPart,\n LanguageModelV2Usage,\n LanguageModelV2Content,\n JSONValue,\n} from '@ai-sdk/provider';\nimport { Ollama, Message as OllamaMessage, ChatResponse, Tool } from 'ollama';\nimport { OllamaChatSettings } from '../provider';\nimport { convertToOllamaChatMessages } from '../utils/convert-to-ollama-messages';\nimport { mapOllamaFinishReason } from '../utils/map-ollama-finish-reason';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaChatConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaChatLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly defaultObjectGenerationMode = 'json';\n readonly supportsImages = false;\n readonly supportsVideoURLs = false;\n readonly supportsAudioURLs = false;\n readonly supportsVideoFile = false;\n readonly supportsAudioFile = false;\n readonly supportsImageFile = true;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n constructor(\n public readonly modelId: string,\n public readonly settings: OllamaChatSettings,\n private readonly config: OllamaChatConfig,\n ) {}\n\n get provider(): string {\n return this.config.provider;\n }\n\n get supportsStructuredOutputs(): boolean {\n return this.settings.structuredOutputs ?? false;\n }\n\n private getCallOptions(options: LanguageModelV2CallOptions): {\n messages: OllamaMessage[];\n options: Record<string, unknown>;\n format?: string;\n tools?: Tool[];\n warnings: LanguageModelV2CallWarning[];\n } {\n const {\n prompt,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n seed,\n responseFormat,\n tools,\n } = options;\n\n const warnings: LanguageModelV2CallWarning[] = [];\n\n // Check for unsupported features and throw errors\n if (\n responseFormat?.type === 'json' &&\n responseFormat.schema &&\n !this.supportsStructuredOutputs\n ) {\n throw new Error(\n 'JSON schema is only supported when structuredOutputs is enabled',\n );\n }\n\n // Convert AI SDK tools to Ollama format (error already thrown if unsupported)\n const ollamaTools: Tool[] | undefined = tools\n ? tools.map((tool): Tool => {\n if (tool.type === 'function') {\n // The inputSchema from AI SDK should already be a JSON schema\n // when tools are passed to providers\n let jsonSchema: Record<string, unknown>;\n\n // Check if we have a Zod schema (has parse method) or a JSON schema\n if (tool.inputSchema && typeof tool.inputSchema === 'object') {\n if (\n 'parse' in tool.inputSchema &&\n typeof tool.inputSchema.parse === 'function'\n ) {\n // It's a Zod schema - we need to convert it\n // For now, we'll use a basic fallback since zod-to-json-schema has version issues\n console.warn(\n `Tool ${tool.name} is using a Zod schema directly. Schema conversion may not work properly due to Zod version mismatch.`,\n );\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n } else if (\n 'properties' in tool.inputSchema ||\n 'type' in tool.inputSchema\n ) {\n // It looks like a JSON schema already\n jsonSchema = tool.inputSchema as Record<string, unknown>;\n } else {\n // Unknown schema format\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n } else {\n // No schema provided\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n },\n };\n }\n // Provider-defined tools not supported by Ollama\n throw new Error(\n `Provider-defined tools are not supported by Ollama. Use function tools instead.`,\n );\n })\n : undefined;\n\n // Build options with correct precedence:\n // 1. AI SDK call parameters (mapped to Ollama equivalents)\n // 2. Model settings (Ollama options) override AI SDK parameters when both are specified\n const ollamaOptions: Record<string, unknown> = {\n // Start with AI SDK parameters mapped to Ollama names\n ...(temperature !== undefined && { temperature }),\n ...(maxOutputTokens !== undefined && { num_predict: maxOutputTokens }),\n ...(topP !== undefined && { top_p: topP }),\n ...(topK !== undefined && { top_k: topK }),\n ...(frequencyPenalty !== undefined && {\n frequency_penalty: frequencyPenalty,\n }),\n ...(presencePenalty !== undefined && {\n presence_penalty: presencePenalty,\n }),\n ...(stopSequences !== undefined && { stop: stopSequences }),\n ...(seed !== undefined && { seed }),\n // Ollama model options override AI SDK parameters\n ...this.settings.options,\n };\n\n // Remove undefined values\n for (const key of Object.keys(ollamaOptions)) {\n if (ollamaOptions[key] === undefined) {\n delete ollamaOptions[key];\n }\n }\n\n let format: string | undefined;\n if (responseFormat?.type === 'json') {\n format = 'json';\n }\n\n const messages = convertToOllamaChatMessages(prompt);\n\n return {\n messages,\n options: ollamaOptions,\n format,\n tools: ollamaTools,\n warnings,\n };\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n providerMetadata?: Record<string, Record<string, JSONValue>>;\n request?: { body: string };\n response?: { id?: string; timestamp?: Date; modelId?: string };\n warnings: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const response = (await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: false,\n })) as ChatResponse;\n\n const text = response.message.content;\n const toolCalls = response.message.tool_calls;\n\n // Convert content based on whether we have tool calls\n const content: LanguageModelV2Content[] = [];\n\n if (text) {\n content.push({ type: 'text', text });\n }\n\n if (toolCalls && toolCalls.length > 0) {\n for (const toolCall of toolCalls) {\n const toolInput = toolCall.function.arguments || {};\n\n content.push({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n return {\n content,\n finishReason: mapOllamaFinishReason(\n response.done_reason,\n ) as LanguageModelV2FinishReason,\n usage: {\n inputTokens: response.prompt_eval_count || 0,\n outputTokens: response.eval_count || 0,\n totalTokens:\n (response.prompt_eval_count || 0) + (response.eval_count || 0),\n },\n providerMetadata: {\n ollama: {\n model: response.model,\n created_at: response.created_at\n ? new Date(response.created_at).toISOString()\n : undefined,\n total_duration: response.total_duration,\n load_duration: response.load_duration,\n eval_duration: response.eval_duration,\n } as Record<string, JSONValue>,\n },\n request: {\n body: JSON.stringify({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n }),\n },\n response: {\n timestamp: new Date(),\n modelId: this.modelId,\n },\n warnings,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const stream = await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: true,\n });\n\n let usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n const transformStream = new TransformStream<\n ChatResponse,\n LanguageModelV2StreamPart\n >({\n async transform(chunk: ChatResponse, controller) {\n // Validate chunk\n if (!chunk || typeof chunk !== 'object') {\n return; // Skip invalid chunks\n }\n\n // Regular chunk with content\n if (chunk.done) {\n // Final chunk with metadata\n usage = {\n inputTokens: chunk.prompt_eval_count || 0,\n outputTokens: chunk.eval_count || 0,\n totalTokens:\n (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),\n };\n finishReason = mapOllamaFinishReason(\n chunk.done_reason,\n ) as LanguageModelV2FinishReason;\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n } else {\n // Handle tool calls in streaming\n if (\n chunk.message.tool_calls &&\n chunk.message.tool_calls.length > 0\n ) {\n for (const toolCall of chunk.message.tool_calls) {\n const toolInput = toolCall.function.arguments || {};\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n } else if (\n chunk.message.content &&\n typeof chunk.message.content === 'string'\n ) {\n controller.enqueue({\n type: 'text-delta',\n id: crypto.randomUUID(), // Generate unique ID for each text chunk\n delta: chunk.message.content,\n });\n }\n }\n },\n });\n\n // Create a readable stream from the async generator\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n // Ensure chunk is valid before enqueuing\n if (chunk && typeof chunk === 'object') {\n controller.enqueue(chunk);\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return {\n stream: readableStream.pipeThrough(transformStream),\n rawCall: {\n rawPrompt: messages,\n rawSettings: {\n model: this.modelId,\n options: ollamaOptions,\n format,\n tools,\n },\n },\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n","import { EmbeddingModelV2, EmbeddingModelV2Embedding } from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaEmbeddingSettings } from '../provider';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaEmbeddingConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaEmbeddingModel implements EmbeddingModelV2<string> {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly maxEmbeddingsPerCall = 2048;\n readonly supportsParallelCalls = true;\n\n constructor(\n modelId: string,\n private readonly settings: OllamaEmbeddingSettings,\n private readonly config: OllamaEmbeddingConfig,\n ) {\n this.modelId = modelId;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n async doEmbed(params: {\n values: string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n embeddings: EmbeddingModelV2Embedding[];\n }> {\n const { values, abortSignal } = params;\n if (values.length > this.maxEmbeddingsPerCall) {\n throw new OllamaError({\n message: `Too many values to embed. Maximum: ${this.maxEmbeddingsPerCall}, Received: ${values.length}`,\n });\n }\n\n // Handle empty array case\n if (values.length === 0) {\n return { embeddings: [] };\n }\n\n try {\n const embeddings: EmbeddingModelV2Embedding[] = [];\n\n // Ollama's embed API currently only supports single prompts\n // So we need to make multiple requests\n for (const value of values) {\n // Skip undefined values (AI SDK interface issue workaround)\n if (value === undefined || value === null) {\n continue;\n }\n\n const response = await this.config.client.embed({\n model: this.modelId,\n input: value,\n options: this.settings.options,\n });\n\n if (!response.embeddings) {\n throw new OllamaError({\n message: `No embeddings field in response`,\n });\n }\n\n if (response.embeddings.length === 0) {\n throw new OllamaError({\n message: `Empty embeddings array returned`,\n });\n }\n\n embeddings.push(response.embeddings[0] as number[]);\n\n // Check if we should abort\n if (abortSignal?.aborted) {\n throw new Error('Embedding generation aborted');\n }\n }\n\n if (embeddings.length === 0) {\n throw new OllamaError({\n message: `No valid values provided for embedding (all were undefined/null)`,\n });\n }\n\n return {\n embeddings,\n };\n } catch (error) {\n if (error instanceof OllamaError) {\n throw error;\n }\n\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n"],"mappings":";AAAA;AAAA,EAIE;AAAA,OACK;AACP,SAAS,cAAc;;;ACHhB,SAAS,4BACd,QACiB;AACjB,QAAM,WAA4B,CAAC;AAEnC,aAAW,WAAW,QAAQ;AAC5B,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,UAAU;AACb,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,QACnB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,YAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS,QAAQ;AAAA,UACnB,CAAC;AAAA,QACH,OAAO;AAEL,gBAAM,YAAY,QAAQ,QACvB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK,IAAI;AAEZ,gBAAM,aAAa,QAAQ,QACxB;AAAA,YACC,CAAC,SACC,KAAK,SAAS;AAAA,UAClB,EACC,OAAO,CAAC,SAAS,KAAK,UAAU,WAAW,QAAQ,CAAC,EACpD,IAAI,CAAC,SAAS;AACb,gBAAI,KAAK,gBAAgB,KAAK;AAC5B,qBAAO,KAAK,KAAK;AAAA,YACnB,WAAW,OAAO,KAAK,SAAS,UAAU;AAExC,kBAAI,KAAK,KAAK,WAAW,OAAO,GAAG;AACjC,sBAAM,cAAc,KAAK,KAAK,MAAM,wBAAwB;AAC5D,oBAAI,aAAa;AACf,yBAAO,YAAY,CAAC;AAAA,gBACtB;AAAA,cACF;AACA,qBAAO,KAAK;AAAA,YACd,WAAW,KAAK,gBAAgB,YAAY;AAE1C,qBAAO,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS,QAAQ;AAAA,YACjD,OAAO;AAEL,qBAAO,OAAO,KAAK,IAAI;AAAA,YACzB;AAAA,UACF,CAAC;AAEH,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,QACE,WAAW,SAAS,IAChB,WAAW,OAAO,CAAC,QAAuB,QAAQ,MAAS,IAC3D;AAAA,UACR,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,aAAa;AAChB,YAAI,UAAU;AAEd,YAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,oBAAU,QAAQ;AAAA,QACpB,OAAO;AAEL,oBAAU,QAAQ,QACf,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI,EACvB,KAAK,EAAE;AAGV,gBAAM,YAAY,QAAQ,QAAQ;AAAA,YAChC,CAAC,SAAS,KAAK,SAAS;AAAA,UAC1B;AACA,cAAI,UAAU,SAAS,GAAG;AAExB,kBAAM,eAAe,UAClB,IAAI,CAAC,OAAO,eAAe,GAAG,QAAQ,GAAG,EACzC,KAAK,IAAI;AACZ,gBAAI,cAAc;AAChB,wBAAU,UAAU,GAAG,OAAO;AAAA,EAAK,YAAY,KAAK;AAAA,YACtD;AAAA,UACF;AAAA,QACF;AAEA,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AAEX,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AAAA,MAEA,SAAS;AAEP,cAAM,IAAI;AAAA,UACR,6BAA8B,QAA6B,IAAI;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACzHO,SAAS,sBACd,QAC6B;AAC7B,MAAI,CAAC,OAAQ,QAAO;AAEpB,UAAQ,QAAQ;AAAA,IACd,KAAK,QAAQ;AACX,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,aAAO;AAAA,IACT;AAAA,IACA,SAAS;AACP,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACZO,IAAM,cAAN,MAAM,qBAAoB,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EAET,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIG;AACD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,OAAO,cAAc,OAAsC;AACzD,WAAO,iBAAiB;AAAA,EAC1B;AACF;;;ACPO,IAAM,0BAAN,MAAyD;AAAA,EAW9D,YACkB,SACA,UACC,QACjB;AAHgB;AACA;AACC;AAAA,EAChB;AAAA,EAdM,uBAAuB;AAAA,EACvB,8BAA8B;AAAA,EAC9B,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,gBAA0C,CAAC;AAAA,EAQpD,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAI,4BAAqC;AACvC,WAAO,KAAK,SAAS,qBAAqB;AAAA,EAC5C;AAAA,EAEQ,eAAe,SAMrB;AACA,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AAEJ,UAAM,WAAyC,CAAC;AAGhD,QACE,gBAAgB,SAAS,UACzB,eAAe,UACf,CAAC,KAAK,2BACN;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,cAAkC,QACpC,MAAM,IAAI,CAAC,SAAe;AACxB,UAAI,KAAK,SAAS,YAAY;AAG5B,YAAI;AAGJ,YAAI,KAAK,eAAe,OAAO,KAAK,gBAAgB,UAAU;AAC5D,cACE,WAAW,KAAK,eAChB,OAAO,KAAK,YAAY,UAAU,YAClC;AAGA,oBAAQ;AAAA,cACN,QAAQ,KAAK,IAAI;AAAA,YACnB;AACA,yBAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY,CAAC;AAAA,cACb,sBAAsB;AAAA,YACxB;AAAA,UACF,WACE,gBAAgB,KAAK,eACrB,UAAU,KAAK,aACf;AAEA,yBAAa,KAAK;AAAA,UACpB,OAAO;AAEL,yBAAa;AAAA,cACX,MAAM;AAAA,cACN,YAAY,CAAC;AAAA,cACb,sBAAsB;AAAA,YACxB;AAAA,UACF;AAAA,QACF,OAAO;AAEL,uBAAa;AAAA,YACX,MAAM;AAAA,YACN,YAAY,CAAC;AAAA,YACb,sBAAsB;AAAA,UACxB;AAAA,QACF;AAEA,eAAO;AAAA,UACL,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,KAAK;AAAA,YACX,aAAa,KAAK;AAAA,YAClB,YAAY;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAC,IACD;AAKJ,UAAM,gBAAyC;AAAA;AAAA,MAE7C,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,MAC/C,GAAI,oBAAoB,UAAa,EAAE,aAAa,gBAAgB;AAAA,MACpE,GAAI,SAAS,UAAa,EAAE,OAAO,KAAK;AAAA,MACxC,GAAI,SAAS,UAAa,EAAE,OAAO,KAAK;AAAA,MACxC,GAAI,qBAAqB,UAAa;AAAA,QACpC,mBAAmB;AAAA,MACrB;AAAA,MACA,GAAI,oBAAoB,UAAa;AAAA,QACnC,kBAAkB;AAAA,MACpB;AAAA,MACA,GAAI,kBAAkB,UAAa,EAAE,MAAM,cAAc;AAAA,MACzD,GAAI,SAAS,UAAa,EAAE,KAAK;AAAA;AAAA,MAEjC,GAAG,KAAK,SAAS;AAAA,IACnB;AAGA,eAAW,OAAO,OAAO,KAAK,aAAa,GAAG;AAC5C,UAAI,cAAc,GAAG,MAAM,QAAW;AACpC,eAAO,cAAc,GAAG;AAAA,MAC1B;AAAA,IACF;AAEA,QAAI;AACJ,QAAI,gBAAgB,SAAS,QAAQ;AACnC,eAAS;AAAA,IACX;AAEA,UAAM,WAAW,4BAA4B,MAAM;AAEnD,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAQd;AACD,UAAM;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,KAAK,eAAe,OAAO;AAE/B,QAAI;AACF,YAAM,WAAY,MAAM,KAAK,OAAO,OAAO,KAAK;AAAA,QAC9C,OAAO,KAAK;AAAA,QACZ;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAED,YAAM,OAAO,SAAS,QAAQ;AAC9B,YAAM,YAAY,SAAS,QAAQ;AAGnC,YAAM,UAAoC,CAAC;AAE3C,UAAI,MAAM;AACR,gBAAQ,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MACrC;AAEA,UAAI,aAAa,UAAU,SAAS,GAAG;AACrC,mBAAW,YAAY,WAAW;AAChC,gBAAM,YAAY,SAAS,SAAS,aAAa,CAAC;AAElD,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,YAAY,OAAO,WAAW;AAAA;AAAA,YAC9B,UAAU,SAAS,SAAS;AAAA,YAC5B,OAAO,KAAK,UAAU,SAAS;AAAA,UACjC,CAAC;AAAA,QACH;AAAA,MACF;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc;AAAA,UACZ,SAAS;AAAA,QACX;AAAA,QACA,OAAO;AAAA,UACL,aAAa,SAAS,qBAAqB;AAAA,UAC3C,cAAc,SAAS,cAAc;AAAA,UACrC,cACG,SAAS,qBAAqB,MAAM,SAAS,cAAc;AAAA,QAChE;AAAA,QACA,kBAAkB;AAAA,UAChB,QAAQ;AAAA,YACN,OAAO,SAAS;AAAA,YAChB,YAAY,SAAS,aACjB,IAAI,KAAK,SAAS,UAAU,EAAE,YAAY,IAC1C;AAAA,YACJ,gBAAgB,SAAS;AAAA,YACzB,eAAe,SAAS;AAAA,YACxB,eAAe,SAAS;AAAA,UAC1B;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP,MAAM,KAAK,UAAU;AAAA,YACnB,OAAO,KAAK;AAAA,YACZ;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAAA,QACA,UAAU;AAAA,UACR,WAAW,oBAAI,KAAK;AAAA,UACpB,SAAS,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAOZ;AACD,UAAM;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI,KAAK,eAAe,OAAO;AAE/B,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO,OAAO,KAAK;AAAA,QAC3C,OAAO,KAAK;AAAA,QACZ;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAED,UAAI,QAA8B;AAAA,QAChC,aAAa;AAAA,QACb,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AACA,UAAI,eAA4C;AAEhD,YAAM,kBAAkB,IAAI,gBAG1B;AAAA,QACA,MAAM,UAAU,OAAqB,YAAY;AAE/C,cAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC;AAAA,UACF;AAGA,cAAI,MAAM,MAAM;AAEd,oBAAQ;AAAA,cACN,aAAa,MAAM,qBAAqB;AAAA,cACxC,cAAc,MAAM,cAAc;AAAA,cAClC,cACG,MAAM,qBAAqB,MAAM,MAAM,cAAc;AAAA,YAC1D;AACA,2BAAe;AAAA,cACb,MAAM;AAAA,YACR;AAEA,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,cACA;AAAA,YACF,CAAC;AAAA,UACH,OAAO;AAEL,gBACE,MAAM,QAAQ,cACd,MAAM,QAAQ,WAAW,SAAS,GAClC;AACA,yBAAW,YAAY,MAAM,QAAQ,YAAY;AAC/C,sBAAM,YAAY,SAAS,SAAS,aAAa,CAAC;AAElD,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,YAAY,OAAO,WAAW;AAAA;AAAA,kBAC9B,UAAU,SAAS,SAAS;AAAA,kBAC5B,OAAO,KAAK,UAAU,SAAS;AAAA,gBACjC,CAAC;AAAA,cACH;AAAA,YACF,WACE,MAAM,QAAQ,WACd,OAAO,MAAM,QAAQ,YAAY,UACjC;AACA,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,OAAO,WAAW;AAAA;AAAA,gBACtB,OAAO,MAAM,QAAQ;AAAA,cACvB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAGD,YAAM,iBAAiB,IAAI,eAAe;AAAA,QACxC,MAAM,MAAM,YAAY;AACtB,cAAI;AACF,6BAAiB,SAAS,QAAQ;AAEhC,kBAAI,SAAS,OAAO,UAAU,UAAU;AACtC,2BAAW,QAAQ,KAAK;AAAA,cAC1B;AAAA,YACF;AACA,uBAAW,MAAM;AAAA,UACnB,SAAS,OAAO;AACd,uBAAW,MAAM,KAAK;AAAA,UACxB;AAAA,QACF;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,QAAQ,eAAe,YAAY,eAAe;AAAA,QAClD,SAAS;AAAA,UACP,WAAW;AAAA,UACX,aAAa;AAAA,YACX,OAAO,KAAK;AAAA,YACZ,SAAS;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,QACA,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,MAC7C;AAAA,IACF,SAAS,OAAO;AACd,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AChZO,IAAM,uBAAN,MAA+D;AAAA,EAMpE,YACE,SACiB,UACA,QACjB;AAFiB;AACA;AAEjB,SAAK,UAAU;AAAA,EACjB;AAAA,EAXS,uBAAuB;AAAA,EACvB;AAAA,EACA,uBAAuB;AAAA,EACvB,wBAAwB;AAAA,EAUjC,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,MAAM,QAAQ,QAKX;AACD,UAAM,EAAE,QAAQ,YAAY,IAAI;AAChC,QAAI,OAAO,SAAS,KAAK,sBAAsB;AAC7C,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,sCAAsC,KAAK,oBAAoB,eAAe,OAAO,MAAM;AAAA,MACtG,CAAC;AAAA,IACH;AAGA,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO,EAAE,YAAY,CAAC,EAAE;AAAA,IAC1B;AAEA,QAAI;AACF,YAAM,aAA0C,CAAC;AAIjD,iBAAW,SAAS,QAAQ;AAE1B,YAAI,UAAU,UAAa,UAAU,MAAM;AACzC;AAAA,QACF;AAEA,cAAM,WAAW,MAAM,KAAK,OAAO,OAAO,MAAM;AAAA,UAC9C,OAAO,KAAK;AAAA,UACZ,OAAO;AAAA,UACP,SAAS,KAAK,SAAS;AAAA,QACzB,CAAC;AAED,YAAI,CAAC,SAAS,YAAY;AACxB,gBAAM,IAAI,YAAY;AAAA,YACpB,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,YAAI,SAAS,WAAW,WAAW,GAAG;AACpC,gBAAM,IAAI,YAAY;AAAA,YACpB,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAEA,mBAAW,KAAK,SAAS,WAAW,CAAC,CAAa;AAGlD,YAAI,aAAa,SAAS;AACxB,gBAAM,IAAI,MAAM,8BAA8B;AAAA,QAChD;AAAA,MACF;AAEA,UAAI,WAAW,WAAW,GAAG;AAC3B,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AAEA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ALkDO,SAAS,aACd,UAAkC,CAAC,GACnB;AAChB,QAAM,SAAS,IAAI,OAAO;AAAA,IACxB,MAAM,QAAQ;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,SAAS,QAAQ;AAAA,EACnB,CAAC;AAED,QAAM,kBAAkB,CACtB,SACA,WAA+B,CAAC,MAC7B;AACH,WAAO,IAAI,wBAAwB,SAAS,UAAU;AAAA,MACpD;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,uBAAuB,CAC3B,SACA,WAAoC,CAAC,MAClC;AACH,WAAO,IAAI,qBAAqB,SAAS,UAAU;AAAA,MACjD;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,SAAU,SAAiB,UAA+B;AACzE,QAAI,YAAY;AACd,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,gBAAgB,SAAS,QAAQ;AAAA,EAC1C;AAEA,WAAS,OAAO;AAChB,WAAS,gBAAgB;AACzB,WAAS,YAAY;AACrB,WAAS,gBAAgB;AACzB,WAAS,qBAAqB;AAC9B,WAAS,aAAa,CAAC,YAAoB;AACzC,UAAM,IAAI,iBAAiB;AAAA,MACzB;AAAA,MACA,WAAW;AAAA,MACX,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAKO,IAAM,SAAS,aAAa;","names":[]}
1
+ {"version":3,"sources":["../src/provider.ts","../src/utils/convert-to-ollama-messages.ts","../src/utils/map-ollama-finish-reason.ts","../src/utils/ollama-error.ts","../src/models/chat-language-model.ts","../src/models/embedding-model.ts"],"sourcesContent":["import {\n LanguageModelV2,\n EmbeddingModelV2,\n ProviderV2,\n NoSuchModelError,\n} from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaChatLanguageModel } from './models/chat-language-model';\nimport { OllamaEmbeddingModel } from './models/embedding-model';\n\nexport interface OllamaProviderSettings {\n /**\n * Base URL for the Ollama API (defaults to http://127.0.0.1:11434)\n */\n baseURL?: string;\n\n /**\n * Custom headers for API requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n}\n\nexport interface OllamaProvider extends ProviderV2 {\n /**\n * Create a language model instance\n */\n (modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `chat` method\n */\n chat(modelId: string, settings?: OllamaChatSettings): LanguageModelV2;\n\n /**\n * Create a language model instance with the `languageModel` method\n */\n languageModel(\n modelId: string,\n settings?: OllamaChatSettings,\n ): LanguageModelV2;\n\n /**\n * Create an embedding model instance\n */\n embedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbedding` method\n */\n textEmbedding(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n\n /**\n * Create an embedding model instance with the `textEmbeddingModel` method\n */\n textEmbeddingModel(\n modelId: string,\n settings?: OllamaEmbeddingSettings,\n ): EmbeddingModelV2<string>;\n}\n\nexport interface OllamaChatSettings {\n /**\n * Enable structured output mode\n */\n structuredOutputs?: boolean;\n\n /**\n * Enable reasoning support for models that support it\n */\n reasoning?: boolean;\n\n /**\n * Additional model parameters\n */\n options?: {\n num_ctx?: number;\n num_predict?: number;\n temperature?: number;\n top_k?: number;\n top_p?: number;\n min_p?: number;\n seed?: number;\n stop?: string[];\n num_keep?: number;\n typical_p?: number;\n repeat_last_n?: number;\n repeat_penalty?: number;\n presence_penalty?: number;\n frequency_penalty?: number;\n mirostat?: number;\n mirostat_tau?: number;\n mirostat_eta?: number;\n penalize_newline?: boolean;\n numa?: boolean;\n num_thread?: number;\n num_gpu?: number;\n main_gpu?: number;\n low_vram?: boolean;\n f16_kv?: boolean;\n vocab_only?: boolean;\n use_mmap?: boolean;\n use_mlock?: boolean;\n };\n}\n\nexport interface OllamaEmbeddingSettings {\n /**\n * Additional embedding parameters\n */\n options?: {\n num_thread?: number;\n };\n}\n\n/**\n * Options for configuring Ollama provider calls\n */\nexport interface OllamaProviderOptions {\n /**\n * Additional headers to include in requests\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Options for configuring Ollama chat model calls\n */\nexport interface OllamaChatProviderOptions extends OllamaProviderOptions {\n /**\n * Enable structured output mode for object generation\n */\n structuredOutputs?: boolean;\n}\n\n/**\n * Options for configuring Ollama embedding model calls\n */\nexport interface OllamaEmbeddingProviderOptions extends OllamaProviderOptions {\n /**\n * Maximum number of embeddings to process in a single call\n */\n maxEmbeddingsPerCall?: number;\n}\n\n/**\n * Create an Ollama provider instance\n */\nexport function createOllama(\n options: OllamaProviderSettings = {},\n): OllamaProvider {\n const client = new Ollama({\n host: options.baseURL,\n fetch: options.fetch,\n headers: options.headers,\n });\n\n const createChatModel = (\n modelId: string,\n settings: OllamaChatSettings = {},\n ) => {\n return new OllamaChatLanguageModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const createEmbeddingModel = (\n modelId: string,\n settings: OllamaEmbeddingSettings = {},\n ) => {\n return new OllamaEmbeddingModel(modelId, settings, {\n client,\n provider: 'ollama',\n });\n };\n\n const provider = function (modelId: string, settings?: OllamaChatSettings) {\n if (new.target) {\n throw new Error(\n 'The Ollama provider cannot be called with the new keyword.',\n );\n }\n return createChatModel(modelId, settings);\n };\n\n provider.chat = createChatModel;\n provider.languageModel = createChatModel;\n provider.embedding = createEmbeddingModel;\n provider.textEmbedding = createEmbeddingModel;\n provider.textEmbeddingModel = createEmbeddingModel;\n provider.imageModel = (modelId: string) => {\n throw new NoSuchModelError({\n modelId,\n modelType: 'imageModel',\n message: 'Image generation is not supported by Ollama',\n });\n };\n\n return provider as OllamaProvider;\n}\n\n/**\n * Default Ollama provider instance\n */\nexport const ollama = createOllama();\n","import { LanguageModelV2Prompt } from '@ai-sdk/provider';\nimport { Message as OllamaMessage } from 'ollama';\n\n/**\n * Enhanced message conversion that supports all Ollama capabilities\n * and handles edge cases better than the referenced implementation\n */\nexport function convertToOllamaChatMessages(\n prompt: LanguageModelV2Prompt,\n): OllamaMessage[] {\n const messages: OllamaMessage[] = [];\n\n for (const message of prompt) {\n switch (message.role) {\n case 'system': {\n messages.push({\n role: 'system',\n content: message.content,\n });\n break;\n }\n\n case 'user': {\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user',\n content: message.content,\n });\n } else {\n // Handle multi-part content with enhanced image support\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n\n const imageParts = message.content\n .filter(\n (part): part is Extract<typeof part, { type: 'file' }> =>\n part.type === 'file',\n )\n .filter((part) => {\n // Support image files only\n return part.mediaType?.startsWith('image/') || false;\n })\n .map((part) => {\n const imageData = part.data;\n\n if (imageData instanceof URL) {\n // Handle image URLs - extract base64 from data URLs or use URL directly\n if (imageData.protocol === 'data:') {\n const base64Match = imageData.href.match(\n /data:[^;]+;base64,(.+)/,\n );\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n // If no base64 match, return the full data URL\n return imageData.href;\n }\n // For HTTP URLs, return as-is (Ollama will handle them)\n return imageData.href;\n } else if (typeof imageData === 'string') {\n // Handle base64 strings\n if (imageData.startsWith('data:')) {\n const base64Match = imageData.match(/data:[^;]+;base64,(.+)/);\n if (base64Match) {\n return base64Match[1]; // Return just the base64 part\n }\n }\n return imageData;\n } else if (imageData instanceof Uint8Array) {\n // Handle Uint8Array by converting to base64\n return Buffer.from(imageData).toString('base64');\n } else {\n // Fallback for other types\n console.warn(\n `Unsupported image data type: ${typeof imageData}`,\n );\n return null;\n }\n })\n .filter((img): img is string => img !== null);\n\n messages.push({\n role: 'user',\n content: textParts || '', // Ensure content is never undefined\n images: imageParts.length > 0 ? imageParts : undefined,\n });\n }\n break;\n }\n\n case 'assistant': {\n let content = '';\n\n if (typeof message.content === 'string') {\n content = message.content;\n } else {\n // Enhanced content handling with better tool call support\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('');\n\n const reasoningParts = message.content\n .filter((part) => part.type === 'reasoning')\n .map((part) => part.text)\n .join('\\n');\n\n // Combine text and reasoning\n content = [textParts, reasoningParts].filter(Boolean).join('\\n');\n\n // Handle tool calls if present\n const toolCalls = message.content.filter(\n (part) => part.type === 'tool-call',\n );\n if (toolCalls.length > 0) {\n // For now, we'll append tool calls as text since Ollama doesn't have native support\n const toolCallText = toolCalls\n .map((tc) => `[Tool Call: ${tc.toolName}]`)\n .join('\\n');\n if (toolCallText) {\n content = content ? `${content}\\n${toolCallText}` : toolCallText;\n }\n }\n }\n\n messages.push({\n role: 'assistant',\n content: content || '', // Ensure content is never undefined\n });\n break;\n }\n\n case 'tool': {\n // Enhanced tool result handling\n if (typeof message.content === 'string') {\n messages.push({\n role: 'user', // Ollama doesn't have native tool role, so we use user\n content: `[Tool Result]: ${message.content}`,\n });\n } else {\n // Handle multi-part tool results\n const toolResultParts = message.content\n .filter((part) => part.type === 'tool-result')\n .map((part) => {\n if (part.output.type === 'text') {\n return part.output.value;\n } else if (part.output.type === 'json') {\n return JSON.stringify(part.output.value);\n }\n return String(part.output.value);\n })\n .join('\\n');\n\n messages.push({\n role: 'user',\n content: `[Tool Result]: ${toolResultParts || ''}`,\n });\n }\n break;\n }\n\n default: {\n // Enhanced error handling with more descriptive messages\n const role = (message as { role: string }).role;\n throw new Error(\n `Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`,\n );\n }\n }\n }\n\n return messages;\n}\n","import { LanguageModelV2FinishReason } from '@ai-sdk/provider';\n\nexport function mapOllamaFinishReason(\n reason?: string | null,\n): LanguageModelV2FinishReason {\n if (!reason) return 'unknown';\n\n switch (reason) {\n case 'stop': {\n return 'stop';\n }\n case 'length': {\n return 'length';\n }\n default: {\n return 'unknown';\n }\n }\n}\n","export interface OllamaErrorData {\n message: string;\n code?: string;\n details?: unknown;\n}\n\nexport class OllamaError extends Error {\n readonly cause?: unknown;\n readonly data?: OllamaErrorData;\n\n constructor({\n message,\n cause,\n data,\n }: {\n message: string;\n cause?: unknown;\n data?: OllamaErrorData;\n }) {\n super(message);\n this.name = 'OllamaError';\n this.cause = cause;\n this.data = data;\n }\n\n static isOllamaError(error: unknown): error is OllamaError {\n return error instanceof OllamaError;\n }\n}\n","import {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2CallWarning,\n LanguageModelV2FinishReason,\n LanguageModelV2StreamPart,\n LanguageModelV2Usage,\n LanguageModelV2Content,\n JSONValue,\n} from '@ai-sdk/provider';\nimport { Ollama, Message as OllamaMessage, ChatResponse, Tool } from 'ollama';\nimport { OllamaChatSettings } from '../provider';\nimport { convertToOllamaChatMessages } from '../utils/convert-to-ollama-messages';\nimport { mapOllamaFinishReason } from '../utils/map-ollama-finish-reason';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaChatConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaChatLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly defaultObjectGenerationMode = 'json';\n readonly supportsImages = true; // โœ… Ollama supports images (URLs, files, base64)\n readonly supportsVideoURLs = false; // โŒ Not supported by Ollama API\n readonly supportsAudioURLs = false; // โŒ Not supported by Ollama API\n readonly supportsVideoFile = false; // โŒ Not supported by Ollama API\n readonly supportsAudioFile = false; // โŒ Not supported by Ollama API\n readonly supportsImageFile = true; // โœ… Already correct\n readonly supportedUrls: Record<string, RegExp[]> = {\n // Support common image URL patterns\n image: [\n /^https?:\\/\\/.*\\.(jpg|jpeg|png|gif|webp|bmp|svg)(\\?.*)?$/i,\n /^data:image\\/[^;]+;base64,/i, // Data URLs\n ],\n };\n\n constructor(\n public readonly modelId: string,\n public readonly settings: OllamaChatSettings,\n private readonly config: OllamaChatConfig,\n ) {}\n\n get provider(): string {\n return this.config.provider;\n }\n\n get supportsStructuredOutputs(): boolean {\n // Auto-detect structured outputs when JSON schema is provided\n // This allows generateObject and streamObject to work without explicit structuredOutputs: true\n return this.settings.structuredOutputs ?? false;\n }\n\n /**\n * Check if structured outputs should be enabled based on the call options\n * This is used internally to auto-detect when structured outputs are needed\n */\n private shouldEnableStructuredOutputs(\n options: LanguageModelV2CallOptions,\n ): boolean {\n // Auto-detect: if we have a JSON schema, we need structured outputs\n // This overrides explicit settings to ensure object generation works\n if (\n options.responseFormat?.type === 'json' &&\n options.responseFormat.schema\n ) {\n // Warn if structuredOutputs was explicitly set to false but we're auto-enabling it\n if (this.settings.structuredOutputs === false) {\n console.warn(\n 'Ollama: structuredOutputs was set to false but auto-enabled for object generation. ' +\n 'This ensures generateObject and streamObject work correctly.',\n );\n }\n return true;\n }\n\n // If explicitly set, use that value (for text generation)\n if (this.settings.structuredOutputs !== undefined) {\n return this.settings.structuredOutputs;\n }\n\n // Default to false for regular text generation\n return false;\n }\n\n private getCallOptions(options: LanguageModelV2CallOptions): {\n messages: OllamaMessage[];\n options: Record<string, unknown>;\n format?: string | Record<string, unknown>;\n tools?: Tool[];\n warnings: LanguageModelV2CallWarning[];\n } {\n const {\n prompt,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n seed,\n responseFormat,\n tools,\n } = options;\n\n const warnings: LanguageModelV2CallWarning[] = [];\n\n // Auto-detect structured outputs when JSON schema is provided\n const needsStructuredOutputs = this.shouldEnableStructuredOutputs(options);\n\n // Check for unsupported features and throw errors\n if (\n responseFormat?.type === 'json' &&\n responseFormat.schema &&\n !needsStructuredOutputs\n ) {\n throw new Error(\n 'JSON schema is only supported when structuredOutputs is enabled',\n );\n }\n\n // Convert AI SDK tools to Ollama format (error already thrown if unsupported)\n const ollamaTools: Tool[] | undefined = tools\n ? tools.map((tool): Tool => {\n if (tool.type === 'function') {\n // The inputSchema from AI SDK should already be a JSON schema\n // when tools are passed to providers\n let jsonSchema: Record<string, unknown>;\n\n // Check if we have a Zod schema (has parse method) or a JSON schema\n if (tool.inputSchema && typeof tool.inputSchema === 'object') {\n if (\n 'parse' in tool.inputSchema &&\n typeof tool.inputSchema.parse === 'function'\n ) {\n // It's a Zod schema - we need to convert it\n // For now, we'll use a basic fallback since zod-to-json-schema has version issues\n console.warn(\n `Tool ${tool.name} is using a Zod schema directly. Schema conversion may not work properly due to Zod version mismatch.`,\n );\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n } else if (\n 'properties' in tool.inputSchema ||\n 'type' in tool.inputSchema\n ) {\n // It looks like a JSON schema already\n jsonSchema = tool.inputSchema as Record<string, unknown>;\n } else {\n // Unknown schema format\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n } else {\n // No schema provided\n jsonSchema = {\n type: 'object',\n properties: {},\n additionalProperties: false,\n };\n }\n\n return {\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: jsonSchema,\n },\n };\n }\n // Provider-defined tools not supported by Ollama\n throw new Error(\n `Provider-defined tools are not supported by Ollama. Use function tools instead.`,\n );\n })\n : undefined;\n\n // Build options with correct precedence:\n // 1. AI SDK call parameters (mapped to Ollama equivalents)\n // 2. Model settings (Ollama options) override AI SDK parameters when both are specified\n const ollamaOptions: Record<string, unknown> = {\n // Start with AI SDK parameters mapped to Ollama names\n ...(temperature !== undefined && { temperature }),\n ...(maxOutputTokens !== undefined && { num_predict: maxOutputTokens }),\n ...(topP !== undefined && { top_p: topP }),\n ...(topK !== undefined && { top_k: topK }),\n ...(frequencyPenalty !== undefined && {\n frequency_penalty: frequencyPenalty,\n }),\n ...(presencePenalty !== undefined && {\n presence_penalty: presencePenalty,\n }),\n ...(stopSequences !== undefined && { stop: stopSequences }),\n ...(seed !== undefined && { seed }),\n // Ollama model options override AI SDK parameters\n ...this.settings.options,\n };\n\n // Remove undefined values\n for (const key of Object.keys(ollamaOptions)) {\n if (ollamaOptions[key] === undefined) {\n delete ollamaOptions[key];\n }\n }\n\n let format: string | Record<string, unknown> | undefined;\n if (responseFormat?.type === 'json') {\n format =\n responseFormat.schema && needsStructuredOutputs\n ? (responseFormat.schema as Record<string, unknown>)\n : 'json';\n }\n\n const messages = convertToOllamaChatMessages(prompt);\n\n return {\n messages,\n options: ollamaOptions,\n format,\n tools: ollamaTools,\n warnings,\n };\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n providerMetadata?: Record<string, Record<string, JSONValue>>;\n request?: { body: string };\n response?: { id?: string; timestamp?: Date; modelId?: string };\n warnings: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const response = (await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: false,\n })) as ChatResponse;\n\n const text = response.message.content;\n const toolCalls = response.message.tool_calls;\n const thinking = response.message.thinking;\n\n // Convert content based on whether we have tool calls, reasoning, or text\n const content: LanguageModelV2Content[] = [];\n\n // Add reasoning content if present and enabled\n if (thinking && this.settings.reasoning) {\n content.push({ type: 'reasoning', text: thinking });\n }\n\n // Add text content if present\n if (text) {\n content.push({ type: 'text', text });\n }\n\n // Add tool calls if present\n if (toolCalls && toolCalls.length > 0) {\n for (const toolCall of toolCalls) {\n const toolInput = toolCall.function.arguments || {};\n\n content.push({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n return {\n content,\n finishReason: mapOllamaFinishReason(\n response.done_reason,\n ) as LanguageModelV2FinishReason,\n usage: {\n inputTokens: response.prompt_eval_count || 0,\n outputTokens: response.eval_count || 0,\n totalTokens:\n (response.prompt_eval_count || 0) + (response.eval_count || 0),\n },\n providerMetadata: {\n ollama: {\n model: response.model,\n created_at: response.created_at\n ? new Date(response.created_at).toISOString()\n : undefined,\n total_duration: response.total_duration,\n load_duration: response.load_duration,\n eval_duration: response.eval_duration,\n } as Record<string, JSONValue>,\n },\n request: {\n body: JSON.stringify({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n }),\n },\n response: {\n timestamp: new Date(),\n modelId: this.modelId,\n },\n warnings,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n rawCall: {\n rawPrompt: unknown;\n rawSettings: Record<string, unknown>;\n };\n warnings?: LanguageModelV2CallWarning[];\n }> {\n const {\n messages,\n options: ollamaOptions,\n format,\n tools,\n warnings,\n } = this.getCallOptions(options);\n\n try {\n const stream = await this.config.client.chat({\n model: this.modelId,\n messages,\n options: ollamaOptions,\n format,\n tools,\n stream: true,\n });\n\n let usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n // Capture settings for use in transform function\n const reasoningEnabled = this.settings.reasoning;\n\n const transformStream = new TransformStream<\n ChatResponse,\n LanguageModelV2StreamPart\n >({\n async transform(chunk: ChatResponse, controller) {\n // Validate chunk\n if (!chunk || typeof chunk !== 'object') {\n return; // Skip invalid chunks\n }\n\n // Regular chunk with content\n if (chunk.done) {\n // Final chunk with metadata\n usage = {\n inputTokens: chunk.prompt_eval_count || 0,\n outputTokens: chunk.eval_count || 0,\n totalTokens:\n (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),\n };\n finishReason = mapOllamaFinishReason(\n chunk.done_reason,\n ) as LanguageModelV2FinishReason;\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n } else {\n // Handle reasoning in streaming\n if (chunk.message.thinking && reasoningEnabled) {\n // For reasoning, we'll emit it as a single reasoning content\n // since Ollama doesn't stream reasoning in chunks\n controller.enqueue({\n type: 'reasoning-start',\n id: crypto.randomUUID(),\n });\n\n controller.enqueue({\n type: 'reasoning-delta',\n id: crypto.randomUUID(),\n delta: chunk.message.thinking,\n });\n\n controller.enqueue({\n type: 'reasoning-end',\n id: crypto.randomUUID(),\n });\n }\n\n // Handle tool calls in streaming\n if (\n chunk.message.tool_calls &&\n chunk.message.tool_calls.length > 0\n ) {\n for (const toolCall of chunk.message.tool_calls) {\n const toolInput = toolCall.function.arguments || {};\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: crypto.randomUUID(), // Ollama doesn't provide IDs\n toolName: toolCall.function.name,\n input: JSON.stringify(toolInput),\n });\n }\n }\n\n // Handle text content in streaming (always emit if present)\n if (\n chunk.message.content &&\n typeof chunk.message.content === 'string' &&\n chunk.message.content.length > 0\n ) {\n controller.enqueue({\n type: 'text-delta',\n id: crypto.randomUUID(), // Generate unique ID for each text chunk\n delta: chunk.message.content,\n });\n }\n }\n },\n });\n\n // Create a readable stream from the async generator\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n // Ensure chunk is valid before enqueuing\n if (chunk && typeof chunk === 'object') {\n controller.enqueue(chunk);\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n\n return {\n stream: readableStream.pipeThrough(transformStream),\n rawCall: {\n rawPrompt: messages,\n rawSettings: {\n model: this.modelId,\n options: ollamaOptions,\n format,\n tools,\n },\n },\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (error) {\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n","import { EmbeddingModelV2, EmbeddingModelV2Embedding } from '@ai-sdk/provider';\nimport { Ollama } from 'ollama';\nimport { OllamaEmbeddingSettings } from '../provider';\nimport { OllamaError } from '../utils/ollama-error';\n\nexport interface OllamaEmbeddingConfig {\n client: Ollama;\n provider: string;\n}\n\nexport class OllamaEmbeddingModel implements EmbeddingModelV2<string> {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly maxEmbeddingsPerCall = 2048;\n readonly supportsParallelCalls = true;\n\n constructor(\n modelId: string,\n private readonly settings: OllamaEmbeddingSettings,\n private readonly config: OllamaEmbeddingConfig,\n ) {\n this.modelId = modelId;\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n async doEmbed(params: {\n values: string[];\n abortSignal?: AbortSignal;\n }): Promise<{\n embeddings: EmbeddingModelV2Embedding[];\n }> {\n const { values, abortSignal } = params;\n if (values.length > this.maxEmbeddingsPerCall) {\n throw new OllamaError({\n message: `Too many values to embed. Maximum: ${this.maxEmbeddingsPerCall}, Received: ${values.length}`,\n });\n }\n\n // Handle empty array case\n if (values.length === 0) {\n return { embeddings: [] };\n }\n\n try {\n const embeddings: EmbeddingModelV2Embedding[] = [];\n\n // Ollama's embed API currently only supports single prompts\n // So we need to make multiple requests\n for (const value of values) {\n // Skip undefined values (AI SDK interface issue workaround)\n if (value === undefined || value === null) {\n continue;\n }\n\n const response = await this.config.client.embed({\n model: this.modelId,\n input: value,\n options: this.settings.options,\n });\n\n if (!response.embeddings) {\n throw new OllamaError({\n message: `No embeddings field in response`,\n });\n }\n\n if (response.embeddings.length === 0) {\n throw new OllamaError({\n message: `Empty embeddings array returned`,\n });\n }\n\n embeddings.push(response.embeddings[0] as number[]);\n\n // Check if we should abort\n if (abortSignal?.aborted) {\n throw new Error('Embedding generation aborted');\n }\n }\n\n if (embeddings.length === 0) {\n throw new OllamaError({\n message: `No valid values provided for embedding (all were undefined/null)`,\n });\n }\n\n return {\n embeddings,\n };\n } catch (error) {\n if (error instanceof OllamaError) {\n throw error;\n }\n\n throw new OllamaError({\n message: error instanceof Error ? error.message : String(error),\n cause: error,\n });\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdk-ollama",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Vercel AI SDK Provider for Ollama using official ollama-js library",
6
6
  "main": "./dist/index.js",
@@ -82,9 +82,11 @@
82
82
  "format": "prettier --write .",
83
83
  "format:check": "prettier --check src/**/*.ts",
84
84
  "type-check": "tsc --noEmit",
85
- "test": "pnpm run test:node && pnpm run test:edge",
86
- "test:node": "vitest run --config vitest.node.config.js",
87
- "test:edge": "vitest run --config vitest.edge.config.js",
85
+ "test": "vitest run --config vitest.unit.config.ts",
86
+ "test:watch": "vitest --config vitest.unit.config.ts",
87
+ "test:integration": "vitest run --config vitest.integration.config.ts",
88
+ "test:integration:watch": "vitest --config vitest.integration.config.ts",
89
+ "test:all": "npm run test && npm run test:integration",
88
90
  "check-format": "prettier --check .",
89
91
  "check-exports": "attw --pack . --ignore-rules false-esm no-resolution",
90
92
  "local-release": "npm run ci && changeset version && changeset publish --access public"