@push.rocks/smartai 0.13.3 → 2.0.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/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/index.d.ts +6 -11
- package/dist_ts/index.js +6 -12
- package/dist_ts/plugins.d.ts +10 -15
- package/dist_ts/plugins.js +13 -19
- package/dist_ts/smartai.classes.smartai.d.ts +7 -0
- package/dist_ts/smartai.classes.smartai.js +51 -0
- package/dist_ts/smartai.interfaces.d.ts +41 -0
- package/dist_ts/smartai.interfaces.js +2 -0
- package/dist_ts/smartai.middleware.anthropic.d.ts +7 -0
- package/dist_ts/smartai.middleware.anthropic.js +36 -0
- package/dist_ts/smartai.provider.ollama.d.ts +8 -0
- package/dist_ts/smartai.provider.ollama.js +378 -0
- package/dist_ts_audio/index.d.ts +9 -0
- package/dist_ts_audio/index.js +15 -0
- package/dist_ts_audio/plugins.d.ts +2 -0
- package/dist_ts_audio/plugins.js +3 -0
- package/dist_ts_document/index.d.ts +11 -0
- package/dist_ts_document/index.js +45 -0
- package/dist_ts_document/plugins.d.ts +3 -0
- package/dist_ts_document/plugins.js +4 -0
- package/dist_ts_image/index.d.ts +46 -0
- package/dist_ts_image/index.js +110 -0
- package/dist_ts_image/plugins.d.ts +3 -0
- package/dist_ts_image/plugins.js +4 -0
- package/dist_ts_research/index.d.ts +19 -0
- package/dist_ts_research/index.js +98 -0
- package/dist_ts_research/plugins.d.ts +2 -0
- package/dist_ts_research/plugins.js +3 -0
- package/dist_ts_vision/index.d.ts +8 -0
- package/dist_ts_vision/index.js +21 -0
- package/dist_ts_vision/plugins.d.ts +2 -0
- package/dist_ts_vision/plugins.js +3 -0
- package/package.json +50 -22
- package/readme.hints.md +34 -88
- package/readme.md +284 -547
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/index.ts +8 -11
- package/ts/plugins.ts +19 -35
- package/ts/smartai.classes.smartai.ts +51 -0
- package/ts/smartai.interfaces.ts +53 -0
- package/ts/smartai.middleware.anthropic.ts +38 -0
- package/ts/smartai.provider.ollama.ts +426 -0
- package/ts_audio/index.ts +24 -0
- package/ts_audio/plugins.ts +2 -0
- package/ts_document/index.ts +61 -0
- package/ts_document/plugins.ts +3 -0
- package/ts_image/index.ts +147 -0
- package/ts_image/plugins.ts +3 -0
- package/ts_research/index.ts +120 -0
- package/ts_research/plugins.ts +2 -0
- package/ts_vision/index.ts +29 -0
- package/ts_vision/plugins.ts +2 -0
- package/dist_ts/abstract.classes.multimodal.d.ts +0 -212
- package/dist_ts/abstract.classes.multimodal.js +0 -43
- package/dist_ts/classes.conversation.d.ts +0 -31
- package/dist_ts/classes.conversation.js +0 -150
- package/dist_ts/classes.smartai.d.ts +0 -59
- package/dist_ts/classes.smartai.js +0 -139
- package/dist_ts/classes.tts.d.ts +0 -6
- package/dist_ts/classes.tts.js +0 -10
- package/dist_ts/interfaces.d.ts +0 -1
- package/dist_ts/interfaces.js +0 -2
- package/dist_ts/paths.d.ts +0 -2
- package/dist_ts/paths.js +0 -4
- package/dist_ts/provider.anthropic.d.ts +0 -48
- package/dist_ts/provider.anthropic.js +0 -369
- package/dist_ts/provider.elevenlabs.d.ts +0 -43
- package/dist_ts/provider.elevenlabs.js +0 -64
- package/dist_ts/provider.exo.d.ts +0 -40
- package/dist_ts/provider.exo.js +0 -116
- package/dist_ts/provider.groq.d.ts +0 -39
- package/dist_ts/provider.groq.js +0 -178
- package/dist_ts/provider.mistral.d.ts +0 -61
- package/dist_ts/provider.mistral.js +0 -288
- package/dist_ts/provider.ollama.d.ts +0 -141
- package/dist_ts/provider.ollama.js +0 -529
- package/dist_ts/provider.openai.d.ts +0 -62
- package/dist_ts/provider.openai.js +0 -403
- package/dist_ts/provider.perplexity.d.ts +0 -37
- package/dist_ts/provider.perplexity.js +0 -215
- package/dist_ts/provider.xai.d.ts +0 -52
- package/dist_ts/provider.xai.js +0 -160
- package/ts/abstract.classes.multimodal.ts +0 -240
- package/ts/classes.conversation.ts +0 -176
- package/ts/classes.smartai.ts +0 -187
- package/ts/classes.tts.ts +0 -15
- package/ts/interfaces.ts +0 -0
- package/ts/paths.ts +0 -4
- package/ts/provider.anthropic.ts +0 -446
- package/ts/provider.elevenlabs.ts +0 -116
- package/ts/provider.exo.ts +0 -155
- package/ts/provider.groq.ts +0 -219
- package/ts/provider.mistral.ts +0 -352
- package/ts/provider.ollama.ts +0 -705
- package/ts/provider.openai.ts +0 -462
- package/ts/provider.perplexity.ts +0 -259
- package/ts/provider.xai.ts +0 -214
package/readme.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @push.rocks/smartai
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**A unified provider registry for the Vercel AI SDK** 🧠⚡
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@push.rocks/smartai)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
9
|
-
SmartAI
|
|
9
|
+
SmartAI gives you a single `getModel()` function that returns a standard `LanguageModelV3` for **any** supported provider — Anthropic, OpenAI, Google, Groq, Mistral, XAI, Perplexity, or Ollama. Use the returned model with the Vercel AI SDK's `generateText()`, `streamText()`, and tool ecosystem. Specialized capabilities like vision, audio, image generation, document analysis, and web research are available as dedicated subpath imports.
|
|
10
10
|
|
|
11
11
|
## Issue Reporting and Security
|
|
12
12
|
|
|
@@ -14,679 +14,416 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
14
14
|
|
|
15
15
|
## 🎯 Why SmartAI?
|
|
16
16
|
|
|
17
|
-
- **🔌
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- **⚡ Zero
|
|
17
|
+
- **🔌 One function, eight providers** — `getModel()` returns a standard `LanguageModelV3`. Switch providers by changing a string.
|
|
18
|
+
- **🧱 Built on Vercel AI SDK** — Uses `ai` v6 under the hood. Your model works with `generateText()`, `streamText()`, tool calling, structured output, and everything else in the AI SDK ecosystem.
|
|
19
|
+
- **🏠 Custom Ollama provider** — A full `LanguageModelV3` implementation for Ollama with support for `think` mode, `num_ctx`, auto-tuned temperature for Qwen models, and native tool calling.
|
|
20
|
+
- **💰 Anthropic prompt caching** — Automatic `cacheControl` middleware reduces cost and latency on repeated calls. Enabled by default, opt out with `promptCaching: false`.
|
|
21
|
+
- **📦 Modular subpath exports** — Vision, audio, image, document, and research capabilities ship as separate imports. Only import what you need.
|
|
22
|
+
- **⚡ Zero lock-in** — Your code uses standard AI SDK types. Swap providers without touching application logic.
|
|
23
23
|
|
|
24
24
|
## 📦 Installation
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
npm install @push.rocks/smartai
|
|
28
|
-
# or
|
|
29
27
|
pnpm install @push.rocks/smartai
|
|
30
28
|
```
|
|
31
29
|
|
|
32
30
|
## 🚀 Quick Start
|
|
33
31
|
|
|
34
32
|
```typescript
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
// Initialize with your favorite providers
|
|
38
|
-
const ai = new SmartAi({
|
|
39
|
-
openaiToken: 'sk-...',
|
|
40
|
-
anthropicToken: 'sk-ant-...',
|
|
41
|
-
elevenlabsToken: 'sk-...',
|
|
42
|
-
elevenlabs: {
|
|
43
|
-
defaultVoiceId: '19STyYD15bswVz51nqLf', // Optional: Samara voice
|
|
44
|
-
},
|
|
45
|
-
});
|
|
33
|
+
import { getModel, generateText, streamText } from '@push.rocks/smartai';
|
|
46
34
|
|
|
47
|
-
|
|
35
|
+
// Get a model for any provider
|
|
36
|
+
const model = getModel({
|
|
37
|
+
provider: 'anthropic',
|
|
38
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
39
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
40
|
+
});
|
|
48
41
|
|
|
49
|
-
//
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
messageHistory: [],
|
|
42
|
+
// Use it with the standard AI SDK functions
|
|
43
|
+
const result = await generateText({
|
|
44
|
+
model,
|
|
45
|
+
prompt: 'Explain quantum computing in simple terms.',
|
|
54
46
|
});
|
|
55
47
|
|
|
56
|
-
console.log(
|
|
48
|
+
console.log(result.text);
|
|
57
49
|
```
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Choose the right provider for your use case:
|
|
51
|
+
That's it. Change `provider` to `'openai'` and `model` to `'gpt-4o'` and the rest of your code stays exactly the same.
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
| -------------- | :--: | :-------: | :-: | :----: | :-------: | :------: | :----: | --------------------------------------------------------------- |
|
|
65
|
-
| **OpenAI** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | gpt-image-1 • DALL-E 3 • Deep Research API |
|
|
66
|
-
| **Anthropic** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | Claude Sonnet 4.5 • Extended Thinking • Web Search API |
|
|
67
|
-
| **Mistral** | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | Native PDF OCR • mistral-large • Fast inference |
|
|
68
|
-
| **ElevenLabs** | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | Premium TTS • 70+ languages • v3 model |
|
|
69
|
-
| **Ollama** | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | 100% local • Privacy-first • No API costs |
|
|
70
|
-
| **XAI** | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | Grok 2 • Real-time data |
|
|
71
|
-
| **Perplexity** | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | Web-aware • Research-focused • Sonar Pro |
|
|
72
|
-
| **Groq** | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 10x faster • LPU inference • Llama 3.3 |
|
|
73
|
-
| **Exo** | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | Distributed • P2P compute • Decentralized |
|
|
53
|
+
## 🔧 Core API
|
|
74
54
|
|
|
75
|
-
|
|
55
|
+
### `getModel(options): LanguageModelV3`
|
|
76
56
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Works identically across all providers:
|
|
57
|
+
The primary export. Returns a standard `LanguageModelV3` you can use with any AI SDK function.
|
|
80
58
|
|
|
81
59
|
```typescript
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
systemMessage: 'You are a code reviewer.',
|
|
99
|
-
userMessage: 'Quick! Find the bug in this code: ...',
|
|
100
|
-
messageHistory: [],
|
|
101
|
-
});
|
|
60
|
+
import { getModel } from '@push.rocks/smartai';
|
|
61
|
+
import type { ISmartAiOptions } from '@push.rocks/smartai';
|
|
62
|
+
|
|
63
|
+
const options: ISmartAiOptions = {
|
|
64
|
+
provider: 'anthropic', // 'anthropic' | 'openai' | 'google' | 'groq' | 'mistral' | 'xai' | 'perplexity' | 'ollama'
|
|
65
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
66
|
+
apiKey: 'sk-ant-...',
|
|
67
|
+
// Anthropic-only: prompt caching (default: true)
|
|
68
|
+
promptCaching: true,
|
|
69
|
+
// Ollama-only: base URL (default: http://localhost:11434)
|
|
70
|
+
baseUrl: 'http://localhost:11434',
|
|
71
|
+
// Ollama-only: model runtime options
|
|
72
|
+
ollamaOptions: { think: true, num_ctx: 4096 },
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const model = getModel(options);
|
|
102
76
|
```
|
|
103
77
|
|
|
104
|
-
###
|
|
78
|
+
### Re-exported AI SDK Functions
|
|
105
79
|
|
|
106
|
-
|
|
80
|
+
SmartAI re-exports the most commonly used functions from `ai` for convenience:
|
|
107
81
|
|
|
108
82
|
```typescript
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
83
|
+
import {
|
|
84
|
+
getModel,
|
|
85
|
+
generateText,
|
|
86
|
+
streamText,
|
|
87
|
+
tool,
|
|
88
|
+
jsonSchema,
|
|
89
|
+
} from '@push.rocks/smartai';
|
|
90
|
+
|
|
91
|
+
import type {
|
|
92
|
+
ModelMessage,
|
|
93
|
+
ToolSet,
|
|
94
|
+
StreamTextResult,
|
|
95
|
+
LanguageModelV3,
|
|
96
|
+
} from '@push.rocks/smartai';
|
|
97
|
+
```
|
|
112
98
|
|
|
113
|
-
|
|
114
|
-
while (true) {
|
|
115
|
-
const { done, value } = await reader.read();
|
|
116
|
-
if (done) break;
|
|
99
|
+
## 🤖 Supported Providers
|
|
117
100
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
101
|
+
| Provider | Package | Example Models |
|
|
102
|
+
|----------|---------|----------------|
|
|
103
|
+
| **Anthropic** | `@ai-sdk/anthropic` | `claude-sonnet-4-5-20250929`, `claude-opus-4-5-20250929` |
|
|
104
|
+
| **OpenAI** | `@ai-sdk/openai` | `gpt-4o`, `gpt-4o-mini`, `o3-mini` |
|
|
105
|
+
| **Google** | `@ai-sdk/google` | `gemini-2.0-flash`, `gemini-2.5-pro` |
|
|
106
|
+
| **Groq** | `@ai-sdk/groq` | `llama-3.3-70b-versatile`, `mixtral-8x7b-32768` |
|
|
107
|
+
| **Mistral** | `@ai-sdk/mistral` | `mistral-large-latest`, `mistral-small-latest` |
|
|
108
|
+
| **XAI** | `@ai-sdk/xai` | `grok-3`, `grok-3-mini` |
|
|
109
|
+
| **Perplexity** | `@ai-sdk/perplexity` | `sonar-pro`, `sonar` |
|
|
110
|
+
| **Ollama** | Custom `LanguageModelV3` | `qwen3:8b`, `llama3:8b`, `deepseek-r1` |
|
|
122
111
|
|
|
123
|
-
|
|
112
|
+
## 💬 Text Generation
|
|
124
113
|
|
|
125
|
-
Generate
|
|
114
|
+
### Generate Text
|
|
126
115
|
|
|
127
116
|
```typescript
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
117
|
+
import { getModel, generateText } from '@push.rocks/smartai';
|
|
118
|
+
|
|
119
|
+
const model = getModel({
|
|
120
|
+
provider: 'openai',
|
|
121
|
+
model: 'gpt-4o',
|
|
122
|
+
apiKey: process.env.OPENAI_TOKEN,
|
|
131
123
|
});
|
|
132
124
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
modelId: 'eleven_v3', // Optional: defaults to eleven_v3 (70+ languages)
|
|
138
|
-
voiceSettings: {
|
|
139
|
-
// Optional: fine-tune voice characteristics
|
|
140
|
-
stability: 0.5, // 0-1: Speech consistency
|
|
141
|
-
similarity_boost: 0.8, // 0-1: Voice similarity to original
|
|
142
|
-
style: 0.0, // 0-1: Expressiveness
|
|
143
|
-
use_speaker_boost: true, // Enhanced clarity
|
|
144
|
-
},
|
|
125
|
+
const result = await generateText({
|
|
126
|
+
model,
|
|
127
|
+
system: 'You are a helpful assistant.',
|
|
128
|
+
prompt: 'What is 2 + 2?',
|
|
145
129
|
});
|
|
146
130
|
|
|
147
|
-
//
|
|
148
|
-
audioStream.pipe(fs.createWriteStream('welcome.mp3'));
|
|
131
|
+
console.log(result.text); // "4"
|
|
149
132
|
```
|
|
150
133
|
|
|
151
|
-
###
|
|
152
|
-
|
|
153
|
-
Understand images with multiple providers:
|
|
134
|
+
### Stream Text
|
|
154
135
|
|
|
155
136
|
```typescript
|
|
156
|
-
|
|
137
|
+
import { getModel, streamText } from '@push.rocks/smartai';
|
|
157
138
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
139
|
+
const model = getModel({
|
|
140
|
+
provider: 'anthropic',
|
|
141
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
142
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
162
143
|
});
|
|
163
144
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
prompt: 'Identify any safety concerns or defects',
|
|
145
|
+
const result = await streamText({
|
|
146
|
+
model,
|
|
147
|
+
prompt: 'Count from 1 to 10.',
|
|
168
148
|
});
|
|
169
149
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
prompt: 'Extract all text and categorize the content',
|
|
174
|
-
});
|
|
150
|
+
for await (const chunk of result.textStream) {
|
|
151
|
+
process.stdout.write(chunk);
|
|
152
|
+
}
|
|
175
153
|
```
|
|
176
154
|
|
|
177
|
-
###
|
|
178
|
-
|
|
179
|
-
Extract insights from PDFs with AI:
|
|
155
|
+
### Tool Calling
|
|
180
156
|
|
|
181
157
|
```typescript
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
userMessage: 'Compare these documents and highlight key differences',
|
|
189
|
-
messageHistory: [],
|
|
190
|
-
pdfDocuments: [contract, invoice],
|
|
158
|
+
import { getModel, generateText, tool, jsonSchema } from '@push.rocks/smartai';
|
|
159
|
+
|
|
160
|
+
const model = getModel({
|
|
161
|
+
provider: 'anthropic',
|
|
162
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
163
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
191
164
|
});
|
|
192
165
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
166
|
+
const result = await generateText({
|
|
167
|
+
model,
|
|
168
|
+
prompt: 'What is the weather in London?',
|
|
169
|
+
tools: {
|
|
170
|
+
getWeather: tool({
|
|
171
|
+
description: 'Get weather for a location',
|
|
172
|
+
parameters: jsonSchema({
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
location: { type: 'string' },
|
|
176
|
+
},
|
|
177
|
+
required: ['location'],
|
|
178
|
+
}),
|
|
179
|
+
execute: async ({ location }) => {
|
|
180
|
+
return { temperature: 18, condition: 'cloudy' };
|
|
181
|
+
},
|
|
182
|
+
}),
|
|
183
|
+
},
|
|
200
184
|
});
|
|
201
185
|
```
|
|
202
186
|
|
|
203
|
-
|
|
187
|
+
## 🏠 Ollama (Local Models)
|
|
204
188
|
|
|
205
|
-
|
|
189
|
+
The custom Ollama provider implements `LanguageModelV3` directly, calling Ollama's native `/api/chat` endpoint. This gives you features that generic OpenAI-compatible wrappers miss:
|
|
206
190
|
|
|
207
191
|
```typescript
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
import { AnthropicProvider } from '@push.rocks/smartai';
|
|
220
|
-
|
|
221
|
-
const anthropic = new AnthropicProvider({
|
|
222
|
-
anthropicToken: 'sk-ant-...',
|
|
223
|
-
enableWebSearch: true,
|
|
224
|
-
searchDomainAllowList: ['nature.com', 'science.org'],
|
|
192
|
+
import { getModel, generateText } from '@push.rocks/smartai';
|
|
193
|
+
|
|
194
|
+
const model = getModel({
|
|
195
|
+
provider: 'ollama',
|
|
196
|
+
model: 'qwen3:8b',
|
|
197
|
+
baseUrl: 'http://localhost:11434', // default
|
|
198
|
+
ollamaOptions: {
|
|
199
|
+
think: true, // Enable thinking/reasoning mode
|
|
200
|
+
num_ctx: 8192, // Context window size
|
|
201
|
+
temperature: 0.7, // Override default (Qwen models auto-default to 0.55)
|
|
202
|
+
},
|
|
225
203
|
});
|
|
226
204
|
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
205
|
+
const result = await generateText({
|
|
206
|
+
model,
|
|
207
|
+
prompt: 'Solve this step by step: what is 15% of 340?',
|
|
230
208
|
});
|
|
231
209
|
|
|
232
|
-
|
|
233
|
-
const perplexityResearch = await ai.perplexityProvider.research({
|
|
234
|
-
query: 'Current state of autonomous vehicle technology',
|
|
235
|
-
searchDepth: 'deep', // Uses Sonar Pro model
|
|
236
|
-
});
|
|
210
|
+
console.log(result.text);
|
|
237
211
|
```
|
|
238
212
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
- `searchDepth`: `'basic'` | `'advanced'` | `'deep'`
|
|
242
|
-
- `maxSources`: Number of sources to include
|
|
243
|
-
- `includeWebSearch`: Enable web search (OpenAI)
|
|
244
|
-
- `background`: Run as background task (OpenAI)
|
|
213
|
+
### Ollama Features
|
|
245
214
|
|
|
246
|
-
**
|
|
215
|
+
- **`think` mode** — Enables reasoning for models that support it (Qwen3, QwQ, DeepSeek-R1). The `think` parameter is sent at the top level of the request body as required by the Ollama API.
|
|
216
|
+
- **Auto-tuned temperature** — Qwen models automatically get `temperature: 0.55` when no explicit temperature is set, matching the recommended inference setting.
|
|
217
|
+
- **Native tool calling** — Full tool call support via Ollama's native format (not shimmed through OpenAI-compatible endpoints).
|
|
218
|
+
- **Streaming with reasoning** — `doStream()` emits proper `reasoning-start`, `reasoning-delta`, `reasoning-end` parts alongside text.
|
|
219
|
+
- **All Ollama options** — `num_ctx`, `top_k`, `top_p`, `repeat_penalty`, `num_predict`, `stop`, `seed`.
|
|
247
220
|
|
|
248
|
-
|
|
249
|
-
- **Anthropic**: Web Search API with domain filtering
|
|
250
|
-
- **Perplexity**: Sonar and Sonar Pro models with built-in citations
|
|
221
|
+
## 💰 Anthropic Prompt Caching
|
|
251
222
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
Enable Claude to spend more time reasoning about complex problems before generating responses:
|
|
223
|
+
When using the Anthropic provider, SmartAI automatically wraps the model with caching middleware that adds `cacheControl: { type: 'ephemeral' }` to the last system message and last user message. This can significantly reduce cost and latency for repeated calls with the same system prompt.
|
|
255
224
|
|
|
256
225
|
```typescript
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
extendedThinking: 'normal', // Options: 'quick' | 'normal' | 'deep' | 'off'
|
|
226
|
+
// Caching enabled by default
|
|
227
|
+
const model = getModel({
|
|
228
|
+
provider: 'anthropic',
|
|
229
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
230
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
263
231
|
});
|
|
264
232
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
messageHistory: [],
|
|
233
|
+
// Opt out of caching
|
|
234
|
+
const modelNoCaching = getModel({
|
|
235
|
+
provider: 'anthropic',
|
|
236
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
237
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
238
|
+
promptCaching: false,
|
|
272
239
|
});
|
|
273
240
|
```
|
|
274
241
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
| Mode | Budget Tokens | Use Case |
|
|
278
|
-
| ---------- | ------------- | ------------------------------------------------ |
|
|
279
|
-
| `'quick'` | 2,048 | Lightweight reasoning for simple queries |
|
|
280
|
-
| `'normal'` | 8,000 | **Default** — Balanced reasoning for most tasks |
|
|
281
|
-
| `'deep'` | 16,000 | Complex reasoning for difficult problems |
|
|
282
|
-
| `'off'` | 0 | Disable extended thinking |
|
|
283
|
-
|
|
284
|
-
**Best Practices:**
|
|
285
|
-
|
|
286
|
-
- Start with `'normal'` (default) for general usage
|
|
287
|
-
- Use `'deep'` for complex analytical tasks, philosophy, mathematics, or research
|
|
288
|
-
- Use `'quick'` for simple factual queries where deep reasoning isn't needed
|
|
289
|
-
- Thinking budget counts against total token usage
|
|
290
|
-
|
|
291
|
-
### 📑 Native PDF OCR (Mistral)
|
|
292
|
-
|
|
293
|
-
Mistral provides native PDF document processing via their OCR API — no image conversion required:
|
|
242
|
+
You can also use the middleware directly:
|
|
294
243
|
|
|
295
244
|
```typescript
|
|
296
|
-
import {
|
|
297
|
-
|
|
298
|
-
const mistral = new MistralProvider({
|
|
299
|
-
mistralToken: 'your-api-key',
|
|
300
|
-
chatModel: 'mistral-large-latest', // Default
|
|
301
|
-
ocrModel: 'mistral-ocr-latest', // Default
|
|
302
|
-
tableFormat: 'markdown', // 'markdown' | 'html'
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
await mistral.start();
|
|
245
|
+
import { createAnthropicCachingMiddleware } from '@push.rocks/smartai';
|
|
246
|
+
import { wrapLanguageModel } from 'ai';
|
|
306
247
|
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
systemMessage: 'You are a document analyst.',
|
|
310
|
-
userMessage: 'Extract all invoice details and calculate the total.',
|
|
311
|
-
pdfDocuments: [invoicePdfBuffer],
|
|
312
|
-
messageHistory: [],
|
|
313
|
-
});
|
|
248
|
+
const middleware = createAnthropicCachingMiddleware();
|
|
249
|
+
const cachedModel = wrapLanguageModel({ model: baseModel, middleware });
|
|
314
250
|
```
|
|
315
251
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
**Supported Formats:**
|
|
252
|
+
## 📦 Subpath Exports
|
|
319
253
|
|
|
320
|
-
|
|
321
|
-
- Image OCR (JPEG, PNG, GIF, WebP) for vision tasks
|
|
322
|
-
- Table extraction with markdown or HTML output
|
|
254
|
+
SmartAI provides specialized capabilities as separate subpath imports. Each one is a focused utility that takes a model (or API key) and does one thing well.
|
|
323
255
|
|
|
324
|
-
###
|
|
256
|
+
### 👁️ Vision — `@push.rocks/smartai/vision`
|
|
325
257
|
|
|
326
|
-
|
|
258
|
+
Analyze images using any vision-capable model.
|
|
327
259
|
|
|
328
260
|
```typescript
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
// Save the generated image
|
|
338
|
-
const imageBuffer = Buffer.from(image.images[0].b64_json!, 'base64');
|
|
339
|
-
fs.writeFileSync('robot.png', imageBuffer);
|
|
340
|
-
|
|
341
|
-
// Advanced: Transparent background with custom format
|
|
342
|
-
const logo = await ai.openaiProvider.imageGenerate({
|
|
343
|
-
prompt: 'Minimalist mountain peak logo, geometric design',
|
|
344
|
-
model: 'gpt-image-1',
|
|
345
|
-
quality: 'high',
|
|
346
|
-
size: '1024x1024',
|
|
347
|
-
background: 'transparent',
|
|
348
|
-
outputFormat: 'png',
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
// WebP with compression for web use
|
|
352
|
-
const webImage = await ai.openaiProvider.imageGenerate({
|
|
353
|
-
prompt: 'Product showcase: sleek smartphone on marble surface',
|
|
354
|
-
model: 'gpt-image-1',
|
|
355
|
-
quality: 'high',
|
|
356
|
-
size: '1536x1024',
|
|
357
|
-
outputFormat: 'webp',
|
|
358
|
-
outputCompression: 85,
|
|
261
|
+
import { analyzeImage } from '@push.rocks/smartai/vision';
|
|
262
|
+
import { getModel } from '@push.rocks/smartai';
|
|
263
|
+
import * as fs from 'fs';
|
|
264
|
+
|
|
265
|
+
const model = getModel({
|
|
266
|
+
provider: 'anthropic',
|
|
267
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
268
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
359
269
|
});
|
|
360
270
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
quality: 'high',
|
|
367
|
-
size: '1024x1024',
|
|
271
|
+
const description = await analyzeImage({
|
|
272
|
+
model,
|
|
273
|
+
image: fs.readFileSync('photo.jpg'),
|
|
274
|
+
prompt: 'Describe this image in detail.',
|
|
275
|
+
mediaType: 'image/jpeg', // optional, defaults to 'image/jpeg'
|
|
368
276
|
});
|
|
369
277
|
|
|
370
|
-
|
|
371
|
-
const variations = await ai.openaiProvider.imageGenerate({
|
|
372
|
-
prompt: 'Abstract geometric pattern, colorful minimalist art',
|
|
373
|
-
model: 'gpt-image-1',
|
|
374
|
-
n: 3,
|
|
375
|
-
quality: 'medium',
|
|
376
|
-
size: '1024x1024',
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// Edit an existing image
|
|
380
|
-
const editedImage = await ai.openaiProvider.imageEdit({
|
|
381
|
-
image: originalImageBuffer,
|
|
382
|
-
prompt: 'Add sunglasses and change the background to a beach sunset',
|
|
383
|
-
model: 'gpt-image-1',
|
|
384
|
-
quality: 'high',
|
|
385
|
-
});
|
|
278
|
+
console.log(description);
|
|
386
279
|
```
|
|
387
280
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
- `
|
|
391
|
-
- `
|
|
392
|
-
- `
|
|
393
|
-
- `background`: `'transparent'` | `'opaque'` | `'auto'`
|
|
394
|
-
- `outputFormat`: `'png'` | `'jpeg'` | `'webp'`
|
|
395
|
-
- `outputCompression`: 0–100 for webp/jpeg
|
|
396
|
-
- `moderation`: `'low'` | `'auto'`
|
|
397
|
-
- `n`: Number of images (1–10)
|
|
398
|
-
|
|
399
|
-
**gpt-image-1 Advantages:**
|
|
400
|
-
|
|
401
|
-
- Superior text rendering in images
|
|
402
|
-
- Up to 4096×4096 resolution
|
|
403
|
-
- Transparent background support
|
|
404
|
-
- Advanced output formats (WebP with compression)
|
|
405
|
-
- Better prompt understanding
|
|
406
|
-
- Streaming support for progressive rendering
|
|
281
|
+
**`analyzeImage(options)`** accepts:
|
|
282
|
+
- `model` — Any `LanguageModelV3` with vision support
|
|
283
|
+
- `image` — `Buffer` or `Uint8Array`
|
|
284
|
+
- `prompt` — What to ask about the image
|
|
285
|
+
- `mediaType` — `'image/jpeg'` | `'image/png'` | `'image/webp'` | `'image/gif'`
|
|
407
286
|
|
|
408
|
-
###
|
|
287
|
+
### 🎙️ Audio — `@push.rocks/smartai/audio`
|
|
409
288
|
|
|
410
|
-
|
|
289
|
+
Text-to-speech using OpenAI's TTS models.
|
|
411
290
|
|
|
412
291
|
```typescript
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
//
|
|
422
|
-
|
|
292
|
+
import { textToSpeech } from '@push.rocks/smartai/audio';
|
|
293
|
+
import * as fs from 'fs';
|
|
294
|
+
|
|
295
|
+
const stream = await textToSpeech({
|
|
296
|
+
apiKey: process.env.OPENAI_TOKEN,
|
|
297
|
+
text: 'Welcome to the future of AI development!',
|
|
298
|
+
voice: 'nova', // 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer'
|
|
299
|
+
model: 'tts-1-hd', // 'tts-1' | 'tts-1-hd'
|
|
300
|
+
responseFormat: 'mp3', // 'mp3' | 'opus' | 'aac' | 'flac'
|
|
301
|
+
speed: 1.0, // 0.25 to 4.0
|
|
302
|
+
});
|
|
423
303
|
|
|
424
|
-
|
|
304
|
+
stream.pipe(fs.createWriteStream('welcome.mp3'));
|
|
425
305
|
```
|
|
426
306
|
|
|
427
|
-
|
|
307
|
+
### 🎨 Image — `@push.rocks/smartai/image`
|
|
428
308
|
|
|
429
|
-
|
|
309
|
+
Generate and edit images using OpenAI's image models.
|
|
430
310
|
|
|
431
311
|
```typescript
|
|
432
|
-
|
|
433
|
-
|
|
312
|
+
import { generateImage, editImage } from '@push.rocks/smartai/image';
|
|
313
|
+
|
|
314
|
+
// Generate an image
|
|
315
|
+
const result = await generateImage({
|
|
316
|
+
apiKey: process.env.OPENAI_TOKEN,
|
|
317
|
+
prompt: 'A futuristic cityscape at sunset, digital art',
|
|
318
|
+
model: 'gpt-image-1', // 'gpt-image-1' | 'dall-e-3' | 'dall-e-2'
|
|
319
|
+
quality: 'high', // 'low' | 'medium' | 'high' | 'auto'
|
|
320
|
+
size: '1024x1024',
|
|
321
|
+
background: 'transparent', // gpt-image-1 only
|
|
322
|
+
outputFormat: 'png', // 'png' | 'jpeg' | 'webp'
|
|
323
|
+
n: 1,
|
|
434
324
|
});
|
|
435
325
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const response = await supportBot.anthropicProvider.chat({
|
|
439
|
-
systemMessage: `You are a helpful customer support agent.
|
|
440
|
-
Be empathetic, professional, and solution-oriented.`,
|
|
441
|
-
userMessage: query,
|
|
442
|
-
messageHistory: history,
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
return response.message;
|
|
446
|
-
} catch (error) {
|
|
447
|
-
// Fallback to another provider if needed
|
|
448
|
-
return await supportBot.openaiProvider.chat({ /* ... */ });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
### Create a Code Review Assistant
|
|
326
|
+
// result.images[0].b64_json — base64-encoded image data
|
|
327
|
+
const imageBuffer = Buffer.from(result.images[0].b64_json!, 'base64');
|
|
454
328
|
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
|
|
329
|
+
// Edit an existing image
|
|
330
|
+
const edited = await editImage({
|
|
331
|
+
apiKey: process.env.OPENAI_TOKEN,
|
|
332
|
+
image: imageBuffer,
|
|
333
|
+
prompt: 'Add a rainbow in the sky',
|
|
334
|
+
model: 'gpt-image-1',
|
|
458
335
|
});
|
|
459
|
-
|
|
460
|
-
async function reviewCode(code: string, language: string) {
|
|
461
|
-
const review = await codeReviewer.groqProvider.chat({
|
|
462
|
-
systemMessage: `You are a ${language} expert. Review code for:
|
|
463
|
-
- Security vulnerabilities
|
|
464
|
-
- Performance issues
|
|
465
|
-
- Best practices
|
|
466
|
-
- Potential bugs`,
|
|
467
|
-
userMessage: `Review this code:\n\n${code}`,
|
|
468
|
-
messageHistory: [],
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
return review.message;
|
|
472
|
-
}
|
|
473
336
|
```
|
|
474
337
|
|
|
475
|
-
###
|
|
338
|
+
### 📄 Document — `@push.rocks/smartai/document`
|
|
339
|
+
|
|
340
|
+
Analyze PDF documents by converting them to images and using a vision model. Uses `@push.rocks/smartpdf` for PDF-to-PNG conversion (requires Chromium/Puppeteer).
|
|
476
341
|
|
|
477
342
|
```typescript
|
|
478
|
-
|
|
479
|
-
|
|
343
|
+
import { analyzeDocuments, stopSmartpdf } from '@push.rocks/smartai/document';
|
|
344
|
+
import { getModel } from '@push.rocks/smartai';
|
|
345
|
+
import * as fs from 'fs';
|
|
346
|
+
|
|
347
|
+
const model = getModel({
|
|
348
|
+
provider: 'anthropic',
|
|
349
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
350
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
480
351
|
});
|
|
481
352
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
return {
|
|
490
|
-
answer: findings.answer,
|
|
491
|
-
sources: findings.sources,
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
### Local AI for Sensitive Data
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
const localAI = new SmartAi({
|
|
500
|
-
ollama: {
|
|
501
|
-
baseUrl: 'http://localhost:11434',
|
|
502
|
-
model: 'llama2',
|
|
503
|
-
visionModel: 'llava',
|
|
504
|
-
},
|
|
353
|
+
const analysis = await analyzeDocuments({
|
|
354
|
+
model,
|
|
355
|
+
systemMessage: 'You are a legal document analyst.',
|
|
356
|
+
userMessage: 'Summarize the key terms and conditions.',
|
|
357
|
+
pdfDocuments: [fs.readFileSync('contract.pdf')],
|
|
358
|
+
messageHistory: [], // optional: prior conversation context
|
|
505
359
|
});
|
|
506
360
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
userMessage: 'Analyze this confidential document',
|
|
512
|
-
messageHistory: [],
|
|
513
|
-
pdfDocuments: [pdfBuffer],
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
// Data never leaves your servers
|
|
517
|
-
return analysis.message;
|
|
518
|
-
}
|
|
361
|
+
console.log(analysis);
|
|
362
|
+
|
|
363
|
+
// Clean up the SmartPdf instance when done
|
|
364
|
+
await stopSmartpdf();
|
|
519
365
|
```
|
|
520
366
|
|
|
521
|
-
|
|
367
|
+
### 🔬 Research — `@push.rocks/smartai/research`
|
|
522
368
|
|
|
523
|
-
|
|
369
|
+
Perform web-search-powered research using Anthropic's `web_search_20250305` tool.
|
|
524
370
|
|
|
525
371
|
```typescript
|
|
526
|
-
|
|
527
|
-
constructor(private ai: SmartAi) {}
|
|
528
|
-
|
|
529
|
-
async query(
|
|
530
|
-
message: string,
|
|
531
|
-
requirements: {
|
|
532
|
-
speed?: boolean;
|
|
533
|
-
accuracy?: boolean;
|
|
534
|
-
cost?: boolean;
|
|
535
|
-
privacy?: boolean;
|
|
536
|
-
}
|
|
537
|
-
) {
|
|
538
|
-
if (requirements.privacy) {
|
|
539
|
-
return this.ai.ollamaProvider.chat({ /* ... */ }); // Local only
|
|
540
|
-
}
|
|
541
|
-
if (requirements.speed) {
|
|
542
|
-
return this.ai.groqProvider.chat({ /* ... */ }); // 10x faster
|
|
543
|
-
}
|
|
544
|
-
if (requirements.accuracy) {
|
|
545
|
-
return this.ai.anthropicProvider.chat({ /* ... */ }); // Best reasoning
|
|
546
|
-
}
|
|
547
|
-
// Default fallback
|
|
548
|
-
return this.ai.openaiProvider.chat({ /* ... */ });
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
```
|
|
372
|
+
import { research } from '@push.rocks/smartai/research';
|
|
552
373
|
|
|
553
|
-
|
|
374
|
+
const result = await research({
|
|
375
|
+
apiKey: process.env.ANTHROPIC_TOKEN,
|
|
376
|
+
query: 'What are the latest developments in quantum computing?',
|
|
377
|
+
searchDepth: 'basic', // 'basic' | 'advanced' | 'deep'
|
|
378
|
+
maxSources: 10, // optional: limit number of search results
|
|
379
|
+
allowedDomains: ['nature.com', 'arxiv.org'], // optional: restrict to domains
|
|
380
|
+
blockedDomains: ['reddit.com'], // optional: exclude domains
|
|
381
|
+
});
|
|
554
382
|
|
|
555
|
-
|
|
556
|
-
//
|
|
557
|
-
|
|
558
|
-
const stream = await ai.openaiProvider.chatStream(
|
|
559
|
-
createInputStream(userQuery)
|
|
560
|
-
);
|
|
561
|
-
|
|
562
|
-
// Process tokens as they arrive
|
|
563
|
-
for await (const chunk of stream) {
|
|
564
|
-
updateUI(chunk); // Immediate feedback
|
|
565
|
-
await processChunk(chunk); // Parallel processing
|
|
566
|
-
}
|
|
567
|
-
}
|
|
383
|
+
console.log(result.answer);
|
|
384
|
+
console.log('Sources:', result.sources); // Array<{ url, title, snippet }>
|
|
385
|
+
console.log('Queries:', result.searchQueries); // search queries the model used
|
|
568
386
|
```
|
|
569
387
|
|
|
570
|
-
|
|
388
|
+
## 🧪 Testing
|
|
571
389
|
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
390
|
+
```bash
|
|
391
|
+
# All tests
|
|
392
|
+
pnpm test
|
|
393
|
+
|
|
394
|
+
# Individual test files
|
|
395
|
+
tstest test/test.smartai.ts --verbose # Core getModel + generateText + streamText
|
|
396
|
+
tstest test/test.ollama.ts --verbose # Ollama provider (mocked, no API needed)
|
|
397
|
+
tstest test/test.vision.ts --verbose # Vision analysis
|
|
398
|
+
tstest test/test.image.ts --verbose # Image generation
|
|
399
|
+
tstest test/test.research.ts --verbose # Web research
|
|
400
|
+
tstest test/test.audio.ts --verbose # Text-to-speech
|
|
401
|
+
tstest test/test.document.ts --verbose # Document analysis (needs Chromium)
|
|
584
402
|
```
|
|
585
403
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
### Provider-Specific Options
|
|
589
|
-
|
|
590
|
-
```typescript
|
|
591
|
-
const ai = new SmartAi({
|
|
592
|
-
// OpenAI
|
|
593
|
-
openaiToken: 'sk-...',
|
|
594
|
-
|
|
595
|
-
// Anthropic with extended thinking
|
|
596
|
-
anthropicToken: 'sk-ant-...',
|
|
597
|
-
|
|
598
|
-
// Perplexity for research
|
|
599
|
-
perplexityToken: 'pplx-...',
|
|
404
|
+
Most tests skip gracefully when API keys are not set. The Ollama tests are fully mocked and require no external services.
|
|
600
405
|
|
|
601
|
-
|
|
602
|
-
groqToken: 'gsk_...',
|
|
406
|
+
## 📐 Architecture
|
|
603
407
|
|
|
604
|
-
// Mistral with OCR settings
|
|
605
|
-
mistralToken: 'your-key',
|
|
606
|
-
mistral: {
|
|
607
|
-
chatModel: 'mistral-large-latest',
|
|
608
|
-
ocrModel: 'mistral-ocr-latest',
|
|
609
|
-
tableFormat: 'markdown',
|
|
610
|
-
},
|
|
611
|
-
|
|
612
|
-
// XAI (Grok)
|
|
613
|
-
xaiToken: 'xai-...',
|
|
614
|
-
|
|
615
|
-
// ElevenLabs TTS
|
|
616
|
-
elevenlabsToken: 'sk-...',
|
|
617
|
-
elevenlabs: {
|
|
618
|
-
defaultVoiceId: '19STyYD15bswVz51nqLf',
|
|
619
|
-
defaultModelId: 'eleven_v3',
|
|
620
|
-
},
|
|
621
|
-
|
|
622
|
-
// Ollama (local)
|
|
623
|
-
ollama: {
|
|
624
|
-
baseUrl: 'http://localhost:11434',
|
|
625
|
-
model: 'llama2',
|
|
626
|
-
visionModel: 'llava',
|
|
627
|
-
defaultOptions: {
|
|
628
|
-
num_ctx: 4096,
|
|
629
|
-
temperature: 0.7,
|
|
630
|
-
top_p: 0.9,
|
|
631
|
-
},
|
|
632
|
-
defaultTimeout: 120000,
|
|
633
|
-
},
|
|
634
|
-
|
|
635
|
-
// Exo (distributed)
|
|
636
|
-
exo: {
|
|
637
|
-
baseUrl: 'http://localhost:8080/v1',
|
|
638
|
-
apiKey: 'optional-key',
|
|
639
|
-
},
|
|
640
|
-
});
|
|
641
408
|
```
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
continue;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
throw new Error('All providers failed');
|
|
659
|
-
}
|
|
660
|
-
}
|
|
409
|
+
@push.rocks/smartai
|
|
410
|
+
├── ts/ # Core package
|
|
411
|
+
│ ├── index.ts # Re-exports getModel, AI SDK functions, types
|
|
412
|
+
│ ├── smartai.classes.smartai.ts # getModel() — provider switch
|
|
413
|
+
│ ├── smartai.interfaces.ts # ISmartAiOptions, TProvider, IOllamaModelOptions
|
|
414
|
+
│ ├── smartai.provider.ollama.ts # Custom LanguageModelV3 for Ollama
|
|
415
|
+
│ ├── smartai.middleware.anthropic.ts # Prompt caching middleware
|
|
416
|
+
│ └── plugins.ts # AI SDK provider factories
|
|
417
|
+
├── ts_vision/ # @push.rocks/smartai/vision
|
|
418
|
+
├── ts_audio/ # @push.rocks/smartai/audio
|
|
419
|
+
├── ts_image/ # @push.rocks/smartai/image
|
|
420
|
+
├── ts_document/ # @push.rocks/smartai/document
|
|
421
|
+
└── ts_research/ # @push.rocks/smartai/research
|
|
661
422
|
```
|
|
662
423
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
| --------------------- | -------------------- | --------------------------------------------------------- |
|
|
667
|
-
| **General Purpose** | OpenAI | Most features, stable, well-documented |
|
|
668
|
-
| **Complex Reasoning** | Anthropic | Superior logical thinking, extended thinking, safer |
|
|
669
|
-
| **Document OCR** | Mistral | Native PDF processing, no image conversion overhead |
|
|
670
|
-
| **Research & Facts** | Perplexity | Web-aware, provides citations |
|
|
671
|
-
| **Deep Research** | OpenAI | Deep Research API with comprehensive analysis |
|
|
672
|
-
| **Premium TTS** | ElevenLabs | Most natural voices, 70+ languages, v3 model |
|
|
673
|
-
| **Speed Critical** | Groq | 10x faster inference, sub-second responses |
|
|
674
|
-
| **Privacy Critical** | Ollama | 100% local, no data leaves your servers |
|
|
675
|
-
| **Real-time Data** | XAI | Grok with access to current information |
|
|
676
|
-
| **Cost Sensitive** | Ollama/Exo | Free (local) or distributed compute |
|
|
677
|
-
|
|
678
|
-
## 📈 Roadmap
|
|
679
|
-
|
|
680
|
-
- [x] Research & Web Search API
|
|
681
|
-
- [x] Image generation support (gpt-image-1, DALL-E 3, DALL-E 2)
|
|
682
|
-
- [x] Extended thinking (Anthropic)
|
|
683
|
-
- [x] Native PDF OCR (Mistral)
|
|
684
|
-
- [ ] Streaming function calls
|
|
685
|
-
- [ ] Voice input processing
|
|
686
|
-
- [ ] Fine-tuning integration
|
|
687
|
-
- [ ] Embedding support
|
|
688
|
-
- [ ] Agent framework
|
|
689
|
-
- [ ] More providers (Cohere, AI21, etc.)
|
|
424
|
+
The core package is a thin registry. `getModel()` creates the appropriate `@ai-sdk/*` provider, calls it with the model ID, and returns the resulting `LanguageModelV3`. For Anthropic, it optionally wraps the model with prompt caching middleware. For Ollama, it returns a custom `LanguageModelV3` implementation that talks directly to Ollama's `/api/chat` endpoint.
|
|
425
|
+
|
|
426
|
+
Subpath modules are independent — they import `ai` and provider SDKs directly, not through the core package. This keeps the dependency graph clean and allows tree-shaking.
|
|
690
427
|
|
|
691
428
|
## License and Legal Information
|
|
692
429
|
|