data-primals-engine 1.6.1 → 1.6.2

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.
@@ -1,7 +1,8 @@
1
1
  import { getCollectionForUser, modelsCollection } from "../mongodb.js";
2
2
  import { Logger } from "../../gameObject.js";
3
3
  import { HumanMessage, SystemMessage } from "@langchain/core/messages";
4
- import {searchData, patchData, deleteData, insertData} from "../data/index.js";
4
+ import { searchData, patchData, deleteData, insertData } from "../data/index.js";
5
+ import { getAIProvider } from "./providers.js";
5
6
  import {providers} from "./constants.js";
6
7
  import {Config} from "../../config.js";
7
8
  import { Event } from "../../events.js";
@@ -13,38 +14,6 @@ import {parseSafeJSON} from "../../core.js";
13
14
 
14
15
  let logger = null;
15
16
 
16
- export const getAIProvider= async (aiProvider, aiModel, apiKey)=>{
17
- const maxTokens = Config.Get('assistant.maxTokens', assistantConfig.maxTokens);
18
- try {
19
- switch (aiProvider) {
20
- case 'OpenAI': {
21
- const { ChatOpenAI } = await import("@langchain/openai");
22
- return new ChatOpenAI({apiKey, model: aiModel, temperature: 0.7, maxTokens});
23
- }
24
- case 'Google': {
25
- const { ChatGoogleGenerativeAI } = await import("@langchain/google-genai");
26
- return new ChatGoogleGenerativeAI({apiKey, model: aiModel, temperature: 0.7, maxTokens});
27
- }
28
- case 'DeepSeek': {
29
- const { ChatDeepSeek } = await import("@langchain/deepseek");
30
- return new ChatDeepSeek({apiKey, model: aiModel, temperature: 0.7, maxTokens});
31
- }
32
- case 'Anthropic': {
33
- const { ChatAnthropic } = await import("@langchain/anthropic");
34
- return new ChatAnthropic({apiKey, model: aiModel, temperature: 0.7, maxTokens});
35
- }
36
- default:
37
- throw new Error(`Unsupported AI provider: ${aiProvider}`);
38
- }
39
- } catch (e) {
40
- if (e.code === 'ERR_MODULE_NOT_FOUND') {
41
- logger.error(`[Assistant] The package for the '${aiProvider}' provider is not installed. Please run 'npm install @langchain/${aiProvider.toLowerCase()}' to use this provider.`);
42
- throw new Error(`The AI provider '${aiProvider}' is not installed. Please ask the administrator to install the corresponding package.`);
43
- }
44
- logger.error(`[Assistant] Error initializing AI provider '${aiProvider}': ${e.message}`);
45
- throw e; // Re-throw other errors
46
- }
47
- }
48
17
  export const assistantGlobalLimiter = rateLimit({
49
18
  windowMs: 15 * 60 * 1000, // Fenêtre de 15 minutes
50
19
  max: 100, // Limite à 100 requêtes globales pour l'assistant pendant la fenêtre (vous pouvez ajuster cette valeur)
@@ -101,7 +70,7 @@ const createSystemPrompt = (modelDefs, lang) => {
101
70
 
102
71
  const date = new Date();
103
72
  const dt = date.toISOString();
104
- return `
73
+ return Config.Get('systemPrompt', `
105
74
  Tu es "Prior", un assistant expert en analyse de données pour le moteur data-primals-engine..
106
75
  Ta mission est d'aider l'utilisateur en répondant à ses questions sur ses données.
107
76
 
@@ -333,7 +302,7 @@ Ma question: Bonjour, je voudrais les requêtes effectuées aujourd'hui sur le m
333
302
  Ta réponse: [
334
303
  { "action" : "search_models", "params": { "query": "request" } },
335
304
  { "action" : "search", "params" : { "model": "request", "filter": { "$and": [{"$gte": ["$createdAt", "${dt}"]}, {"$regexMatch": { "input": "$url", "regex": "content"}}] }, "limit" : 10, "sort" : "_id:DESC" } }
336
- ]`;
305
+ ]`);
337
306
  }
338
307
 
339
308
  /**
@@ -475,7 +444,7 @@ export async function handleChatRequest(params, user, sendEvent = null) {
475
444
  return errorResult;
476
445
  }
477
446
 
478
- const systemPrompt = await Event.Trigger('OnSystemPrompt', 'event', 'user', user);
447
+ const systemPrompt = (await Event.Trigger('OnSystemPrompt', 'event', 'user', user)) || createSystemPrompt([], user.lang || 'en');
479
448
 
480
449
  const conversationHistory = (history || [])
481
450
  .filter(msg => msg.text && !(msg.from === 'bot' && msg.text.startsWith(i18n.t('assistant.welcome'))))
@@ -559,11 +528,12 @@ export async function handleChatRequest(params, user, sendEvent = null) {
559
528
  return result;
560
529
  }
561
530
 
562
- let hasContinued = false;
531
+ const toolResults = [];
532
+ let finalActionResult = null;
533
+
563
534
  for (const command of commands) {
564
535
  logger.debug(`[Assistant] Action décidée par l'IA: ${command.action}`, command);
565
536
  if (sendEvent) sendEvent('action', { action: command.action, params: command.params });
566
- conversationHistory.push(new SystemMessage(JSON.stringify(command)));
567
537
 
568
538
  const { action, params: parsedParams } = command;
569
539
 
@@ -576,40 +546,52 @@ export async function handleChatRequest(params, user, sendEvent = null) {
576
546
  // Outils pour le raisonnement interne de l'IA
577
547
  if (['search_models'].includes(action)) {
578
548
  const toolResult = await executeTool(action, parsedParams, user, allModels);
579
- if (sendEvent) sendEvent('tool_result', { action, result: toolResult });
580
- conversationHistory.push(new SystemMessage(`Résultat de l'outil '${action}':\n${toolResult}`));
581
- hasContinued = true; // On indique qu'on doit continuer la boucle principale
582
- continue; // On passe à la commande suivante dans la liste de l'IA
549
+ toolResults.push({ action, result: toolResult });
550
+ continue; // Passe à la commande suivante sans vérifier si c'est une action finale
583
551
  }
584
552
 
585
553
  // Actions finales
586
- const res = await Event.Trigger('OnChatAction', 'event', 'user', action, params, command, llmOptions, user);
554
+ const res = await Event.Trigger('OnChatAction', 'event', 'user', action, parsedParams, command, llmOptions, user, params);
587
555
 
588
- if (!res) {
556
+ if (res) {
557
+ // On a trouvé une action finale. On la stocke et on arrête de chercher.
558
+ finalActionResult = res;
559
+ break; // Sort de la boucle des commandes
560
+ } else {
589
561
  // Si l'action n'est reconnue par aucune des logiques ci-dessus
590
562
  logger.warn(`[Assistant] Action non reconnue reçue de l'IA: ${action}`);
591
- const result = {
563
+ finalActionResult = {
592
564
  success: true,
593
565
  displayMessage: i18n.t('assistant.unknownAction', "Désolé, je ne comprends pas la commande '{{action}}'.", { action })
594
566
  };
595
- if (sendEvent) {
596
- sendEvent('final_result', result);
597
- return;
598
- }
599
- return result;
567
+ break; // Sortir de la boucle des commandes
600
568
  }
601
- // Une action finale a été trouvée, on retourne son résultat et on arrête le traitement.
569
+ }
570
+
571
+ // Si une action finale a été exécutée, on retourne son résultat.
572
+ if (finalActionResult) {
602
573
  if (sendEvent) {
603
- sendEvent('final_result', res);
574
+ sendEvent('final_result', finalActionResult);
604
575
  return;
605
576
  }
606
- return res;
577
+ return finalActionResult;
607
578
  }
608
579
 
609
- // Si on a traité des outils de raisonnement, on relance la boucle de l'IA
610
- if (hasContinued) {
580
+ // Si on a uniquement des résultats d'outils, on les ajoute à l'historique et on continue la boucle.
581
+ if (toolResults.length > 0) {
582
+ let toolResponse = "";
583
+ for (const tool of toolResults) {
584
+ if (sendEvent) sendEvent('tool_result', { action: tool.action, result: tool.result });
585
+ toolResponse += `Résultat de l'outil '${tool.action}':\n${tool.result}\n\n`;
586
+ }
587
+ conversationHistory.push(new SystemMessage(toolResponse));
611
588
  continue;
612
589
  }
590
+
591
+ // Si l'IA ne retourne ni outil ni action finale reconnue, on arrête.
592
+ if (commands.length > 0) {
593
+ logger.warn(`[Assistant] L'IA a retourné des commandes mais aucune n'était un outil ou une action finale reconnue. Commandes:`, commands);
594
+ }
613
595
  }
614
596
 
615
597
  // Si la boucle se termine sans une action finale
@@ -656,7 +638,7 @@ async function executeConfirmedAction(action, params, user) {
656
638
  * @param {object} user - L'objet utilisateur.
657
639
  * @returns {Promise<object|boolean>} - L'objet de réponse final ou false si l'action n'est pas reconnue.
658
640
  */
659
- async function handleFinalChatAction(action, params, parsedResponse, user) {
641
+ async function handleFinalChatAction(action, params, parsedResponse, llmOptions, user) {
660
642
  // Action de génération de graphique, gérée par le front-end
661
643
  if (action === 'generateChart') {
662
644
  return {success: true, chartConfig: params};
@@ -0,0 +1,38 @@
1
+ import { Config } from "../../config.js";
2
+ import { assistantConfig } from "../../constants.js";
3
+ import { Logger } from "../../gameObject.js";
4
+
5
+ const logger = new Logger("AssistantProviders");
6
+
7
+ export const getAIProvider = async (aiProvider, aiModel, apiKey) => {
8
+ const maxTokens = Config.Get('assistant.maxTokens', assistantConfig.maxTokens);
9
+ try {
10
+ switch (aiProvider) {
11
+ case 'OpenAI': {
12
+ const { ChatOpenAI } = await import("@langchain/openai");
13
+ return new ChatOpenAI({ apiKey, model: aiModel, temperature: 0.7, maxTokens });
14
+ }
15
+ case 'Google': {
16
+ const { ChatGoogleGenerativeAI } = await import("@langchain/google-genai");
17
+ return new ChatGoogleGenerativeAI({ apiKey, model: aiModel, temperature: 0.7, maxTokens });
18
+ }
19
+ case 'DeepSeek': {
20
+ const { ChatDeepSeek } = await import("@langchain/deepseek");
21
+ return new ChatDeepSeek({ apiKey, model: aiModel, temperature: 0.7, maxTokens });
22
+ }
23
+ case 'Anthropic': {
24
+ const { ChatAnthropic } = await import("@langchain/anthropic");
25
+ return new ChatAnthropic({ apiKey, model: aiModel, temperature: 0.7, maxTokens });
26
+ }
27
+ default:
28
+ throw new Error(`Unsupported AI provider: ${aiProvider}`);
29
+ }
30
+ } catch (e) {
31
+ if (e.code === 'ERR_MODULE_NOT_FOUND') {
32
+ logger.error(`[Assistant] The package for the '${aiProvider}' provider is not installed. Please run 'npm install @langchain/${aiProvider.toLowerCase()}' to use this provider.`);
33
+ throw new Error(`The AI provider '${aiProvider}' is not installed. Please ask the administrator to install the corresponding package.`);
34
+ }
35
+ logger.error(`[Assistant] Error initializing AI provider '${aiProvider}': ${e.message}`);
36
+ throw e; // Re-throw other errors
37
+ }
38
+ }
@@ -323,17 +323,14 @@ export function onInit(defaultEngine) {
323
323
  engine.post('/api/data/history/:modelName/:recordId/revert/:version', [middlewareAuthenticator, userInitiator], handleRevertToRevisionRequest);
324
324
 
325
325
  // --- Écouteur pour la CRÉATION de données (Version 1 - Snapshot) ---
326
- Event.Listen("OnDataAdded", async (engine, { modelName, insertedIds, user }) => {
326
+ Event.Listen("OnDataAdded", async (engine, { modelName, insertedDocs, user }) => {
327
327
  try {
328
328
  const model = await getModel(modelName, user);
329
329
  if (!model?.history?.enabled) return;
330
330
 
331
- const dataCollection = await getCollectionForUser(user);
332
331
  const historyCollection = getCollection('history');
333
332
 
334
- const newDocs = await dataCollection.find({ _id: { $in: insertedIds.map(id => new ObjectId(id)) } }).toArray();
335
-
336
- for (const doc of newDocs) {
333
+ for (const doc of insertedDocs) {
337
334
  await historyCollection.insertOne({
338
335
  documentId: doc._id,
339
336
  model: modelName,