@push.rocks/smartai 0.5.11 → 0.6.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.
@@ -9,13 +9,15 @@ export type TChatCompletionRequestMessage = {
9
9
  };
10
10
 
11
11
  import { MultiModalModel } from './abstract.classes.multimodal.js';
12
+ import type { ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
12
13
 
13
14
  export interface IOpenaiProviderOptions {
14
15
  openaiToken: string;
15
16
  chatModel?: string;
16
17
  audioModel?: string;
17
18
  visionModel?: string;
18
- // Optionally add more model options (e.g., documentModel) if needed.
19
+ researchModel?: string;
20
+ enableWebSearch?: boolean;
19
21
  }
20
22
 
21
23
  export class OpenAiProvider extends MultiModalModel {
@@ -229,4 +231,111 @@ export class OpenAiProvider extends MultiModalModel {
229
231
  const result = await this.openAiApiClient.chat.completions.create(requestParams);
230
232
  return result.choices[0].message.content || '';
231
233
  }
234
+
235
+ public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
236
+ // Determine which model to use based on search depth
237
+ let model: string;
238
+ if (optionsArg.searchDepth === 'deep') {
239
+ model = this.options.researchModel || 'o4-mini-deep-research-2025-06-26';
240
+ } else {
241
+ model = this.options.chatModel || 'gpt-5-mini';
242
+ }
243
+
244
+ // Prepare the request parameters
245
+ const requestParams: any = {
246
+ model,
247
+ messages: [
248
+ {
249
+ role: 'system',
250
+ content: 'You are a research assistant. Provide comprehensive answers with citations and sources when available.'
251
+ },
252
+ {
253
+ role: 'user',
254
+ content: optionsArg.query
255
+ }
256
+ ],
257
+ temperature: 0.7
258
+ };
259
+
260
+ // Add web search tools if requested
261
+ if (optionsArg.includeWebSearch || optionsArg.searchDepth === 'deep') {
262
+ requestParams.tools = [
263
+ {
264
+ type: 'function',
265
+ function: {
266
+ name: 'web_search',
267
+ description: 'Search the web for information',
268
+ parameters: {
269
+ type: 'object',
270
+ properties: {
271
+ query: {
272
+ type: 'string',
273
+ description: 'The search query'
274
+ }
275
+ },
276
+ required: ['query']
277
+ }
278
+ }
279
+ }
280
+ ];
281
+ requestParams.tool_choice = 'auto';
282
+ }
283
+
284
+ // Add background flag for deep research
285
+ if (optionsArg.background && optionsArg.searchDepth === 'deep') {
286
+ requestParams.background = true;
287
+ }
288
+
289
+ try {
290
+ // Execute the research request
291
+ const result = await this.openAiApiClient.chat.completions.create(requestParams);
292
+
293
+ // Extract the answer
294
+ const answer = result.choices[0].message.content || '';
295
+
296
+ // Parse sources from the response (OpenAI often includes URLs in markdown format)
297
+ const sources: Array<{ url: string; title: string; snippet: string }> = [];
298
+ const urlRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
299
+ let match: RegExpExecArray | null;
300
+
301
+ while ((match = urlRegex.exec(answer)) !== null) {
302
+ sources.push({
303
+ title: match[1],
304
+ url: match[2],
305
+ snippet: '' // OpenAI doesn't provide snippets in standard responses
306
+ });
307
+ }
308
+
309
+ // Extract search queries if tools were used
310
+ const searchQueries: string[] = [];
311
+ if (result.choices[0].message.tool_calls) {
312
+ for (const toolCall of result.choices[0].message.tool_calls) {
313
+ if ('function' in toolCall && toolCall.function.name === 'web_search') {
314
+ try {
315
+ const args = JSON.parse(toolCall.function.arguments);
316
+ if (args.query) {
317
+ searchQueries.push(args.query);
318
+ }
319
+ } catch (e) {
320
+ // Ignore parsing errors
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+ return {
327
+ answer,
328
+ sources,
329
+ searchQueries: searchQueries.length > 0 ? searchQueries : undefined,
330
+ metadata: {
331
+ model,
332
+ searchDepth: optionsArg.searchDepth || 'basic',
333
+ tokensUsed: result.usage?.total_tokens
334
+ }
335
+ };
336
+ } catch (error) {
337
+ console.error('Research API error:', error);
338
+ throw new Error(`Failed to perform research: ${error.message}`);
339
+ }
340
+ }
232
341
  }
@@ -1,7 +1,7 @@
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 } from './abstract.classes.multimodal.js';
4
+ import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
5
5
 
6
6
  export interface IPerplexityProviderOptions {
7
7
  perplexityToken: string;
@@ -168,4 +168,69 @@ export class PerplexityProvider extends MultiModalModel {
168
168
  }): Promise<{ message: any }> {
169
169
  throw new Error('Document processing is not supported by Perplexity.');
170
170
  }
171
+
172
+ public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
173
+ // Perplexity has Sonar models that are optimized for search
174
+ // sonar models: sonar, sonar-pro
175
+ const model = optionsArg.searchDepth === 'deep' ? 'sonar-pro' : 'sonar';
176
+
177
+ try {
178
+ const response = await fetch('https://api.perplexity.ai/chat/completions', {
179
+ method: 'POST',
180
+ headers: {
181
+ 'Authorization': `Bearer ${this.options.perplexityToken}`,
182
+ 'Content-Type': 'application/json',
183
+ },
184
+ body: JSON.stringify({
185
+ model,
186
+ messages: [
187
+ {
188
+ role: 'system',
189
+ content: 'You are a helpful research assistant. Provide accurate information with sources.'
190
+ },
191
+ {
192
+ role: 'user',
193
+ content: optionsArg.query
194
+ }
195
+ ],
196
+ temperature: 0.7,
197
+ max_tokens: 4000
198
+ }),
199
+ });
200
+
201
+ if (!response.ok) {
202
+ throw new Error(`Perplexity API error: ${response.statusText}`);
203
+ }
204
+
205
+ const result = await response.json();
206
+ const answer = result.choices[0].message.content;
207
+
208
+ // Parse citations from the response
209
+ const sources: Array<{ url: string; title: string; snippet: string }> = [];
210
+
211
+ // Perplexity includes citations in the format [1], [2], etc. with sources listed
212
+ // This is a simplified parser - could be enhanced based on actual Perplexity response format
213
+ if (result.citations) {
214
+ for (const citation of result.citations) {
215
+ sources.push({
216
+ url: citation.url || '',
217
+ title: citation.title || '',
218
+ snippet: citation.snippet || ''
219
+ });
220
+ }
221
+ }
222
+
223
+ return {
224
+ answer,
225
+ sources,
226
+ metadata: {
227
+ model,
228
+ searchDepth: optionsArg.searchDepth || 'basic'
229
+ }
230
+ };
231
+ } catch (error) {
232
+ console.error('Perplexity research error:', error);
233
+ throw new Error(`Failed to perform research: ${error.message}`);
234
+ }
235
+ }
171
236
  }
@@ -1,7 +1,7 @@
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 } from './abstract.classes.multimodal.js';
4
+ import type { ChatOptions, ChatResponse, ChatMessage, ResearchOptions, ResearchResponse } from './abstract.classes.multimodal.js';
5
5
  import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
6
6
 
7
7
  export interface IXAIProviderOptions {
@@ -181,4 +181,8 @@ export class XAIProvider extends MultiModalModel {
181
181
  message: completion.choices[0]?.message?.content || ''
182
182
  };
183
183
  }
184
+
185
+ public async research(optionsArg: ResearchOptions): Promise<ResearchResponse> {
186
+ throw new Error('Research capabilities are not yet supported by xAI provider.');
187
+ }
184
188
  }