@easbot/ollama-sdk 0.1.0 → 0.1.1

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.en.md CHANGED
@@ -1,17 +1,19 @@
1
1
  # @easbot/ollama-sdk
2
2
 
3
- AI SDK v2 compatible Ollama Provider with automatic event stream generation.
3
+ AI SDK v2 compatible Ollama Provider with automatic complete event stream generation.
4
4
 
5
5
  [中文文档](./README.md) | English
6
6
 
7
7
  ## Features
8
8
 
9
9
  - ✅ Full AI SDK v2 compatibility
10
- - ✅ Automatic generation of missing event stream events
11
- - ✅ Lightweight wrapper based on `ai-sdk-ollama`
10
+ - ✅ Tool Calling support
11
+ - ✅ Automatic complete event stream generation
12
+ - ✅ Native Ollama implementation with no extra dependencies
12
13
  - ✅ TypeScript type support
13
14
  - ✅ Streaming and non-streaming generation
14
15
  - ✅ Complete error handling
16
+ - ✅ <think> tag reasoning support
15
17
 
16
18
  ## Installation
17
19
 
@@ -24,17 +26,17 @@ pnpm add @easbot/ollama-sdk ai
24
26
  ### Basic Usage
25
27
 
26
28
  ```typescript
27
- import { createOllama } from '@easbot/ollama-sdk';
29
+ import { NativeOllamaLanguageModel } from '@easbot/ollama-sdk';
28
30
  import { streamText } from 'ai';
29
31
 
30
- // Create Ollama provider
31
- const ollama = createOllama({
32
+ // Create Ollama model
33
+ const model = new NativeOllamaLanguageModel('qwen2.5:0.5b', {
32
34
  baseURL: 'http://localhost:11434', // Optional, default value
33
35
  });
34
36
 
35
37
  // Streaming generation
36
38
  const result = await streamText({
37
- model: ollama('llama2'),
39
+ model,
38
40
  prompt: 'Hello, world!',
39
41
  });
40
42
 
@@ -43,96 +45,407 @@ for await (const chunk of result.textStream) {
43
45
  }
44
46
  ```
45
47
 
48
+ ### Tool Calling
49
+
50
+ ```typescript
51
+ import { NativeOllamaLanguageModel } from '@easbot/ollama-sdk';
52
+ import { generateText } from 'ai';
53
+
54
+ const model = new NativeOllamaLanguageModel('qwen2.5:0.5b');
55
+
56
+ // Define tools
57
+ const tools = {
58
+ read_file: {
59
+ description: 'Read file content',
60
+ parameters: {
61
+ type: 'object',
62
+ properties: {
63
+ path: {
64
+ type: 'string',
65
+ description: 'File path',
66
+ },
67
+ },
68
+ required: ['path'],
69
+ },
70
+ execute: async ({ path }: { path: string }) => {
71
+ const fs = await import('fs/promises');
72
+ return await fs.readFile(path, 'utf-8');
73
+ },
74
+ },
75
+ };
76
+
77
+ // Use tool calling
78
+ const result = await generateText({
79
+ model,
80
+ tools,
81
+ prompt: 'Please read the content of package.json file',
82
+ });
83
+
84
+ console.log(result.text);
85
+ ```
86
+
46
87
  ### Non-Streaming Generation
47
88
 
48
89
  ```typescript
49
90
  import { generateText } from 'ai';
50
91
 
92
+ const model = new NativeOllamaLanguageModel('qwen2.5:0.5b');
93
+
51
94
  const result = await generateText({
52
- model: ollama('llama2'),
95
+ model,
53
96
  prompt: 'What is the capital of France?',
54
97
  });
55
98
 
56
99
  console.log(result.text);
57
100
  ```
58
101
 
102
+ ## System Requirements
103
+
104
+ ### Ollama Version Requirements
105
+
106
+ - **Tool Calling Feature**: Requires Ollama 0.1.26 or higher
107
+ - **Basic Text Generation**: Supports all Ollama versions
108
+
109
+ ### Supported Models
110
+
111
+ Tool calling feature requires models that support tool calling. Recommended:
112
+
113
+ - `qwen2.5:0.5b` - Lightweight, suitable for development and testing
114
+ - `qwen2.5:7b` - Balanced performance and quality
115
+ - `llama3.1:8b` - High-quality tool calling
116
+ - `mistral:7b` - General-purpose model
117
+
118
+ Check if a model supports tool calling:
119
+
120
+ ```bash
121
+ ollama show <model-name>
122
+ ```
123
+
124
+ Look for the `tools` field in the model information.
125
+
59
126
  ### Multiple Invocation Methods
60
127
 
61
128
  ```typescript
62
- // Method 1: Direct provider call
63
- const model1 = ollama('llama2');
129
+ // Method 1: Direct model instance creation
130
+ const model1 = new NativeOllamaLanguageModel('qwen2.5:0.5b');
131
+
132
+ // Method 2: Custom baseURL
133
+ const model2 = new NativeOllamaLanguageModel('qwen2.5:0.5b', {
134
+ baseURL: 'http://192.168.1.100:11434',
135
+ });
136
+
137
+ // Method 3: Use different models
138
+ const model3 = new NativeOllamaLanguageModel('llama3.1:8b');
139
+ ```
140
+
141
+ ## Tool Calling Details
142
+
143
+ ### Tool Definition Format
144
+
145
+ Tool definitions follow the AI SDK v2 specification, using the `inputSchema` field:
146
+
147
+ ```typescript
148
+ const tools = {
149
+ tool_name: {
150
+ description: 'Tool description',
151
+ inputSchema: {
152
+ type: 'object',
153
+ properties: {
154
+ param1: {
155
+ type: 'string',
156
+ description: 'Parameter description',
157
+ },
158
+ param2: {
159
+ type: 'number',
160
+ description: 'Number parameter',
161
+ },
162
+ },
163
+ required: ['param1'],
164
+ },
165
+ execute: async (args) => {
166
+ // Tool execution logic
167
+ return result;
168
+ },
169
+ },
170
+ };
171
+ ```
172
+
173
+ ### Tool Calling Event Stream
174
+
175
+ Streaming tool calling generates the following event sequence:
176
+
177
+ ```
178
+ response-metadata
179
+
180
+ tool-input-start (tool call starts)
181
+
182
+ tool-input-delta (parameter accumulation, multiple times)
183
+
184
+ tool-input-end (parameter reception complete)
185
+
186
+ tool-call (tool call complete)
187
+
188
+ finish (finishReason: 'tool-calls')
189
+ ```
190
+
191
+ ### Tool Calling Loop
192
+
193
+ AI SDK automatically handles tool calling loops:
194
+
195
+ ```typescript
196
+ const result = await generateText({
197
+ model,
198
+ tools,
199
+ prompt: 'Please read package.json and analyze its content',
200
+ maxSteps: 5, // Maximum 5 rounds of tool calling
201
+ });
202
+
203
+ // AI SDK will automatically:
204
+ // 1. Call tools
205
+ // 2. Return tool results to the model
206
+ // 3. Continue generation until complete or maxSteps reached
207
+ ```
208
+
209
+ ### Tool Calling + Reasoning
210
+
211
+ Models can use both tool calling and reasoning (<think> tags) simultaneously:
212
+
213
+ ```typescript
214
+ const result = await streamText({
215
+ model,
216
+ tools,
217
+ prompt: 'Analyze this problem and use tools to solve it',
218
+ });
219
+
220
+ for await (const event of result.fullStream) {
221
+ switch (event.type) {
222
+ case 'reasoning-delta':
223
+ console.log('[Reasoning]', event.delta);
224
+ break;
225
+ case 'text-delta':
226
+ console.log('[Text]', event.delta);
227
+ break;
228
+ case 'tool-call':
229
+ console.log('[Tool Call]', event.toolName, event.input);
230
+ break;
231
+ }
232
+ }
233
+ ```
234
+
235
+ ## Limitations and Considerations
236
+
237
+ ### Tool Calling Limitations
238
+
239
+ 1. **Model Support**: Not all Ollama models support tool calling, please use supported models
240
+ 2. **Parameter Format**: Tool parameters must be valid JSON objects
241
+ 3. **Concurrent Calls**: A single response can contain multiple tool calls, but they are executed sequentially
242
+ 4. **Parameter Size**: Avoid passing overly large parameters (recommended < 10KB)
243
+
244
+ ### Reasoning Tag Limitations
245
+
246
+ 1. **Tag Format**: Must use `<think>...</think>` format
247
+ 2. **Nesting**: Nested think tags are not supported
248
+ 3. **Mixed Content**: Can be mixed with regular text and tool calling
249
+
250
+ ### Performance Considerations
251
+
252
+ 1. **Streaming First**: For long text generation, prioritize streaming API
253
+ 2. **Tool Count**: Recommended number of tools per request < 20
254
+ 3. **Parameter Validation**: Validate parameters before tool execution to avoid invalid calls
255
+
256
+ ## FAQ
257
+
258
+ ### Q: How to check Ollama version?
259
+
260
+ ```bash
261
+ ollama --version
262
+ ```
263
+
264
+ If version is lower than 0.1.26, please upgrade:
265
+
266
+ ```bash
267
+ # macOS/Linux
268
+ curl -fsSL https://ollama.com/install.sh | sh
269
+
270
+ # Windows
271
+ # Download the latest version from https://ollama.com/download
272
+ ```
273
+
274
+ ### Q: What if tool calling doesn't work?
275
+
276
+ 1. Check if Ollama version is >= 0.1.26
277
+ 2. Confirm the model supports tool calling (use `ollama show <model>`)
278
+ 3. Check if tool definition format is correct (use `inputSchema` instead of `parameters`)
279
+ 4. Check log output for error messages
280
+
281
+ ### Q: How to debug tool calling?
282
+
283
+ Enable debug logging:
284
+
285
+ ```typescript
286
+ import { Log } from '@easbot/ollama-sdk';
64
287
 
65
- // Method 2: Using languageModel method
66
- const model2 = ollama.languageModel('mistral');
288
+ // Initialize logging system
289
+ await Log.init({
290
+ print: true,
291
+ dev: true,
292
+ level: 'DEBUG', // Enable DEBUG level logging
293
+ });
67
294
 
68
- // Method 3: Using chat method (alias)
69
- const model3 = ollama.chat('codellama');
295
+ // Now all tool calling details will be output to console
70
296
  ```
71
297
 
298
+ ### Q: What tool parameter types are supported?
299
+
300
+ All JSON Schema types are supported:
301
+
302
+ - `string` - String
303
+ - `number` - Number
304
+ - `boolean` - Boolean
305
+ - `object` - Object
306
+ - `array` - Array
307
+ - `null` - Null
308
+
309
+ ### Q: How to handle tool calling errors?
310
+
311
+ ```typescript
312
+ const tools = {
313
+ risky_operation: {
314
+ description: 'Operation that may fail',
315
+ inputSchema: { /* ... */ },
316
+ execute: async (args) => {
317
+ try {
318
+ // Execute operation
319
+ return result;
320
+ } catch (error) {
321
+ // Return error message to model
322
+ throw new Error(`Operation failed: ${error.message}`);
323
+ }
324
+ },
325
+ },
326
+ };
327
+ ```
328
+
329
+ ### Q: What about backward compatibility?
330
+
331
+ Fully backward compatible:
332
+
333
+ - When `tools` parameter is not provided, behavior is exactly the same as before
334
+ - Existing text generation and reasoning features are not affected
335
+ - API signature remains unchanged
336
+
337
+ ## Example Code
338
+
339
+ For complete usage examples, please refer to:
340
+
341
+ - [Basic Tool Calling Example](./.easbot/test-ollama-tool-calling.ts)
342
+ - [Multiple Tool Calling Example](./.easbot/test-ollama-tool-calling.ts#example2)
343
+ - [Tool Calling + Reasoning Example](./.easbot/test-ollama-tool-calling.ts#example3)
344
+ - [Error Handling Example](./.easbot/test-ollama-tool-calling.ts#example4)
345
+ - [Tool Calling Loop Example](./.easbot/test-ollama-tool-calling.ts#example5)
346
+
72
347
  ## API Reference
73
348
 
74
- ### `createOllama(config?)`
349
+ ### `NativeOllamaLanguageModel`
75
350
 
76
- Create an Ollama provider instance.
351
+ Native Ollama language model implementation, fully compatible with AI SDK v2.
352
+
353
+ **Constructor:**
354
+
355
+ ```typescript
356
+ new NativeOllamaLanguageModel(modelId: string, config?: {
357
+ baseURL?: string;
358
+ })
359
+ ```
77
360
 
78
361
  **Parameters:**
79
362
 
80
- - `config` (optional): Provider configuration
363
+ - `modelId` (string): Ollama model ID (e.g., 'qwen2.5:0.5b', 'llama3.1:8b')
364
+ - `config` (optional): Model configuration
81
365
  - `baseURL` (string): Ollama API base URL, defaults to `'http://localhost:11434'`
82
- - `headers` (Record<string, string>): Custom request headers
83
- - `fetch` (typeof fetch): Custom fetch implementation
84
366
 
85
- **Returns:**
367
+ **Methods:**
86
368
 
87
- `OllamaProvider` - Callable provider object
369
+ - `doStream(options)`: Streaming generation, returns ReadableStream
370
+ - `doGenerate(options)`: Non-streaming generation, returns complete result
88
371
 
89
372
  **Example:**
90
373
 
91
374
  ```typescript
92
- const ollama = createOllama({
375
+ const model = new NativeOllamaLanguageModel('qwen2.5:0.5b', {
93
376
  baseURL: 'http://localhost:11434',
94
- headers: {
95
- 'X-Custom-Header': 'value',
96
- },
377
+ });
378
+
379
+ // Streaming generation
380
+ const streamResult = await model.doStream({
381
+ prompt: [
382
+ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }
383
+ ],
384
+ tools: [/* ... */],
385
+ });
386
+
387
+ // Non-streaming generation
388
+ const generateResult = await model.doGenerate({
389
+ prompt: [
390
+ { role: 'user', content: [{ type: 'text', text: 'Hello' }] }
391
+ ],
392
+ tools: [/* ... */],
97
393
  });
98
394
  ```
99
395
 
100
- ### `OllamaProvider`
396
+ ## Event Stream
101
397
 
102
- Provider object that provides three ways to create language models:
398
+ This SDK generates a complete AI SDK v2 event stream, including:
103
399
 
104
- ```typescript
105
- // Direct call
106
- const model = ollama('llama2');
400
+ ### Basic Events
401
+
402
+ 1. **response-metadata** - First event, contains model ID and timestamp
403
+ 2. **text-start** - Emitted before the first text-delta
404
+ 3. **text-delta** - Text content delta (multiple times)
405
+ 4. **text-end** - Emitted after all text-deltas
406
+ 5. **finish** - Last event, contains finishReason and usage
407
+
408
+ ### Tool Calling Events
409
+
410
+ 6. **tool-input-start** - Tool call starts, contains toolName
411
+ 7. **tool-input-delta** - Tool parameter delta (multiple times)
412
+ 8. **tool-input-end** - Tool parameter reception complete
413
+ 9. **tool-call** - Tool call complete, contains complete parameters
414
+
415
+ ### Reasoning Events
416
+
417
+ 10. **reasoning-start** - Reasoning starts (<think> tag)
418
+ 11. **reasoning-delta** - Reasoning content delta (multiple times)
419
+ 12. **reasoning-end** - Reasoning ends (</think> tag)
420
+
421
+ ### Event Stream Order Examples
107
422
 
108
- // Using languageModel method
109
- const model = ollama.languageModel('llama2');
423
+ **Pure Text Generation:**
110
424
 
111
- // Using chat method
112
- const model = ollama.chat('llama2');
425
+ ```
426
+ response-metadata text-start → text-delta (multiple) → text-end → finish
113
427
  ```
114
428
 
115
- ## Event Stream Enhancement
429
+ **Tool Calling:**
116
430
 
117
- This SDK automatically enhances the `ai-sdk-ollama` event stream by adding the following missing events:
431
+ ```
432
+ response-metadata → tool-input-start → tool-input-delta (multiple) →
433
+ tool-input-end → tool-call → finish (finishReason: 'tool-calls')
434
+ ```
118
435
 
119
- 1. **response-metadata** - First event, contains model ID and timestamp
120
- 2. **text-start** - Emitted before the first text-delta
121
- 3. **text-end** - Emitted after all text-deltas
122
- 4. **finish** - Automatically added if ai-sdk-ollama doesn't emit it
436
+ **Reasoning + Text:**
123
437
 
124
- ### Event Stream Order
438
+ ```
439
+ response-metadata → reasoning-start → reasoning-delta (multiple) →
440
+ reasoning-end → text-start → text-delta (multiple) → text-end → finish
441
+ ```
442
+
443
+ **Tool Calling + Reasoning:**
125
444
 
126
445
  ```
127
- response-metadata
128
-
129
- text-start (if text generation occurs)
130
-
131
- text-delta (multiple)
132
-
133
- text-end (if text generation occurs)
134
-
135
- finish
446
+ response-metadata → reasoning-start → reasoning-delta (multiple) →
447
+ reasoning-end → tool-input-start → tool-input-delta (multiple) →
448
+ tool-input-end tool-call finish
136
449
  ```
137
450
 
138
451
  ## Error Handling
@@ -141,64 +454,96 @@ The SDK provides complete error types:
141
454
 
142
455
  ```typescript
143
456
  import {
144
- OllamaError,
145
- ConnectionError,
146
- ModelNotFoundError,
147
- ValidationError,
148
- TimeoutError,
457
+ InvalidToolDefinitionError,
149
458
  } from '@easbot/ollama-sdk';
150
459
 
151
460
  try {
461
+ const model = new NativeOllamaLanguageModel('qwen2.5:0.5b');
152
462
  const result = await generateText({
153
- model: ollama('llama2'),
463
+ model,
464
+ tools: {
465
+ invalid_tool: {
466
+ // Missing inputSchema field
467
+ description: 'Invalid tool',
468
+ } as any,
469
+ },
154
470
  prompt: 'Hello',
155
471
  });
156
472
  } catch (error) {
157
- if (error instanceof ConnectionError) {
158
- console.error('Cannot connect to Ollama service:', error.url);
159
- } else if (error instanceof ModelNotFoundError) {
160
- console.error('Model not found:', error.modelId);
161
- } else if (error instanceof ValidationError) {
162
- console.error('Validation failed:', error.field, error.value);
163
- } else if (error instanceof TimeoutError) {
164
- console.error('Request timeout:', error.timeoutMs);
473
+ if (error instanceof InvalidToolDefinitionError) {
474
+ console.error('Invalid tool definition:', error.toolName, error.missingField);
475
+ } else {
476
+ console.error('Other error:', error);
477
+ }
478
+ }
479
+ ```
480
+
481
+ ### Error Events
482
+
483
+ In streaming processing, errors are emitted as events:
484
+
485
+ ```typescript
486
+ const result = await model.doStream({
487
+ prompt: [{ role: 'user', content: [{ type: 'text', text: 'Hello' }] }],
488
+ });
489
+
490
+ for await (const event of result.stream) {
491
+ if (event.type === 'error') {
492
+ console.error('Streaming error:', event.error);
493
+ } else if (event.type === 'finish') {
494
+ if (event.finishReason === 'error') {
495
+ console.error('Error occurred during generation');
496
+ }
165
497
  }
166
498
  }
167
499
  ```
168
500
 
169
501
  ## Architecture
170
502
 
171
- This SDK is a lightweight wrapper layer that relies on `ai-sdk-ollama` for actual LLM requests:
503
+ This SDK is a fully native Ollama implementation that directly calls the Ollama HTTP API:
172
504
 
173
505
  ```
174
506
  User Code
175
507
 
176
- @easbot/ollama-sdk (Wrapper Layer)
177
- ├── createOllama() - Provider factory
178
- ├── OllamaLanguageModel - Language model wrapper
179
- ├── doGenerate() - Delegates to ai-sdk-ollama
180
- │ └── doStream() - Delegates + event stream enhancement
181
- └── enhanceStream() - Event stream enhancer
182
-
183
- ai-sdk-ollama (Underlying LLM requests)
508
+ @easbot/ollama-sdk
509
+ ├── NativeOllamaLanguageModel - Language model implementation
510
+ ├── doGenerate() - Non-streaming generation
511
+ └── doStream() - Streaming generation + event stream generation
512
+ ├── NativeOllamaClient - HTTP client
513
+ │ ├── chat() - Non-streaming request
514
+ │ └── streamChat() - Streaming request
515
+ ├── prepareTools() - Tool definition conversion
516
+ ├── convertToOllamaMessages() - Message format conversion
517
+ └── Log - Structured logging system
184
518
 
185
519
  Ollama HTTP API
186
520
  ```
187
521
 
188
- ## Comparison with Other Providers
522
+ ### Features
523
+
524
+ - **Zero Dependencies**: No dependency on `ai-sdk-ollama` or other third-party libraries
525
+ - **Complete Implementation**: Fully compliant with AI SDK v2 specification
526
+ - **High Performance**: Batch event queue, timely state cleanup
527
+ - **Debuggable**: Structured logging, trace ID tracking
528
+
529
+ ## Comparison with Other Implementations
189
530
 
190
531
  ### vs `ai-sdk-ollama`
191
532
 
192
- - ✅ Complete AI SDK v2 event stream (automatically adds missing events)
533
+ - ✅ Complete tool calling support (ai-sdk-ollama doesn't support)
534
+ - ✅ Complete AI SDK v2 event stream
193
535
  - ✅ Better TypeScript type support
194
536
  - ✅ Complete error handling system
195
- - ✅ Maintains same performance as `ai-sdk-ollama`
537
+ - ✅ Structured logging and debugging support
538
+ - ✅ Zero extra dependencies
196
539
 
197
540
  ### vs `ollama-ai-provider`
198
541
 
199
- - ✅ Based on official `ai-sdk-ollama`, more stable
200
- - ✅ Automatic event stream enhancement
542
+ - ✅ Native implementation, more stable
543
+ - ✅ Tool calling support
544
+ - ✅ Automatic event stream generation
201
545
  - ✅ Cleaner API
546
+ - ✅ Complete documentation and examples
202
547
 
203
548
  ## Development
204
549
 
@@ -225,10 +570,4 @@ MIT
225
570
 
226
571
  ## Contributing
227
572
 
228
- Issues and Pull Requests are welcome!
229
-
230
- ## Links
231
-
232
- - npm package: https://www.npmjs.com/package/@easbot/ollama-sdk
233
- - GitHub repository: https://github.com/houjallen/easbot
234
- - Issue tracker: https://github.com/houjallen/easbot/issues
573
+ Issues and Pull Requests are welcome!