ai-sdk-ollama 0.3.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 +21 -0
- package/README.md +43 -0
- package/dist/index.cjs +93 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +93 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
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
|
+
|
|
3
24
|
## 0.3.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -274,6 +274,48 @@ const { text } = await generateText({
|
|
|
274
274
|
});
|
|
275
275
|
```
|
|
276
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
|
+
|
|
277
319
|
## Common Issues
|
|
278
320
|
|
|
279
321
|
- **Make sure Ollama is running** - Run `ollama serve` before using the provider
|
|
@@ -290,6 +332,7 @@ Works with any model in your Ollama installation:
|
|
|
290
332
|
- **Chat**: `llama3.2`, `mistral`, `phi4-mini`, `qwen2.5`, `codellama`
|
|
291
333
|
- **Vision**: `llava`, `bakllava`, `llama3.2-vision`, `minicpm-v`
|
|
292
334
|
- **Embeddings**: `nomic-embed-text`, `all-minilm`, `mxbai-embed-large`
|
|
335
|
+
- **Reasoning**: `deepseek-r1:7b`, `deepseek-r1:1.5b`, `deepseek-r1:8b`
|
|
293
336
|
|
|
294
337
|
## Testing
|
|
295
338
|
|
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) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
68
|
-
} else if (
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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: ${
|
|
150
|
+
`Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`
|
|
115
151
|
);
|
|
116
152
|
}
|
|
117
153
|
}
|
|
@@ -163,13 +199,26 @@ var OllamaChatLanguageModel = class {
|
|
|
163
199
|
}
|
|
164
200
|
specificationVersion = "v2";
|
|
165
201
|
defaultObjectGenerationMode = "json";
|
|
166
|
-
supportsImages =
|
|
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
|
-
|
|
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
|
}
|
|
@@ -311,7 +360,11 @@ var OllamaChatLanguageModel = class {
|
|
|
311
360
|
});
|
|
312
361
|
const text = response.message.content;
|
|
313
362
|
const toolCalls = response.message.tool_calls;
|
|
363
|
+
const thinking = response.message.thinking;
|
|
314
364
|
const content = [];
|
|
365
|
+
if (thinking && this.settings.reasoning) {
|
|
366
|
+
content.push({ type: "reasoning", text: thinking });
|
|
367
|
+
}
|
|
315
368
|
if (text) {
|
|
316
369
|
content.push({ type: "text", text });
|
|
317
370
|
}
|
|
@@ -391,6 +444,7 @@ var OllamaChatLanguageModel = class {
|
|
|
391
444
|
totalTokens: 0
|
|
392
445
|
};
|
|
393
446
|
let finishReason = "unknown";
|
|
447
|
+
const reasoningEnabled = this.settings.reasoning;
|
|
394
448
|
const transformStream = new TransformStream({
|
|
395
449
|
async transform(chunk, controller) {
|
|
396
450
|
if (!chunk || typeof chunk !== "object") {
|
|
@@ -411,6 +465,21 @@ var OllamaChatLanguageModel = class {
|
|
|
411
465
|
usage
|
|
412
466
|
});
|
|
413
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
|
+
}
|
|
414
483
|
if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
|
|
415
484
|
for (const toolCall of chunk.message.tool_calls) {
|
|
416
485
|
const toolInput = toolCall.function.arguments || {};
|
|
@@ -422,7 +491,8 @@ var OllamaChatLanguageModel = class {
|
|
|
422
491
|
input: JSON.stringify(toolInput)
|
|
423
492
|
});
|
|
424
493
|
}
|
|
425
|
-
}
|
|
494
|
+
}
|
|
495
|
+
if (chunk.message.content && typeof chunk.message.content === "string" && chunk.message.content.length > 0) {
|
|
426
496
|
controller.enqueue({
|
|
427
497
|
type: "text-delta",
|
|
428
498
|
id: crypto.randomUUID(),
|
package/dist/index.cjs.map
CHANGED
|
@@ -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","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 // 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\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 =
|
|
140
|
+
readonly supportsImages = true;
|
|
137
141
|
readonly supportsVideoURLs = false;
|
|
138
142
|
readonly supportsAudioURLs = false;
|
|
139
143
|
readonly supportsVideoFile = false;
|
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 =
|
|
140
|
+
readonly supportsImages = true;
|
|
137
141
|
readonly supportsVideoURLs = false;
|
|
138
142
|
readonly supportsAudioURLs = false;
|
|
139
143
|
readonly supportsVideoFile = false;
|
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) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
40
|
-
} else if (
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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: ${
|
|
122
|
+
`Unsupported message role: ${role}. Supported roles are: system, user, assistant, tool`
|
|
87
123
|
);
|
|
88
124
|
}
|
|
89
125
|
}
|
|
@@ -135,13 +171,26 @@ var OllamaChatLanguageModel = class {
|
|
|
135
171
|
}
|
|
136
172
|
specificationVersion = "v2";
|
|
137
173
|
defaultObjectGenerationMode = "json";
|
|
138
|
-
supportsImages =
|
|
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
|
-
|
|
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
|
}
|
|
@@ -283,7 +332,11 @@ var OllamaChatLanguageModel = class {
|
|
|
283
332
|
});
|
|
284
333
|
const text = response.message.content;
|
|
285
334
|
const toolCalls = response.message.tool_calls;
|
|
335
|
+
const thinking = response.message.thinking;
|
|
286
336
|
const content = [];
|
|
337
|
+
if (thinking && this.settings.reasoning) {
|
|
338
|
+
content.push({ type: "reasoning", text: thinking });
|
|
339
|
+
}
|
|
287
340
|
if (text) {
|
|
288
341
|
content.push({ type: "text", text });
|
|
289
342
|
}
|
|
@@ -363,6 +416,7 @@ var OllamaChatLanguageModel = class {
|
|
|
363
416
|
totalTokens: 0
|
|
364
417
|
};
|
|
365
418
|
let finishReason = "unknown";
|
|
419
|
+
const reasoningEnabled = this.settings.reasoning;
|
|
366
420
|
const transformStream = new TransformStream({
|
|
367
421
|
async transform(chunk, controller) {
|
|
368
422
|
if (!chunk || typeof chunk !== "object") {
|
|
@@ -383,6 +437,21 @@ var OllamaChatLanguageModel = class {
|
|
|
383
437
|
usage
|
|
384
438
|
});
|
|
385
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
|
+
}
|
|
386
455
|
if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
|
|
387
456
|
for (const toolCall of chunk.message.tool_calls) {
|
|
388
457
|
const toolInput = toolCall.function.arguments || {};
|
|
@@ -394,7 +463,8 @@ var OllamaChatLanguageModel = class {
|
|
|
394
463
|
input: JSON.stringify(toolInput)
|
|
395
464
|
});
|
|
396
465
|
}
|
|
397
|
-
}
|
|
466
|
+
}
|
|
467
|
+
if (chunk.message.content && typeof chunk.message.content === "string" && chunk.message.content.length > 0) {
|
|
398
468
|
controller.enqueue({
|
|
399
469
|
type: "text-delta",
|
|
400
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 // 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\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/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":[]}
|