@elizaos/plugin-ollama 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # Ollama Plugin
2
2
 
3
- This plugin provides integration with Ollama's local models through the ElizaOS platform.
3
+ This plugin provides integration with [Ollama](https://ollama.com/)'s local models through the ElizaOS platform. It allows you to leverage locally running LLMs for text generation, embeddings, and object generation.
4
+
5
+ ## Overview
6
+
7
+ Ollama enables running large language models locally on your machine. This plugin connects ElizaOS with your local Ollama installation, giving your characters access to powerful language models running on your own hardware.
8
+
9
+ ## Requirements
10
+
11
+ - [Ollama](https://ollama.com/) installed and running on your system
12
+ - ElizaOS platform
13
+ - At least one Ollama model pulled and available (e.g., `llama3`, `gemma3:latest`)
14
+
15
+ ## Installation
16
+
17
+ 1. Install this plugin in your ElizaOS project:
18
+ ```bash
19
+ bun add @elizaos-plugins/plugin-ollama
20
+ ```
21
+
22
+ 2. Make sure Ollama is running:
23
+ ```bash
24
+ ollama serve
25
+ ```
4
26
 
5
27
  ## Usage
6
28
 
@@ -50,10 +72,18 @@ The plugin provides these model classes:
50
72
  - `OBJECT_SMALL`: JSON object generation with simpler models
51
73
  - `OBJECT_LARGE`: JSON object generation with more complex models
52
74
 
53
- ## Additional Features
75
+ ## API Reference
76
+
77
+ For detailed information about the Ollama API used by this plugin, refer to the [official Ollama API documentation](https://github.com/ollama/ollama/blob/main/docs/api.md).
78
+
79
+
80
+
81
+ ## Features
54
82
 
55
83
  ### Text Generation (Small Model)
56
84
 
85
+ Generate text using smaller, faster models optimized for quick responses:
86
+
57
87
  ```js
58
88
  const text = await runtime.useModel(ModelType.TEXT_SMALL, {
59
89
  prompt: 'What is the nature of reality?',
@@ -63,6 +93,8 @@ const text = await runtime.useModel(ModelType.TEXT_SMALL, {
63
93
 
64
94
  ### Text Generation (Large Model)
65
95
 
96
+ Generate comprehensive text responses using more powerful models for complex tasks:
97
+
66
98
  ```js
67
99
  const text = await runtime.useModel(ModelType.TEXT_LARGE, {
68
100
  prompt: 'Write a detailed explanation of quantum physics',
@@ -76,6 +108,8 @@ const text = await runtime.useModel(ModelType.TEXT_LARGE, {
76
108
 
77
109
  ### Text Embeddings
78
110
 
111
+ Generate vector embeddings for text, which can be used for semantic search or other vector operations:
112
+
79
113
  ```js
80
114
  const embedding = await runtime.useModel(ModelType.TEXT_EMBEDDING, {
81
115
  text: 'Text to embed',
@@ -86,6 +120,8 @@ const embedding = await runtime.useModel(ModelType.TEXT_EMBEDDING, 'Text to embe
86
120
 
87
121
  ### Object Generation (Small Model)
88
122
 
123
+ Generate structured JSON objects using faster models:
124
+
89
125
  ```js
90
126
  const object = await runtime.useModel(ModelType.OBJECT_SMALL, {
91
127
  prompt: 'Generate a JSON object representing a user profile',
@@ -95,9 +131,30 @@ const object = await runtime.useModel(ModelType.OBJECT_SMALL, {
95
131
 
96
132
  ### Object Generation (Large Model)
97
133
 
134
+ Generate complex, detailed JSON objects using more powerful models:
135
+
98
136
  ```js
99
137
  const object = await runtime.useModel(ModelType.OBJECT_LARGE, {
100
138
  prompt: 'Generate a detailed JSON object representing a restaurant',
101
139
  temperature: 0.7, // optional
102
140
  });
103
141
  ```
142
+
143
+ ## Troubleshooting
144
+
145
+ ### Connection Issues
146
+
147
+ - Ensure Ollama is running by testing the `OLLAMA_API_ENDPOINT`
148
+ - Verify the `OLLAMA_API_ENDPOINT` points to the correct host and port
149
+ - Check firewall settings if connecting to a remote Ollama instance
150
+
151
+ ### Model Availability
152
+
153
+ - The plugin will attempt to download models automatically if they're not found
154
+ - You can pre-download models using `ollama pull modelname`
155
+ - Check model availability with `ollama list`
156
+
157
+
158
+ ## License
159
+
160
+ See LICENSE file for details.
package/dist/index.js CHANGED
@@ -2,18 +2,31 @@
2
2
  import { ModelType, logger } from "@elizaos/core";
3
3
  import { generateObject, generateText } from "ai";
4
4
  import { createOllama } from "ollama-ai-provider";
5
- var OLLAMA_API_URL = "http://localhost:11434/api";
6
- async function ensureModelAvailable(runtime, model) {
7
- const baseURL = runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL;
5
+ var OLLAMA_API_URL = "http://localhost:11434";
6
+ function stripEndpointToBaseDomain(endpoint) {
8
7
  try {
9
- const showRes = await fetch(`${baseURL}/show`, {
8
+ const url = new URL(endpoint);
9
+ return `${url.protocol}//${url.host}`;
10
+ } catch (err) {
11
+ logger.error("Error parsing endpoint URL:", err);
12
+ return endpoint;
13
+ }
14
+ }
15
+ function getBaseURL(runtime) {
16
+ const apiEndpoint = runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL;
17
+ return stripEndpointToBaseDomain(apiEndpoint);
18
+ }
19
+ async function ensureModelAvailable(runtime, model, baseURL) {
20
+ const url = baseURL || getBaseURL(runtime);
21
+ try {
22
+ const showRes = await fetch(`${url}/api/show`, {
10
23
  method: "POST",
11
24
  headers: { "Content-Type": "application/json" },
12
25
  body: JSON.stringify({ model })
13
26
  });
14
27
  if (showRes.ok) return;
15
28
  logger.info(`[Ollama] Model ${model} not found locally. Downloading...`);
16
- const pullRes = await fetch(`${baseURL}/pull`, {
29
+ const pullRes = await fetch(`${url}/api/pull`, {
17
30
  method: "POST",
18
31
  headers: { "Content-Type": "application/json" },
19
32
  body: JSON.stringify({ model, stream: false })
@@ -72,30 +85,28 @@ var ollamaPlugin = {
72
85
  models: {
73
86
  [ModelType.TEXT_EMBEDDING]: async (runtime, params) => {
74
87
  try {
88
+ const baseURL = getBaseURL(runtime);
75
89
  const ollama = createOllama({
76
90
  fetch: runtime.fetch,
77
- baseURL: runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL
91
+ baseURL
78
92
  });
79
93
  const modelName = runtime.getSetting("OLLAMA_EMBEDDING_MODEL") || "nomic-embed-text";
80
94
  logger.log(`[Ollama] Using TEXT_EMBEDDING model: ${modelName}`);
81
- await ensureModelAvailable(runtime, modelName);
82
- const text = typeof params === "string" ? params : params?.text || "";
95
+ await ensureModelAvailable(runtime, modelName, baseURL);
96
+ const text = typeof params === "string" ? params : params ? params.text || "" : "";
83
97
  if (!text) {
84
98
  logger.error("No text provided for embedding");
85
99
  return Array(1536).fill(0);
86
100
  }
87
101
  try {
88
- const response = await fetch(
89
- `${runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL}/embeddings`,
90
- {
91
- method: "POST",
92
- headers: { "Content-Type": "application/json" },
93
- body: JSON.stringify({
94
- model: modelName,
95
- prompt: text
96
- })
97
- }
98
- );
102
+ const response = await fetch(`${baseURL}/api/embeddings`, {
103
+ method: "POST",
104
+ headers: { "Content-Type": "application/json" },
105
+ body: JSON.stringify({
106
+ model: modelName,
107
+ prompt: text
108
+ })
109
+ });
99
110
  if (!response.ok) {
100
111
  throw new Error(`Embedding request failed: ${response.statusText}`);
101
112
  }
@@ -116,18 +127,19 @@ var ollamaPlugin = {
116
127
  const frequency_penalty = 0.7;
117
128
  const presence_penalty = 0.7;
118
129
  const max_response_length = 8e3;
130
+ const baseURL = getBaseURL(runtime);
119
131
  const ollama = createOllama({
120
132
  fetch: runtime.fetch,
121
- baseURL: runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL
133
+ baseURL
122
134
  });
123
- const model = runtime.getSetting("OLLAMA_SMALL_MODEL") ?? runtime.getSetting("SMALL_MODEL") ?? "gemma3:latest";
135
+ const model = runtime.getSetting("OLLAMA_SMALL_MODEL") || runtime.getSetting("SMALL_MODEL") || "gemma3:latest";
124
136
  logger.log(`[Ollama] Using TEXT_SMALL model: ${model}`);
125
- await ensureModelAvailable(runtime, model);
137
+ await ensureModelAvailable(runtime, model, baseURL);
126
138
  logger.log("generating text");
127
139
  logger.log(prompt);
128
140
  return await generateOllamaText(ollama, model, {
129
141
  prompt,
130
- system: runtime.character.system ?? void 0,
142
+ system: runtime.character?.system || void 0,
131
143
  temperature,
132
144
  maxTokens: max_response_length,
133
145
  frequencyPenalty: frequency_penalty,
@@ -148,16 +160,17 @@ var ollamaPlugin = {
148
160
  presencePenalty = 0.7
149
161
  }) => {
150
162
  try {
151
- const model = runtime.getSetting("OLLAMA_LARGE_MODEL") ?? runtime.getSetting("LARGE_MODEL") ?? "gemma3:latest";
163
+ const model = runtime.getSetting("OLLAMA_LARGE_MODEL") || runtime.getSetting("LARGE_MODEL") || "gemma3:latest";
164
+ const baseURL = getBaseURL(runtime);
152
165
  const ollama = createOllama({
153
166
  fetch: runtime.fetch,
154
- baseURL: runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL
167
+ baseURL
155
168
  });
156
169
  logger.log(`[Ollama] Using TEXT_LARGE model: ${model}`);
157
- await ensureModelAvailable(runtime, model);
170
+ await ensureModelAvailable(runtime, model, baseURL);
158
171
  return await generateOllamaText(ollama, model, {
159
172
  prompt,
160
- system: runtime.character.system ?? void 0,
173
+ system: runtime.character?.system || void 0,
161
174
  temperature,
162
175
  maxTokens,
163
176
  frequencyPenalty,
@@ -171,13 +184,14 @@ var ollamaPlugin = {
171
184
  },
172
185
  [ModelType.OBJECT_SMALL]: async (runtime, params) => {
173
186
  try {
187
+ const baseURL = getBaseURL(runtime);
174
188
  const ollama = createOllama({
175
189
  fetch: runtime.fetch,
176
- baseURL: runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL
190
+ baseURL
177
191
  });
178
- const model = runtime.getSetting("OLLAMA_SMALL_MODEL") ?? runtime.getSetting("SMALL_MODEL") ?? "gemma3:latest";
192
+ const model = runtime.getSetting("OLLAMA_SMALL_MODEL") || runtime.getSetting("SMALL_MODEL") || "gemma3:latest";
179
193
  logger.log(`[Ollama] Using OBJECT_SMALL model: ${model}`);
180
- await ensureModelAvailable(runtime, model);
194
+ await ensureModelAvailable(runtime, model, baseURL);
181
195
  if (params.schema) {
182
196
  logger.info("Using OBJECT_SMALL without schema validation");
183
197
  }
@@ -189,13 +203,14 @@ var ollamaPlugin = {
189
203
  },
190
204
  [ModelType.OBJECT_LARGE]: async (runtime, params) => {
191
205
  try {
206
+ const baseURL = getBaseURL(runtime);
192
207
  const ollama = createOllama({
193
208
  fetch: runtime.fetch,
194
- baseURL: runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL
209
+ baseURL
195
210
  });
196
- const model = runtime.getSetting("OLLAMA_LARGE_MODEL") ?? runtime.getSetting("LARGE_MODEL") ?? "gemma3:latest";
211
+ const model = runtime.getSetting("OLLAMA_LARGE_MODEL") || runtime.getSetting("LARGE_MODEL") || "gemma3:latest";
197
212
  logger.log(`[Ollama] Using OBJECT_LARGE model: ${model}`);
198
- await ensureModelAvailable(runtime, model);
213
+ await ensureModelAvailable(runtime, model, baseURL);
199
214
  if (params.schema) {
200
215
  logger.info("Using OBJECT_LARGE without schema validation");
201
216
  }
@@ -214,12 +229,12 @@ var ollamaPlugin = {
214
229
  name: "ollama_test_url_validation",
215
230
  fn: async (runtime) => {
216
231
  try {
217
- const baseURL = runtime.getSetting("OLLAMA_API_ENDPOINT") || OLLAMA_API_URL;
218
- const response = await fetch(`${baseURL}/tags`);
232
+ const baseURL = getBaseURL(runtime);
233
+ const response = await fetch(`${baseURL}/api/tags`);
219
234
  const data = await response.json();
220
235
  logger.log(
221
236
  "Models Available:",
222
- data?.models?.length
237
+ data && typeof data === "object" && "models" in data && Array.isArray(data.models) ? data.models.length : 0
223
238
  );
224
239
  if (!response.ok) {
225
240
  logger.error(
@@ -288,7 +303,8 @@ var ollamaPlugin = {
288
303
  try {
289
304
  const object = await runtime.useModel(ModelType.OBJECT_SMALL, {
290
305
  prompt: "Generate a JSON object representing a user profile with name, age, and hobbies",
291
- temperature: 0.7
306
+ temperature: 0.7,
307
+ schema: void 0
292
308
  });
293
309
  logger.log("Generated object:", object);
294
310
  } catch (error) {
@@ -302,7 +318,8 @@ var ollamaPlugin = {
302
318
  try {
303
319
  const object = await runtime.useModel(ModelType.OBJECT_LARGE, {
304
320
  prompt: "Generate a detailed JSON object representing a restaurant with name, cuisine type, menu items with prices, and customer reviews",
305
- temperature: 0.7
321
+ temperature: 0.7,
322
+ schema: void 0
306
323
  });
307
324
  logger.log("Generated object:", object);
308
325
  } catch (error) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n ObjectGenerationParams,\n Plugin,\n TextEmbeddingParams,\n} from '@elizaos/core';\nimport { type GenerateTextParams, ModelType, logger } from '@elizaos/core';\nimport { generateObject, generateText } from 'ai';\nimport { createOllama } from 'ollama-ai-provider';\n\n// Default Ollama API URL\nconst OLLAMA_API_URL = 'http://localhost:11434/api';\n\nasync function ensureModelAvailable(\n runtime: {\n fetch: typeof fetch;\n getSetting: (key: string) => string | undefined;\n },\n model: string,\n) {\n const baseURL = runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL;\n try {\n const showRes = await fetch(`${baseURL}/show`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model }),\n });\n if (showRes.ok) return;\n logger.info(`[Ollama] Model ${model} not found locally. Downloading...`);\n const pullRes = await fetch(`${baseURL}/pull`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ model, stream: false }),\n });\n if (!pullRes.ok) {\n logger.error(`Failed to pull model ${model}: ${pullRes.statusText}`);\n } else {\n logger.info(`[Ollama] Downloaded model ${model}`);\n }\n } catch (err) {\n logger.error('Error ensuring model availability:', err);\n }\n}\n\n/**\n * Generate text using Ollama API\n */\nasync function generateOllamaText(\n ollama: ReturnType<typeof createOllama>,\n model: string,\n params: {\n prompt: string;\n system?: string;\n temperature: number;\n maxTokens: number;\n frequencyPenalty: number;\n presencePenalty: number;\n stopSequences: string[];\n },\n) {\n try {\n const { text: ollamaResponse } = await generateText({\n model: ollama(model),\n prompt: params.prompt,\n system: params.system,\n temperature: params.temperature,\n maxTokens: params.maxTokens,\n frequencyPenalty: params.frequencyPenalty,\n presencePenalty: params.presencePenalty,\n stopSequences: params.stopSequences,\n });\n return ollamaResponse;\n } catch (error: unknown) {\n logger.error('Error in generateOllamaText:', error);\n return 'Error generating text. Please try again later.';\n }\n}\n\n/**\n * Generate object using Ollama API with consistent error handling\n */\nasync function generateOllamaObject(\n ollama: ReturnType<typeof createOllama>,\n model: string,\n params: ObjectGenerationParams,\n) {\n try {\n const { object } = await generateObject({\n model: ollama(model),\n output: 'no-schema',\n prompt: params.prompt,\n temperature: params.temperature,\n });\n return object;\n } catch (error: unknown) {\n logger.error('Error generating object:', error);\n return {};\n }\n}\n\nexport const ollamaPlugin: Plugin = {\n name: 'ollama',\n description: 'Ollama plugin',\n config: {\n OLLAMA_API_ENDPOINT: process.env.OLLAMA_API_ENDPOINT,\n OLLAMA_SMALL_MODEL: process.env.OLLAMA_SMALL_MODEL,\n OLLAMA_MEDIUM_MODEL: process.env.OLLAMA_MEDIUM_MODEL,\n OLLAMA_LARGE_MODEL: process.env.OLLAMA_LARGE_MODEL,\n OLLAMA_EMBEDDING_MODEL: process.env.OLLAMA_EMBEDDING_MODEL,\n },\n models: {\n [ModelType.TEXT_EMBEDDING]: async (\n runtime,\n params: TextEmbeddingParams | string | null,\n ): Promise<number[]> => {\n try {\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL: runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL,\n });\n\n const modelName =\n runtime.getSetting('OLLAMA_EMBEDDING_MODEL') || 'nomic-embed-text';\n logger.log(`[Ollama] Using TEXT_EMBEDDING model: ${modelName}`);\n await ensureModelAvailable(runtime, modelName);\n const text =\n typeof params === 'string'\n ? params\n : (params as TextEmbeddingParams)?.text || '';\n\n if (!text) {\n logger.error('No text provided for embedding');\n return Array(1536).fill(0);\n }\n\n // Generate embeddings - note we're using a simpler approach since generateEmbedding\n // may not be available in the current version of the AI SDK\n try {\n // This is simplified and may need to be adjusted based on the actual API\n const response = await fetch(\n `${runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL}/embeddings`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: modelName,\n prompt: text,\n }),\n },\n );\n\n if (!response.ok) {\n throw new Error(`Embedding request failed: ${response.statusText}`);\n }\n\n const result = (await response.json()) as { embedding?: number[] };\n return result.embedding || Array(1536).fill(0);\n } catch (embeddingError) {\n logger.error('Error generating embedding:', embeddingError);\n return Array(1536).fill(0);\n }\n } catch (error) {\n logger.error('Error in TEXT_EMBEDDING model:', error);\n // Return a fallback vector rather than crashing\n return Array(1536).fill(0);\n }\n },\n [ModelType.TEXT_SMALL]: async (\n runtime,\n { prompt, stopSequences = [] }: GenerateTextParams,\n ) => {\n try {\n const temperature = 0.7;\n const frequency_penalty = 0.7;\n const presence_penalty = 0.7;\n const max_response_length = 8000;\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL: runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL,\n });\n\n const model =\n runtime.getSetting('OLLAMA_SMALL_MODEL') ??\n runtime.getSetting('SMALL_MODEL') ??\n 'gemma3:latest';\n\n logger.log(`[Ollama] Using TEXT_SMALL model: ${model}`);\n await ensureModelAvailable(runtime, model);\n logger.log('generating text');\n logger.log(prompt);\n\n return await generateOllamaText(ollama, model, {\n prompt,\n system: runtime.character.system ?? undefined,\n temperature,\n maxTokens: max_response_length,\n frequencyPenalty: frequency_penalty,\n presencePenalty: presence_penalty,\n stopSequences,\n });\n } catch (error) {\n logger.error('Error in TEXT_SMALL model:', error);\n return 'Error generating text. Please try again later.';\n }\n },\n [ModelType.TEXT_LARGE]: async (\n runtime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n try {\n const model =\n runtime.getSetting('OLLAMA_LARGE_MODEL') ??\n runtime.getSetting('LARGE_MODEL') ??\n 'gemma3:latest';\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL: runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL,\n });\n\n logger.log(`[Ollama] Using TEXT_LARGE model: ${model}`);\n await ensureModelAvailable(runtime, model);\n return await generateOllamaText(ollama, model, {\n prompt,\n system: runtime.character.system ?? undefined,\n temperature,\n maxTokens,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n });\n } catch (error) {\n logger.error('Error in TEXT_LARGE model:', error);\n return 'Error generating text. Please try again later.';\n }\n },\n [ModelType.OBJECT_SMALL]: async (\n runtime,\n params: ObjectGenerationParams,\n ) => {\n try {\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL: runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL,\n });\n const model =\n runtime.getSetting('OLLAMA_SMALL_MODEL') ??\n runtime.getSetting('SMALL_MODEL') ??\n 'gemma3:latest';\n\n logger.log(`[Ollama] Using OBJECT_SMALL model: ${model}`);\n await ensureModelAvailable(runtime, model);\n if (params.schema) {\n logger.info('Using OBJECT_SMALL without schema validation');\n }\n\n return await generateOllamaObject(ollama, model, params);\n } catch (error) {\n logger.error('Error in OBJECT_SMALL model:', error);\n // Return empty object instead of crashing\n return {};\n }\n },\n [ModelType.OBJECT_LARGE]: async (\n runtime,\n params: ObjectGenerationParams,\n ) => {\n try {\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL: runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL,\n });\n const model =\n runtime.getSetting('OLLAMA_LARGE_MODEL') ??\n runtime.getSetting('LARGE_MODEL') ??\n 'gemma3:latest';\n\n logger.log(`[Ollama] Using OBJECT_LARGE model: ${model}`);\n await ensureModelAvailable(runtime, model);\n if (params.schema) {\n logger.info('Using OBJECT_LARGE without schema validation');\n }\n\n return await generateOllamaObject(ollama, model, params);\n } catch (error) {\n logger.error('Error in OBJECT_LARGE model:', error);\n // Return empty object instead of crashing\n return {};\n }\n },\n },\n tests: [\n {\n name: 'ollama_plugin_tests',\n tests: [\n {\n name: 'ollama_test_url_validation',\n fn: async (runtime) => {\n try {\n const baseURL =\n runtime.getSetting('OLLAMA_API_ENDPOINT') || OLLAMA_API_URL;\n const response = await fetch(`${baseURL}/tags`);\n const data = await response.json();\n logger.log(\n 'Models Available:',\n (data as { models: unknown[] })?.models?.length,\n );\n if (!response.ok) {\n logger.error(\n `Failed to validate Ollama API: ${response.statusText}`,\n );\n return;\n }\n } catch (error) {\n logger.error('Error in ollama_test_url_validation:', error);\n }\n },\n },\n {\n name: 'ollama_test_text_embedding',\n fn: async (runtime) => {\n try {\n const embedding = await runtime.useModel(\n ModelType.TEXT_EMBEDDING,\n {\n text: 'Hello, world!',\n },\n );\n logger.log('embedding', embedding);\n } catch (error) {\n logger.error('Error in test_text_embedding:', error);\n }\n },\n },\n {\n name: 'ollama_test_text_large',\n fn: async (runtime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: 'What is the nature of reality in 10 words?',\n });\n if (text.length === 0) {\n logger.error('Failed to generate text');\n return;\n }\n logger.log('generated with test_text_large:', text);\n } catch (error) {\n logger.error('Error in test_text_large:', error);\n }\n },\n },\n {\n name: 'ollama_test_text_small',\n fn: async (runtime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt: 'What is the nature of reality in 10 words?',\n });\n if (text.length === 0) {\n logger.error('Failed to generate text');\n return;\n }\n logger.log('generated with test_text_small:', text);\n } catch (error) {\n logger.error('Error in test_text_small:', error);\n }\n },\n },\n {\n name: 'ollama_test_object_small',\n fn: async (runtime) => {\n try {\n const object = await runtime.useModel(ModelType.OBJECT_SMALL, {\n prompt:\n 'Generate a JSON object representing a user profile with name, age, and hobbies',\n temperature: 0.7,\n });\n logger.log('Generated object:', object);\n } catch (error) {\n logger.error('Error in test_object_small:', error);\n }\n },\n },\n {\n name: 'ollama_test_object_large',\n fn: async (runtime) => {\n try {\n const object = await runtime.useModel(ModelType.OBJECT_LARGE, {\n prompt:\n 'Generate a detailed JSON object representing a restaurant with name, cuisine type, menu items with prices, and customer reviews',\n temperature: 0.7,\n });\n logger.log('Generated object:', object);\n } catch (error) {\n logger.error('Error in test_object_large:', error);\n }\n },\n },\n ],\n },\n ],\n};\nexport default ollamaPlugin;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n ObjectGenerationParams,\n Plugin,\n TextEmbeddingParams,\n} from \"@elizaos/core\";\nimport { type GenerateTextParams, ModelType, logger } from \"@elizaos/core\";\nimport { generateObject, generateText } from \"ai\";\nimport { createOllama } from \"ollama-ai-provider\";\n\n// Default Ollama API URL\nconst OLLAMA_API_URL = \"http://localhost:11434\";\n\n/**\n * Extracts the protocol and host from an API endpoint URL, removing any path or query components.\n *\n * If the input cannot be parsed as a valid URL, returns the original string.\n *\n * @param endpoint - The API endpoint URL to process\n * @returns The base domain (protocol and host) of the endpoint, or the original string if parsing fails\n */\nfunction stripEndpointToBaseDomain(endpoint: string): string {\n try {\n // Using Node.js URL module explicitly\n const url = new URL(endpoint);\n return `${url.protocol}//${url.host}`;\n } catch (err) {\n logger.error(\"Error parsing endpoint URL:\", err);\n return endpoint; // Return original if parsing fails\n }\n}\n\n/**\n * Retrieves the Ollama API base URL from runtime settings, returning only the protocol and domain.\n *\n * If the API endpoint is not set in the runtime, defaults to the standard Ollama URL.\n * Removes any path or trailing segments, ensuring the result is just the base domain.\n *\n * @returns The normalized base URL for the Ollama API.\n */\nfunction getBaseURL(runtime: {\n getSetting: (key: string) => string | undefined;\n}): string {\n const apiEndpoint =\n runtime.getSetting(\"OLLAMA_API_ENDPOINT\") || OLLAMA_API_URL;\n return stripEndpointToBaseDomain(apiEndpoint);\n}\n\n/**\n * Ensures that the specified Ollama model is available locally, downloading it if necessary.\n *\n * Checks for the presence of the model via the Ollama API and attempts to download it if not found. Logs progress and errors during the process.\n */\nasync function ensureModelAvailable(\n runtime: {\n getSetting: (key: string) => string | undefined;\n fetch?: typeof fetch;\n },\n model: string,\n baseURL?: string,\n) {\n const url = baseURL || getBaseURL(runtime);\n try {\n const showRes = await fetch(`${url}/api/show`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ model }),\n });\n if (showRes.ok) return;\n logger.info(`[Ollama] Model ${model} not found locally. Downloading...`);\n const pullRes = await fetch(`${url}/api/pull`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ model, stream: false }),\n });\n if (!pullRes.ok) {\n logger.error(`Failed to pull model ${model}: ${pullRes.statusText}`);\n } else {\n logger.info(`[Ollama] Downloaded model ${model}`);\n }\n } catch (err) {\n logger.error(\"Error ensuring model availability:\", err);\n }\n}\n\n/**\n * Generates text from the Ollama API using the specified model and parameters.\n *\n * Returns the generated text, or an error message if generation fails.\n */\nasync function generateOllamaText(\n ollama: ReturnType<typeof createOllama>,\n model: string,\n params: {\n prompt: string;\n system?: string;\n temperature: number;\n maxTokens: number;\n frequencyPenalty: number;\n presencePenalty: number;\n stopSequences: string[];\n },\n) {\n try {\n const { text: ollamaResponse } = await generateText({\n model: ollama(model),\n prompt: params.prompt,\n system: params.system,\n temperature: params.temperature,\n maxTokens: params.maxTokens,\n frequencyPenalty: params.frequencyPenalty,\n presencePenalty: params.presencePenalty,\n stopSequences: params.stopSequences,\n });\n return ollamaResponse;\n } catch (error: unknown) {\n logger.error(\"Error in generateOllamaText:\", error);\n return \"Error generating text. Please try again later.\";\n }\n}\n\n/**\n * Generates an object from the Ollama API using the specified model and parameters.\n *\n * Returns the generated object, or an empty object if generation fails.\n */\nasync function generateOllamaObject(\n ollama: ReturnType<typeof createOllama>,\n model: string,\n params: ObjectGenerationParams,\n) {\n try {\n const { object } = await generateObject({\n model: ollama(model),\n output: \"no-schema\",\n prompt: params.prompt,\n temperature: params.temperature,\n });\n return object;\n } catch (error: unknown) {\n logger.error(\"Error generating object:\", error);\n return {};\n }\n}\n\nexport const ollamaPlugin: Plugin = {\n name: \"ollama\",\n description: \"Ollama plugin\",\n config: {\n OLLAMA_API_ENDPOINT: process.env.OLLAMA_API_ENDPOINT,\n OLLAMA_SMALL_MODEL: process.env.OLLAMA_SMALL_MODEL,\n OLLAMA_MEDIUM_MODEL: process.env.OLLAMA_MEDIUM_MODEL,\n OLLAMA_LARGE_MODEL: process.env.OLLAMA_LARGE_MODEL,\n OLLAMA_EMBEDDING_MODEL: process.env.OLLAMA_EMBEDDING_MODEL,\n },\n models: {\n [ModelType.TEXT_EMBEDDING]: async (\n runtime,\n params: TextEmbeddingParams | string | null,\n ): Promise<number[]> => {\n try {\n const baseURL = getBaseURL(runtime);\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL,\n });\n\n const modelName =\n runtime.getSetting(\"OLLAMA_EMBEDDING_MODEL\") || \"nomic-embed-text\";\n logger.log(`[Ollama] Using TEXT_EMBEDDING model: ${modelName}`);\n await ensureModelAvailable(runtime, modelName, baseURL);\n const text =\n typeof params === \"string\"\n ? params\n : params\n ? (params as TextEmbeddingParams).text || \"\"\n : \"\";\n\n if (!text) {\n logger.error(\"No text provided for embedding\");\n return Array(1536).fill(0);\n }\n\n // Generate embeddings - note we're using a simpler approach since generateEmbedding\n // may not be available in the current version of the AI SDK\n try {\n // This is simplified and may need to be adjusted based on the actual API\n\n const response = await fetch(`${baseURL}/api/embeddings`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: modelName,\n prompt: text,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Embedding request failed: ${response.statusText}`);\n }\n\n const result = (await response.json()) as { embedding?: number[] };\n return result.embedding || Array(1536).fill(0);\n } catch (embeddingError) {\n logger.error(\"Error generating embedding:\", embeddingError);\n return Array(1536).fill(0);\n }\n } catch (error) {\n logger.error(\"Error in TEXT_EMBEDDING model:\", error);\n // Return a fallback vector rather than crashing\n return Array(1536).fill(0);\n }\n },\n [ModelType.TEXT_SMALL]: async (\n runtime,\n { prompt, stopSequences = [] }: GenerateTextParams,\n ) => {\n try {\n const temperature = 0.7;\n const frequency_penalty = 0.7;\n const presence_penalty = 0.7;\n const max_response_length = 8000;\n const baseURL = getBaseURL(runtime);\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL,\n });\n\n const model =\n runtime.getSetting(\"OLLAMA_SMALL_MODEL\") ||\n runtime.getSetting(\"SMALL_MODEL\") ||\n \"gemma3:latest\";\n\n logger.log(`[Ollama] Using TEXT_SMALL model: ${model}`);\n await ensureModelAvailable(runtime, model, baseURL);\n logger.log(\"generating text\");\n logger.log(prompt);\n\n return await generateOllamaText(ollama, model, {\n prompt,\n system: runtime.character?.system || undefined,\n temperature,\n maxTokens: max_response_length,\n frequencyPenalty: frequency_penalty,\n presencePenalty: presence_penalty,\n stopSequences,\n });\n } catch (error) {\n logger.error(\"Error in TEXT_SMALL model:\", error);\n return \"Error generating text. Please try again later.\";\n }\n },\n [ModelType.TEXT_LARGE]: async (\n runtime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n try {\n const model =\n runtime.getSetting(\"OLLAMA_LARGE_MODEL\") ||\n runtime.getSetting(\"LARGE_MODEL\") ||\n \"gemma3:latest\";\n const baseURL = getBaseURL(runtime);\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL,\n });\n\n logger.log(`[Ollama] Using TEXT_LARGE model: ${model}`);\n await ensureModelAvailable(runtime, model, baseURL);\n return await generateOllamaText(ollama, model, {\n prompt,\n system: runtime.character?.system || undefined,\n temperature,\n maxTokens,\n frequencyPenalty,\n presencePenalty,\n stopSequences,\n });\n } catch (error) {\n logger.error(\"Error in TEXT_LARGE model:\", error);\n return \"Error generating text. Please try again later.\";\n }\n },\n [ModelType.OBJECT_SMALL]: async (\n runtime,\n params: ObjectGenerationParams,\n ) => {\n try {\n const baseURL = getBaseURL(runtime);\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL,\n });\n const model =\n runtime.getSetting(\"OLLAMA_SMALL_MODEL\") ||\n runtime.getSetting(\"SMALL_MODEL\") ||\n \"gemma3:latest\";\n\n logger.log(`[Ollama] Using OBJECT_SMALL model: ${model}`);\n await ensureModelAvailable(runtime, model, baseURL);\n if (params.schema) {\n logger.info(\"Using OBJECT_SMALL without schema validation\");\n }\n\n return await generateOllamaObject(ollama, model, params);\n } catch (error) {\n logger.error(\"Error in OBJECT_SMALL model:\", error);\n // Return empty object instead of crashing\n return {};\n }\n },\n [ModelType.OBJECT_LARGE]: async (\n runtime,\n params: ObjectGenerationParams,\n ) => {\n try {\n const baseURL = getBaseURL(runtime);\n const ollama = createOllama({\n fetch: runtime.fetch,\n baseURL,\n });\n const model =\n runtime.getSetting(\"OLLAMA_LARGE_MODEL\") ||\n runtime.getSetting(\"LARGE_MODEL\") ||\n \"gemma3:latest\";\n\n logger.log(`[Ollama] Using OBJECT_LARGE model: ${model}`);\n await ensureModelAvailable(runtime, model, baseURL);\n if (params.schema) {\n logger.info(\"Using OBJECT_LARGE without schema validation\");\n }\n\n return await generateOllamaObject(ollama, model, params);\n } catch (error) {\n logger.error(\"Error in OBJECT_LARGE model:\", error);\n // Return empty object instead of crashing\n return {};\n }\n },\n },\n tests: [\n {\n name: \"ollama_plugin_tests\",\n tests: [\n {\n name: \"ollama_test_url_validation\",\n fn: async (runtime) => {\n try {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/api/tags`);\n const data = await response.json();\n logger.log(\n \"Models Available:\",\n data &&\n typeof data === \"object\" &&\n \"models\" in data &&\n Array.isArray(data.models)\n ? data.models.length\n : 0,\n );\n if (!response.ok) {\n logger.error(\n `Failed to validate Ollama API: ${response.statusText}`,\n );\n return;\n }\n } catch (error) {\n logger.error(\"Error in ollama_test_url_validation:\", error);\n }\n },\n },\n {\n name: \"ollama_test_text_embedding\",\n fn: async (runtime) => {\n try {\n const embedding = await runtime.useModel(\n ModelType.TEXT_EMBEDDING,\n {\n text: \"Hello, world!\",\n },\n );\n logger.log(\"embedding\", embedding);\n } catch (error) {\n logger.error(\"Error in test_text_embedding:\", error);\n }\n },\n },\n {\n name: \"ollama_test_text_large\",\n fn: async (runtime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n logger.error(\"Failed to generate text\");\n return;\n }\n logger.log(\"generated with test_text_large:\", text);\n } catch (error) {\n logger.error(\"Error in test_text_large:\", error);\n }\n },\n },\n {\n name: \"ollama_test_text_small\",\n fn: async (runtime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n logger.error(\"Failed to generate text\");\n return;\n }\n logger.log(\"generated with test_text_small:\", text);\n } catch (error) {\n logger.error(\"Error in test_text_small:\", error);\n }\n },\n },\n {\n name: \"ollama_test_object_small\",\n fn: async (runtime) => {\n try {\n const object = await runtime.useModel(ModelType.OBJECT_SMALL, {\n prompt:\n \"Generate a JSON object representing a user profile with name, age, and hobbies\",\n temperature: 0.7,\n schema: undefined,\n });\n logger.log(\"Generated object:\", object);\n } catch (error) {\n logger.error(\"Error in test_object_small:\", error);\n }\n },\n },\n {\n name: \"ollama_test_object_large\",\n fn: async (runtime) => {\n try {\n const object = await runtime.useModel(ModelType.OBJECT_LARGE, {\n prompt:\n \"Generate a detailed JSON object representing a restaurant with name, cuisine type, menu items with prices, and customer reviews\",\n temperature: 0.7,\n schema: undefined,\n });\n logger.log(\"Generated object:\", object);\n } catch (error) {\n logger.error(\"Error in test_object_large:\", error);\n }\n },\n },\n ],\n },\n ],\n};\nexport default ollamaPlugin;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/plugin-ollama",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -45,9 +45,9 @@
45
45
  "pluginParameters": {
46
46
  "OLLAMA_API_ENDPOINT": {
47
47
  "type": "string",
48
- "description": "Base URL for the Ollama API that overrides the default http://localhost:11434/api endpoint.",
48
+ "description": "Base URL for the Ollama API. The plugin will strip this to the domain part and append the necessary API paths.",
49
49
  "required": true,
50
- "default": "http://localhost:11434/api",
50
+ "default": "http://localhost:11434",
51
51
  "sensitive": false
52
52
  },
53
53
  "OLLAMA_SMALL_MODEL": {
@@ -95,6 +95,7 @@
95
95
  },
96
96
  "gitHead": "646c632924826e2b75c2304a75ee56959fe4a460",
97
97
  "devDependencies": {
98
+ "@types/node": "^24.0.4",
98
99
  "prettier": "3.5.3",
99
100
  "typescript": "^5.8.2"
100
101
  }