@push.rocks/smartai 0.6.1 → 0.7.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.
@@ -50,6 +50,60 @@ export interface ResearchResponse {
50
50
  metadata?: any;
51
51
  }
52
52
 
53
+ /**
54
+ * Options for image generation
55
+ */
56
+ export interface ImageGenerateOptions {
57
+ prompt: string;
58
+ model?: 'gpt-image-1' | 'dall-e-3' | 'dall-e-2';
59
+ quality?: 'low' | 'medium' | 'high' | 'standard' | 'hd' | 'auto';
60
+ size?: '256x256' | '512x512' | '1024x1024' | '1536x1024' | '1024x1536' | '1792x1024' | '1024x1792' | 'auto';
61
+ style?: 'vivid' | 'natural';
62
+ background?: 'transparent' | 'opaque' | 'auto';
63
+ outputFormat?: 'png' | 'jpeg' | 'webp';
64
+ outputCompression?: number; // 0-100 for webp/jpeg
65
+ moderation?: 'low' | 'auto';
66
+ n?: number; // Number of images to generate
67
+ stream?: boolean;
68
+ partialImages?: number; // 0-3 for streaming
69
+ }
70
+
71
+ /**
72
+ * Options for image editing
73
+ */
74
+ export interface ImageEditOptions {
75
+ image: Buffer;
76
+ prompt: string;
77
+ mask?: Buffer;
78
+ model?: 'gpt-image-1' | 'dall-e-2';
79
+ quality?: 'low' | 'medium' | 'high' | 'standard' | 'auto';
80
+ size?: '256x256' | '512x512' | '1024x1024' | '1536x1024' | '1024x1536' | 'auto';
81
+ background?: 'transparent' | 'opaque' | 'auto';
82
+ outputFormat?: 'png' | 'jpeg' | 'webp';
83
+ outputCompression?: number;
84
+ n?: number;
85
+ stream?: boolean;
86
+ partialImages?: number;
87
+ }
88
+
89
+ /**
90
+ * Response format for image operations
91
+ */
92
+ export interface ImageResponse {
93
+ images: Array<{
94
+ b64_json?: string;
95
+ url?: string;
96
+ revisedPrompt?: string;
97
+ }>;
98
+ metadata?: {
99
+ model: string;
100
+ quality?: string;
101
+ size?: string;
102
+ outputFormat?: string;
103
+ tokensUsed?: number;
104
+ };
105
+ }
106
+
53
107
  /**
54
108
  * Abstract base class for multi-modal AI models.
55
109
  * Provides a common interface for different AI providers (OpenAI, Anthropic, Perplexity, Ollama)
@@ -131,4 +185,20 @@ export abstract class MultiModalModel {
131
185
  * @throws Error if the provider doesn't support research capabilities
132
186
  */
133
187
  public abstract research(optionsArg: ResearchOptions): Promise<ResearchResponse>;
188
+
189
+ /**
190
+ * Image generation from text prompts
191
+ * @param optionsArg Options containing the prompt and generation parameters
192
+ * @returns Promise resolving to the generated image(s)
193
+ * @throws Error if the provider doesn't support image generation
194
+ */
195
+ public abstract imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse>;
196
+
197
+ /**
198
+ * Image editing and inpainting
199
+ * @param optionsArg Options containing the image, prompt, and editing parameters
200
+ * @returns Promise resolving to the edited image(s)
201
+ * @throws Error if the provider doesn't support image editing
202
+ */
203
+ public abstract imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse>;
134
204
  }
@@ -1,7 +1,16 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import * as paths from './paths.js';
3
3
  import { MultiModalModel } from './abstract.classes.multimodal.js';
4
- import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
4
+ import type {
5
+ ChatOptions,
6
+ ChatResponse,
7
+ ChatMessage,
8
+ ResearchOptions,
9
+ ResearchResponse,
10
+ ImageGenerateOptions,
11
+ ImageEditOptions,
12
+ ImageResponse
13
+ } from './abstract.classes.multimodal.js';
5
14
  import type { ImageBlockParam, TextBlockParam } from '@anthropic-ai/sdk/resources/messages';
6
15
 
7
16
  type ContentBlock = ImageBlockParam | TextBlockParam;
@@ -68,7 +77,7 @@ export class AnthropicProvider extends MultiModalModel {
68
77
  // If we have a complete message, send it to Anthropic
69
78
  if (currentMessage) {
70
79
  const stream = await this.anthropicApiClient.messages.create({
71
- model: 'claude-3-opus-20240229',
80
+ model: 'claude-sonnet-4-5-20250929',
72
81
  messages: [{ role: currentMessage.role, content: currentMessage.content }],
73
82
  system: '',
74
83
  stream: true,
@@ -112,7 +121,7 @@ export class AnthropicProvider extends MultiModalModel {
112
121
  }));
113
122
 
114
123
  const result = await this.anthropicApiClient.messages.create({
115
- model: 'claude-3-opus-20240229',
124
+ model: 'claude-sonnet-4-5-20250929',
116
125
  system: optionsArg.systemMessage,
117
126
  messages: [
118
127
  ...messages,
@@ -159,7 +168,7 @@ export class AnthropicProvider extends MultiModalModel {
159
168
  ];
160
169
 
161
170
  const result = await this.anthropicApiClient.messages.create({
162
- model: 'claude-3-opus-20240229',
171
+ model: 'claude-sonnet-4-5-20250929',
163
172
  messages: [{
164
173
  role: 'user',
165
174
  content
@@ -218,7 +227,7 @@ export class AnthropicProvider extends MultiModalModel {
218
227
  }
219
228
 
220
229
  const result = await this.anthropicApiClient.messages.create({
221
- model: 'claude-3-opus-20240229',
230
+ model: 'claude-sonnet-4-5-20250929',
222
231
  system: optionsArg.systemMessage,
223
232
  messages: [
224
233
  ...messages,
@@ -251,23 +260,27 @@ export class AnthropicProvider extends MultiModalModel {
251
260
 
252
261
  try {
253
262
  // Build the tool configuration for web search
254
- const tools = this.options.enableWebSearch ? [
255
- {
256
- type: 'web_search_20250305' as const,
257
- name: 'web_search',
258
- description: 'Search the web for current information',
259
- input_schema: {
260
- type: 'object' as const,
261
- properties: {
262
- query: {
263
- type: 'string',
264
- description: 'The search query'
265
- }
266
- },
267
- required: ['query']
268
- }
263
+ const tools: any[] = [];
264
+
265
+ if (this.options.enableWebSearch) {
266
+ const webSearchTool: any = {
267
+ type: 'web_search_20250305',
268
+ name: 'web_search'
269
+ };
270
+
271
+ // Add optional parameters
272
+ if (optionsArg.maxSources) {
273
+ webSearchTool.max_uses = optionsArg.maxSources;
269
274
  }
270
- ] : [];
275
+
276
+ if (this.options.searchDomainAllowList?.length) {
277
+ webSearchTool.allowed_domains = this.options.searchDomainAllowList;
278
+ } else if (this.options.searchDomainBlockList?.length) {
279
+ webSearchTool.blocked_domains = this.options.searchDomainBlockList;
280
+ }
281
+
282
+ tools.push(webSearchTool);
283
+ }
271
284
 
272
285
  // Configure the request based on search depth
273
286
  const maxTokens = optionsArg.searchDepth === 'deep' ? 8192 :
@@ -275,7 +288,7 @@ export class AnthropicProvider extends MultiModalModel {
275
288
 
276
289
  // Create the research request
277
290
  const requestParams: any = {
278
- model: 'claude-3-opus-20240229',
291
+ model: 'claude-sonnet-4-5-20250929',
279
292
  system: systemMessage,
280
293
  messages: [
281
294
  {
@@ -290,7 +303,6 @@ export class AnthropicProvider extends MultiModalModel {
290
303
  // Add tools if web search is enabled
291
304
  if (tools.length > 0) {
292
305
  requestParams.tools = tools;
293
- requestParams.tool_choice = { type: 'auto' };
294
306
  }
295
307
 
296
308
  // Execute the research request
@@ -304,54 +316,71 @@ export class AnthropicProvider extends MultiModalModel {
304
316
  // Process content blocks
305
317
  for (const block of result.content) {
306
318
  if ('text' in block) {
319
+ // Accumulate text content
307
320
  answer += block.text;
308
- }
309
- }
310
321
 
311
- // Parse sources from the answer (Claude includes citations in various formats)
312
- const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
313
- let match: RegExpExecArray | null;
314
-
315
- while ((match = urlRegex.exec(answer)) !== null) {
316
- sources.push({
317
- title: match[1],
318
- url: match[2],
319
- snippet: ''
320
- });
322
+ // Extract citations if present
323
+ if ('citations' in block && Array.isArray(block.citations)) {
324
+ for (const citation of block.citations) {
325
+ if (citation.type === 'web_search_result_location') {
326
+ sources.push({
327
+ title: citation.title || '',
328
+ url: citation.url || '',
329
+ snippet: citation.cited_text || ''
330
+ });
331
+ }
332
+ }
333
+ }
334
+ } else if ('type' in block && block.type === 'server_tool_use') {
335
+ // Extract search queries from server tool use
336
+ if (block.name === 'web_search' && block.input && typeof block.input === 'object' && 'query' in block.input) {
337
+ searchQueries.push((block.input as any).query);
338
+ }
339
+ } else if ('type' in block && block.type === 'web_search_tool_result') {
340
+ // Extract sources from web search results
341
+ if (Array.isArray(block.content)) {
342
+ for (const result of block.content) {
343
+ if (result.type === 'web_search_result') {
344
+ // Only add if not already in sources (avoid duplicates from citations)
345
+ if (!sources.some(s => s.url === result.url)) {
346
+ sources.push({
347
+ title: result.title || '',
348
+ url: result.url || '',
349
+ snippet: '' // Search results don't include snippets, only citations do
350
+ });
351
+ }
352
+ }
353
+ }
354
+ }
355
+ }
321
356
  }
322
357
 
323
- // Also look for plain URLs
324
- const plainUrlRegex = /https?:\/\/[^\s\)]+/g;
325
- const plainUrls = answer.match(plainUrlRegex) || [];
358
+ // Fallback: Parse markdown-style links if no citations found
359
+ if (sources.length === 0) {
360
+ const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
361
+ let match: RegExpExecArray | null;
326
362
 
327
- for (const url of plainUrls) {
328
- // Check if this URL is already in sources
329
- if (!sources.some(s => s.url === url)) {
363
+ while ((match = urlRegex.exec(answer)) !== null) {
330
364
  sources.push({
331
- title: new URL(url).hostname,
332
- url: url,
365
+ title: match[1],
366
+ url: match[2],
333
367
  snippet: ''
334
368
  });
335
369
  }
336
370
  }
337
371
 
338
- // Extract tool use information if available
339
- if ('tool_use' in result && Array.isArray(result.tool_use)) {
340
- for (const toolUse of result.tool_use) {
341
- if (toolUse.name === 'web_search' && toolUse.input?.query) {
342
- searchQueries.push(toolUse.input.query);
343
- }
344
- }
345
- }
372
+ // Check if web search was used based on usage info
373
+ const webSearchCount = result.usage?.server_tool_use?.web_search_requests || 0;
346
374
 
347
375
  return {
348
376
  answer,
349
377
  sources,
350
378
  searchQueries: searchQueries.length > 0 ? searchQueries : undefined,
351
379
  metadata: {
352
- model: 'claude-3-opus-20240229',
380
+ model: 'claude-sonnet-4-5-20250929',
353
381
  searchDepth: optionsArg.searchDepth || 'basic',
354
- tokensUsed: result.usage?.output_tokens
382
+ tokensUsed: result.usage?.output_tokens,
383
+ webSearchesPerformed: webSearchCount
355
384
  }
356
385
  };
357
386
  } catch (error) {
@@ -359,4 +388,18 @@ export class AnthropicProvider extends MultiModalModel {
359
388
  throw new Error(`Failed to perform research: ${error.message}`);
360
389
  }
361
390
  }
391
+
392
+ /**
393
+ * Image generation is not supported by Anthropic
394
+ */
395
+ public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
396
+ throw new Error('Image generation is not supported by Anthropic. Claude can only analyze images, not generate them. Please use OpenAI provider for image generation.');
397
+ }
398
+
399
+ /**
400
+ * Image editing is not supported by Anthropic
401
+ */
402
+ public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
403
+ throw new Error('Image editing is not supported by Anthropic. Claude can only analyze images, not edit them. Please use OpenAI provider for image editing.');
404
+ }
362
405
  }
@@ -1,7 +1,16 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import * as paths from './paths.js';
3
3
  import { MultiModalModel } from './abstract.classes.multimodal.js';
4
- import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
4
+ import type {
5
+ ChatOptions,
6
+ ChatResponse,
7
+ ChatMessage,
8
+ ResearchOptions,
9
+ ResearchResponse,
10
+ ImageGenerateOptions,
11
+ ImageEditOptions,
12
+ ImageResponse
13
+ } from './abstract.classes.multimodal.js';
5
14
  import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
6
15
 
7
16
  export interface IExoProviderOptions {
@@ -129,4 +138,18 @@ export class ExoProvider extends MultiModalModel {
129
138
  public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
130
139
  throw new Error('Research capabilities are not yet supported by Exo provider.');
131
140
  }
141
+
142
+ /**
143
+ * Image generation is not supported by Exo
144
+ */
145
+ public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
146
+ throw new Error('Image generation is not supported by Exo. Please use OpenAI provider for image generation.');
147
+ }
148
+
149
+ /**
150
+ * Image editing is not supported by Exo
151
+ */
152
+ public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
153
+ throw new Error('Image editing is not supported by Exo. Please use OpenAI provider for image editing.');
154
+ }
132
155
  }
@@ -1,7 +1,16 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import * as paths from './paths.js';
3
3
  import { MultiModalModel } from './abstract.classes.multimodal.js';
4
- import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
4
+ import type {
5
+ ChatOptions,
6
+ ChatResponse,
7
+ ChatMessage,
8
+ ResearchOptions,
9
+ ResearchResponse,
10
+ ImageGenerateOptions,
11
+ ImageEditOptions,
12
+ ImageResponse
13
+ } from './abstract.classes.multimodal.js';
5
14
 
6
15
  export interface IGroqProviderOptions {
7
16
  groqToken: string;
@@ -193,4 +202,18 @@ export class GroqProvider extends MultiModalModel {
193
202
  public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
194
203
  throw new Error('Research capabilities are not yet supported by Groq provider.');
195
204
  }
205
+
206
+ /**
207
+ * Image generation is not supported by Groq
208
+ */
209
+ public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
210
+ throw new Error('Image generation is not supported by Groq. Please use OpenAI provider for image generation.');
211
+ }
212
+
213
+ /**
214
+ * Image editing is not supported by Groq
215
+ */
216
+ public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
217
+ throw new Error('Image editing is not supported by Groq. Please use OpenAI provider for image editing.');
218
+ }
196
219
  }
@@ -1,7 +1,16 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import * as paths from './paths.js';
3
3
  import { MultiModalModel } from './abstract.classes.multimodal.js';
4
- import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
4
+ import type {
5
+ ChatOptions,
6
+ ChatResponse,
7
+ ChatMessage,
8
+ ResearchOptions,
9
+ ResearchResponse,
10
+ ImageGenerateOptions,
11
+ ImageEditOptions,
12
+ ImageResponse
13
+ } from './abstract.classes.multimodal.js';
5
14
 
6
15
  export interface IOllamaProviderOptions {
7
16
  baseUrl?: string;
@@ -255,4 +264,18 @@ export class OllamaProvider extends MultiModalModel {
255
264
  public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
256
265
  throw new Error('Research capabilities are not yet supported by Ollama provider.');
257
266
  }
267
+
268
+ /**
269
+ * Image generation is not supported by Ollama
270
+ */
271
+ public async imageGenerate(optionsArg: ImageGenerateOptions): Promise<ImageResponse> {
272
+ throw new Error('Image generation is not supported by Ollama. Please use OpenAI provider for image generation.');
273
+ }
274
+
275
+ /**
276
+ * Image editing is not supported by Ollama
277
+ */
278
+ public async imageEdit(optionsArg: ImageEditOptions): Promise<ImageResponse> {
279
+ throw new Error('Image editing is not supported by Ollama. Please use OpenAI provider for image editing.');
280
+ }
258
281
  }