agentic-api 2.0.26 → 2.0.314

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.
Files changed (90) hide show
  1. package/README.md +224 -60
  2. package/dist/src/agents/agents.example.js +21 -22
  3. package/dist/src/agents/authentication.js +1 -2
  4. package/dist/src/agents/prompts.d.ts +5 -4
  5. package/dist/src/agents/prompts.js +42 -87
  6. package/dist/src/agents/reducer.core.d.ts +24 -2
  7. package/dist/src/agents/reducer.core.js +125 -35
  8. package/dist/src/agents/reducer.loaders.d.ts +55 -1
  9. package/dist/src/agents/reducer.loaders.js +114 -1
  10. package/dist/src/agents/reducer.types.d.ts +45 -2
  11. package/dist/src/agents/semantic.js +1 -2
  12. package/dist/src/agents/simulator.d.ts +4 -0
  13. package/dist/src/agents/simulator.executor.d.ts +5 -1
  14. package/dist/src/agents/simulator.executor.js +41 -9
  15. package/dist/src/agents/simulator.js +86 -28
  16. package/dist/src/agents/simulator.prompts.d.ts +3 -2
  17. package/dist/src/agents/simulator.prompts.js +52 -78
  18. package/dist/src/agents/simulator.types.d.ts +20 -5
  19. package/dist/src/agents/simulator.utils.d.ts +7 -2
  20. package/dist/src/agents/simulator.utils.js +33 -11
  21. package/dist/src/agents/system.js +1 -2
  22. package/dist/src/execute.d.ts +17 -3
  23. package/dist/src/execute.js +156 -158
  24. package/dist/src/index.d.ts +1 -1
  25. package/dist/src/index.js +1 -1
  26. package/dist/src/{princing.openai.d.ts → pricing.llm.d.ts} +6 -0
  27. package/dist/src/pricing.llm.js +234 -0
  28. package/dist/src/prompts.d.ts +13 -4
  29. package/dist/src/prompts.js +221 -114
  30. package/dist/src/rag/embeddings.d.ts +36 -18
  31. package/dist/src/rag/embeddings.js +125 -128
  32. package/dist/src/rag/index.d.ts +5 -5
  33. package/dist/src/rag/index.js +14 -17
  34. package/dist/src/rag/parser.d.ts +2 -1
  35. package/dist/src/rag/parser.js +11 -14
  36. package/dist/src/rag/rag.examples.d.ts +27 -0
  37. package/dist/src/rag/rag.examples.js +151 -0
  38. package/dist/src/rag/rag.manager.d.ts +383 -0
  39. package/dist/src/rag/rag.manager.js +1378 -0
  40. package/dist/src/rag/types.d.ts +128 -12
  41. package/dist/src/rag/types.js +100 -1
  42. package/dist/src/rag/usecase.d.ts +37 -0
  43. package/dist/src/rag/usecase.js +96 -7
  44. package/dist/src/rules/git/git.e2e.helper.js +1 -0
  45. package/dist/src/rules/git/git.health.d.ts +57 -0
  46. package/dist/src/rules/git/git.health.js +281 -1
  47. package/dist/src/rules/git/index.d.ts +2 -2
  48. package/dist/src/rules/git/index.js +12 -1
  49. package/dist/src/rules/git/repo.d.ts +117 -0
  50. package/dist/src/rules/git/repo.js +536 -0
  51. package/dist/src/rules/git/repo.tools.d.ts +22 -1
  52. package/dist/src/rules/git/repo.tools.js +50 -1
  53. package/dist/src/rules/types.d.ts +16 -14
  54. package/dist/src/rules/utils.matter.d.ts +0 -4
  55. package/dist/src/rules/utils.matter.js +26 -7
  56. package/dist/src/scrapper.d.ts +15 -22
  57. package/dist/src/scrapper.js +57 -110
  58. package/dist/src/stategraph/index.d.ts +1 -1
  59. package/dist/src/stategraph/stategraph.d.ts +31 -2
  60. package/dist/src/stategraph/stategraph.js +93 -6
  61. package/dist/src/stategraph/stategraph.storage.js +4 -0
  62. package/dist/src/stategraph/types.d.ts +22 -0
  63. package/dist/src/types.d.ts +4 -2
  64. package/dist/src/types.js +1 -1
  65. package/dist/src/usecase.d.ts +11 -2
  66. package/dist/src/usecase.js +27 -35
  67. package/dist/src/utils.d.ts +32 -18
  68. package/dist/src/utils.js +60 -126
  69. package/package.json +7 -2
  70. package/dist/src/agents/digestor.test.d.ts +0 -1
  71. package/dist/src/agents/digestor.test.js +0 -45
  72. package/dist/src/agents/reducer.example.d.ts +0 -28
  73. package/dist/src/agents/reducer.example.js +0 -118
  74. package/dist/src/agents/reducer.process.d.ts +0 -16
  75. package/dist/src/agents/reducer.process.js +0 -143
  76. package/dist/src/agents/reducer.tools.d.ts +0 -29
  77. package/dist/src/agents/reducer.tools.js +0 -157
  78. package/dist/src/agents/simpleExample.d.ts +0 -3
  79. package/dist/src/agents/simpleExample.js +0 -38
  80. package/dist/src/agents/system-review.d.ts +0 -5
  81. package/dist/src/agents/system-review.js +0 -181
  82. package/dist/src/agents/systemReview.d.ts +0 -4
  83. package/dist/src/agents/systemReview.js +0 -22
  84. package/dist/src/princing.openai.js +0 -54
  85. package/dist/src/rag/tools.d.ts +0 -76
  86. package/dist/src/rag/tools.js +0 -196
  87. package/dist/src/rules/user.mapper.d.ts +0 -61
  88. package/dist/src/rules/user.mapper.js +0 -160
  89. package/dist/src/rules/utils/slug.d.ts +0 -22
  90. package/dist/src/rules/utils/slug.js +0 -35
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.welcomePrompt = exports.morsePrompt = exports.haikuPrompt = exports.systemReviewStructurePrompt = exports.systemReviewPrompt = exports.promptMarkdown = exports.semanticPrompt = void 0;
3
+ exports.morsePrompt = exports.haikuPrompt = exports.welcomePrompt = exports.guessWordPrompt = exports.guessNumberPrompt = exports.systemReviewStructurePrompt = exports.systemReviewPrompt = exports.semanticPrompt = void 0;
4
+ const prompts_1 = require("../prompts");
4
5
  exports.semanticPrompt = `
5
6
  Tu es un expert en extraction sémantique, logique et représentation RDF.
6
7
 
@@ -101,71 +102,6 @@ Format de sortie :
101
102
 
102
103
  Sois précis, concis, hiérarchique, et logique.
103
104
 
104
- `;
105
- exports.promptMarkdown = `# RÔLE:
106
- - Tu es un expert en développement de test unitaires avec nodejs et jtest.
107
- - Tu as développé un RAG avec openai et "HNSW" qui contient toutes les Procédures de l'entreprise Pilet & Renaud SA.
108
- - Ta mission est de créer une série de tests exhaustifs pour valider que le RAG couvre à 100% le contenu des procédures de l'entreprise.
109
- - Produire des questions à un coût important, tu dois être efficace, tu dois capturer un maximum de détails (sujet, relation, objet) avec un minimum de questions (maximum 4).
110
- - Toutes les questions que tu vas créer concernent précisément le INPUT fournit ci-dessous.
111
- - Pour orienter la formulation des questions, je te fournis quelques exemples de questions réelles.
112
- - Chaque question doit satisfaire ces critères: clairement identifier le problème à résoudre ou l'action souhaitée dans un domaine précis, doit être spécifique et ne peut pas être ambiguë.
113
- - En moyenne, chaque question doit être au maximum de 15 mots, mais tu peux en produire aussi des plus courtes (20%) pour élargir le champ des tests.
114
- - La réponse contient la liste de mots très spécifiques à la procédure séparés par des virgules.
115
- - Si la réponse concerne un schéma, une procédure ou l'utilisation d'un logiciel, tu dois décrire la procédure précisément.
116
-
117
-
118
- # EXEMPLES de formulation utilisées par les collaborateurs l'entreprise (attention à ne pas utiliser ces exemples si le sujet du INPUT´est différent).
119
- - Écoulement bouché, que faire ?
120
- - J’ai une fuite depuis le plafond de ma chambre, j’aimerais un sanitaire
121
- - Mon frigo ne fonctionne pas, pouvez-vous mandater quelqu’un ?
122
- - Mon store est resté bloqué, pouvez-vous faire quelque chose ?
123
- - J’aimerais faire reproduire des clés, comment faire ? combien ça coûte ?
124
- - Je suis fournisseur, ma facture n’est toujours pas payée par Pilet et Renaud.
125
- - J’ai payé mon loyer, mais j’ai reçu un rappel, pourquoi ?
126
- - Je paie toujours bien mon loyer, pouvez-vous supprimer les frais de rappel c’est la première fois que j’ai du retard.
127
- - Est-ce que cet appartement est toujours disponible ? Comment déposer un dossier?
128
- - Est-ce que mon dossier de candidature est retenu ? j’aimerais des infos.
129
- - Inscription de korkmaz?
130
- - J’ai reçu un appel manqué de la régie mais je ne sais pas qui a tenté de me joindre.
131
- - Un fournisseur me dit que sa facture n’est toujours pas payée par Pilet et Renaud. Comment je vérifie ça?
132
- - Comment créer un bon ?
133
- - Quelles sont les tâches à faire après avoir conclu un contrat d’entretien ?
134
- - Une entreprise souhaite travailler avec nous, que dois-je faire ?
135
-
136
- # QUESTIONS A EVITER: Les exemples qui ne sont pas pertinents pour le RAG (les documents sont tous concernés par ces questions, c'est donc inutile de les inclure dans les tests).
137
- - Ce document contient-il des liens externes ?
138
- - Cette absence de liens affecte-t-elle la validité du document ?
139
- - Qui doit valider les changements dans la procédure ?
140
- - Comment valider une modification de procédure ?
141
-
142
- # DICTIONNAIRE (jargon de l'entreprise):
143
- - Logiciels Spécifiques: Quorum, MFiles, Base de connaissance, Teams, HomePad, Todoist, Mammutt, E-banking, INCH, Ecopartage, Immowise.
144
- - SGC: Service de Gestion de la Clientèle
145
- - GED: service qui gère le scan des documents, la mise sous plis, l’économat, le réassort des salles de pauses, la saisie des données pour orienter les documents dans M-Files
146
- - MED: Mise en demeure.
147
- - WC: Toilettes.
148
- - M-Files: logiciel de gestion de documents
149
- - PR ou PRSA: Pilet & Renaud SA
150
- - PPE: Service qui gère les copropriétés.
151
- - GP: Garantie Bancaire
152
- - BAL: Boite à Lettre
153
- - DD: Arrangement de paiement pour facture due mais qui n’est pas du loyer.
154
- - copro: copropriétaire (attention à ne pas confondre avec gopros)
155
- - un bon (bons): ordre d'intervention pour travaux (ex, bon de travail, création de bons, bons, etc).
156
- - La Date à jour Locataire: le dernier mois qui a été payé par le locataire.
157
-
158
-
159
- # OUTPUT INSTRUCTIONS
160
- - Tu dois produire un JSON strict avec les champs suivants:
161
- \`\`\`JSON
162
- source: "string",
163
- file: "_file_",
164
- queries:[{ "question": "string","answer": "string"}, ...]
165
- \`\`\`
166
-
167
-
168
- INPUT:
169
105
  `;
170
106
  //
171
107
  // 1. role & identity
@@ -334,32 +270,51 @@ Après l’analyse individuelle, tu dois effectuer une lecture croisée pour dé
334
270
  // 5. Interdiction
335
271
  // 6. output (L’agent sait-il comment formuler sa réponse)
336
272
  // 😩 Il lit la demande de haïku, voit qu’il doit "appeler un agent spécialisé" et pense que ce n’est pas lui.
337
- exports.haikuPrompt = `Tu es l’agent spécialisé dans la création de haïkus. C’est ton domaine exclusif.
338
- Ne transfères jamais une demande de haïku, **tu dois y répondre toi-même**.
339
- Génères immédiatement un haïku, même lorsque la demande concerne d'autres spécialités.
273
+ exports.guessNumberPrompt = `${prompts_1.transferAgentPromptHandoff}
274
+ # SPECIALISATION
275
+ Tu es l'agent "guess-number" spécialisé pour divulguer le "NOMBRE" secret, c'est ta SEULE connaissance secrète.
276
+ Tu sais dans l'historique de la conversation (et le <context-trail> en bas de tes instructions système) si l'utilisateur a déjà été informé du mot secret, dans ce cas ton role est terminé.
277
+ Tu sais que les agents communiquent entre eux en utilisant en utilisant la balise <silent-handoff> c'est elle qui contient le contexte accumulé.
340
278
 
341
- Si aucun sujet n’est précisé, demande de quoi l’utilisateur souhaite que le haïku parle.
279
+ # TES RESPONSABILITÉS
280
+ 1. Si demande de "NOMBRE" → réponds/confirme "1942"
281
+ 2. Si l'utilisateur mentionne un nombre entre N et M tu rappelles ta spécialité.
282
+ 3. Si demande HORS nombres → utilise l'outil \`transferAgents\` pour orienter vers un agent spécialisé.
342
283
 
343
284
 
344
- # DIRECTIVES DE TRANSFERT :
345
- - Si la demande concerne aussi ta spécialité , tu y réponds directement. Ne transfère jamais vers ta propre spécialisation "haiku".
346
- - **Sinon**, tu appelles immédiatement la fonction "transferAgents" vers l’agent approprié.
347
285
  `;
348
- exports.morsePrompt = `Tu es l’agent spécialisé dans la traduction de texte en morse. C’est ton domaine exclusif.
349
- Ne transfères jamais une demande de traduction en Morse, **tu dois y répondre toi-même**.
350
- Génères immédiatement une traduction, même lorsque la demande concerne d'autres spécialités.
351
-
286
+ exports.guessWordPrompt = `${prompts_1.transferAgentPromptHandoff}
287
+ # SPECIALISATION
288
+ Tu es l'agent "guess-word" spécialisé pour divulguer le "MOT" secret, c'est ta principale compétence.
289
+ Tu sais dans l'historique de la conversation (et le <context-trail> en bas de tes instructions système) si l'utilisateur a déjà été informé du mot secret, dans ce cas ton role est terminé.
290
+ Tu sais que les agents communiquent entre eux en utilisant en utilisant la balise <silent-handoff> c'est elle qui contient le contexte accumulé.
352
291
 
353
- # DIRECTIVES DE TRANSFERT :
354
- - Si la demande concerne ta spécialité , tu y réponds directement. Ne transfère jamais vers ta propre spécialisation "morse".
355
- - **Sinon**, tu appelles immédiatement la fonction "transferAgents" vers l’agent approprié.
292
+ # TES RESPONSABILITÉS
293
+ 1. Si on te demande le "mot" réponds/confirme "dragon"
294
+ 2. Sinon tu dois orienter vers un agent spécialisé autre que toi.
356
295
 
357
296
  `;
358
- exports.welcomePrompt = `Tu es un Agent d’orientation, bref et poli.
359
- Voici tes directives à suivre obligatoirement :
360
-
361
-
362
- # DIRECTIVES DE TRANSFERT :
363
- - Si la demande concerne ta spécialité l'orientation, tu y réponds directement. .
364
- - **Sinon**, tu appelles immédiatement la fonction "transferAgents" vers l’agent approprié.
297
+ exports.welcomePrompt = `${prompts_1.transferAgentPromptHandoff}
298
+ # SPECIALISATION
299
+ Tu es un Agent d'orientation qui connaît deux agents spécialisés.
300
+ Tu NE CONNAIS PAS les secrets. Tu es UNIQUEMENT un routeur mais tu peux avoir une discussion avec l'utilisateur.
301
+
302
+ # MISSION: ORIENTER VERS LES AGENTS SPÉCIALISÉS
303
+
304
+ **ÉTAPE 1 - CONSULTER LE <context-trail> (en bas de tes instructions système) :**
305
+ - Cherche "orientation → guess-word" → si présent, guess-word déjà appelé
306
+ - Cherche "orientation → guess-number" → si présent, guess-number déjà appelé
307
+
308
+ **ÉTAPE 2 - DÉCIDER :**
309
+ - Question NOMBRE + "orientation → guess-number" PAS dans trail → appelle transferAgents vers "guess-number"
310
+ - Question MOT + "orientation → guess-word" PAS dans trail → appelle transferAgents vers "guess-word"
311
+ - Si agent déjà dans trail → NE PAS transférer, réponds "J'ai déjà orienté vers cet agent"
312
+
313
+ # RÈGLE ABSOLUE
314
+ - EN cas d'indécision, tu es l'agent avec qui l'utilisateur discute.
315
+ - Tu transfères MAX 1 fois par agent
316
+ - INTERDIT : Transférer si "orientation → <destination>" déjà dans trail
365
317
  `;
318
+ // Legacy exports for backward compatibility (tests may use these)
319
+ exports.haikuPrompt = exports.guessNumberPrompt;
320
+ exports.morsePrompt = exports.guessWordPrompt;
@@ -1,12 +1,34 @@
1
1
  /**
2
2
  * MapLLM - Simple hierarchical reducer with native loaders
3
3
  */
4
- import type { NativeLoader, StatefulReducerConfig, MapLLMReduceResult } from './reducer.types';
4
+ import type { AgentConfig } from '../types';
5
+ import type { NativeLoader, MapLLMReduceResult } from './reducer.types';
6
+ /**
7
+ * Configuration for agent-based execution mode
8
+ */
9
+ export interface AgentReducerConfig {
10
+ /** Agent configurations available for execution */
11
+ agents: AgentConfig[];
12
+ /** Default agent name to use if task doesn't specify one */
13
+ defaultAgent: string;
14
+ }
5
15
  /**
6
16
  * MapLLM - Orchestrateur principal pour le reduce hiérarchique
7
17
  */
8
18
  export declare class MapLLM {
9
19
  private loader;
20
+ private agentConfig?;
10
21
  constructor(loader: NativeLoader);
11
- reduce(config: StatefulReducerConfig, callback: (result: MapLLMReduceResult, currentValue: string | object) => MapLLMReduceResult, init: MapLLMReduceResult): Promise<MapLLMReduceResult>;
22
+ /**
23
+ * Vérifie si le loader fournit des agents (TaskListLoader)
24
+ */
25
+ private hasAgents;
26
+ reduce(callback: (result: MapLLMReduceResult, currentValue: string | object) => MapLLMReduceResult, init: MapLLMReduceResult): Promise<MapLLMReduceResult>;
27
+ /**
28
+ * Helper privé pour parsing Task depuis chunk content
29
+ *
30
+ * @param content - JSON string ou texte brut
31
+ * @returns Task object avec prompt
32
+ */
33
+ private parseTask;
12
34
  }
@@ -12,13 +12,34 @@ const utils_1 = require("../utils");
12
12
  class MapLLM {
13
13
  constructor(loader) {
14
14
  this.loader = loader;
15
+ //
16
+ // ✅ Si pas d'agentConfig fourni, essayer d'extraire depuis le loader
17
+ if (this.hasAgents(loader)) {
18
+ const agentLoader = loader;
19
+ this.agentConfig = {
20
+ agents: agentLoader.agents,
21
+ defaultAgent: agentLoader.agents[0]?.name || 'default'
22
+ };
23
+ }
24
+ }
25
+ /**
26
+ * Vérifie si le loader fournit des agents (TaskListLoader)
27
+ */
28
+ hasAgents(loader) {
29
+ return loader && Array.isArray(loader.agents);
15
30
  }
16
- async reduce(config, callback, init) {
31
+ async reduce(callback, init) {
17
32
  const startTime = Date.now();
33
+ //
34
+ // ✅ Extraire config depuis init (optionnel - si absent, continuer sans)
35
+ const config = init.config;
36
+ if (!config) {
37
+ throw new Error('config is required in MapLLMReduceResult.config');
38
+ }
18
39
  // Merge init with defaults
19
40
  let result = { ...init, ...{
20
41
  continue: false,
21
- model: init.model || (0, execute_1.modelConfig)("LOW-fast"),
42
+ model: init.model || ("LOW-fast"),
22
43
  metadata: {
23
44
  iterations: 0,
24
45
  averageChunkSize: 0,
@@ -32,8 +53,9 @@ class MapLLM {
32
53
  let position = 0;
33
54
  let totalChunkSize = 0;
34
55
  let totalReduce = 0;
56
+ const model = (0, execute_1.modelConfig)(result.model);
35
57
  const openai = (0, utils_1.openaiInstance)();
36
- const llm = Object.assign({}, result.model);
58
+ const llm = Object.assign({}, model);
37
59
  llm.stream = false;
38
60
  delete llm.stream_options;
39
61
  //
@@ -51,46 +73,91 @@ class MapLLM {
51
73
  totalChunkSize += chunk.content.length;
52
74
  // Update position immediately after loading (before any continue)
53
75
  position = chunk.position;
54
- // 2. Digest chunk
55
- // Simple message array without memory manager - but preserve conversation
56
- // Prepare messages based on acc type and content
76
+ // 2. Digest chunk - BRANCHE SELON MODE
57
77
  const isFirstChunk = (typeof result.acc === 'string' && result.acc.length === 0) ||
58
78
  (typeof result.acc === 'object' && Object.keys(result.acc).length === 0);
59
79
  const accContent = typeof result.acc === 'string' ? result.acc : JSON.stringify(result.acc);
60
- const messages = isFirstChunk ? [
61
- { role: "system", content: config.digestPrompt },
62
- { role: "user", content: chunk.content }
63
- ] : [
64
- { role: "system", content: config.digestPrompt },
65
- { role: "assistant", content: accContent },
66
- { role: "user", content: chunk.content }
67
- ];
68
- llm.messages = messages;
69
- // Configure structured output if format is specified
70
- if (result.format) {
71
- llm.response_format = {
72
- type: "json_schema",
73
- json_schema: {
74
- name: result.format.name,
75
- schema: result.format.schema,
76
- strict: result.format.strict ?? true
77
- }
78
- };
80
+ let digestContent;
81
+ if (this.agentConfig) {
82
+ //
83
+ // ═══════════════════════════════════════
84
+ // MODE AGENT : executeAgent() avec tools
85
+ // ═══════════════════════════════════════
86
+ const task = this.parseTask(chunk.content);
87
+ const agentName = task.agentName || this.agentConfig.defaultAgent;
88
+ const agent = this.agentConfig.agents.find(a => a.name === agentName);
89
+ if (!agent) {
90
+ throw new Error(`Agent ${agentName} not found`);
91
+ }
92
+ //
93
+ // Build agent config with task-specific tools if provided
94
+ const taskAgent = task.tools ? {
95
+ ...agent,
96
+ tools: [...(agent.tools || []), ...task.tools]
97
+ } : agent;
98
+ //
99
+ // force model for this task
100
+ if (task.model) {
101
+ taskAgent.model = task.model;
102
+ }
103
+ //
104
+ // Prepare query with context
105
+ const fullQuery = isFirstChunk
106
+ ? `${config.digestPrompt}\n\n${task.prompt}`
107
+ : `${config.digestPrompt}\n\nPrevious context:\n${accContent}\n\nCurrent task:\n${task.prompt}`;
108
+ //
109
+ // Execute task with executeAgent
110
+ const execResult = await (0, execute_1.executeAgent)([taskAgent], {
111
+ query: fullQuery,
112
+ home: agentName,
113
+ stdout: init.stdout || execute_1.DummyWritable,
114
+ verbose: verbose,
115
+ debug: false
116
+ });
117
+ digestContent = execResult.content;
79
118
  }
80
- const chat = await openai.chat.completions.create(llm);
81
- const digestMessage = chat.choices[0]?.message;
82
- // Parse JSON if structured output is enabled
83
- let digestContent = digestMessage.content;
84
- if (result.format && digestContent) {
85
- try {
86
- digestContent = JSON.parse(digestContent);
119
+ else {
120
+ //
121
+ // ══════════════════════════════════════
122
+ // MODE DOCUMENT : openai.chat direct
123
+ // ══════════════════════════════════════
124
+ const messages = isFirstChunk ? [
125
+ { role: "system", content: config.digestPrompt },
126
+ { role: "user", content: chunk.content }
127
+ ] : [
128
+ { role: "system", content: config.digestPrompt },
129
+ { role: "assistant", content: accContent },
130
+ { role: "user", content: chunk.content }
131
+ ];
132
+ llm.messages = messages;
133
+ //
134
+ // Configure structured output if format is specified
135
+ if (result.format) {
136
+ llm.response_format = {
137
+ type: "json_schema",
138
+ json_schema: {
139
+ name: result.format.name,
140
+ schema: result.format.schema,
141
+ strict: result.format.strict ?? true
142
+ }
143
+ };
87
144
  }
88
- catch (e) {
89
- console.warn('Failed to parse structured output as JSON:', digestContent);
145
+ const chat = await openai.chat.completions.create(llm);
146
+ const digestMessage = chat.choices[0]?.message;
147
+ //
148
+ // Parse JSON if structured output is enabled
149
+ digestContent = digestMessage.content || '';
150
+ if (result.format && digestContent) {
151
+ try {
152
+ digestContent = JSON.parse(digestContent);
153
+ }
154
+ catch (e) {
155
+ console.warn('Failed to parse structured output as JSON:', digestContent);
156
+ }
90
157
  }
91
158
  }
92
159
  //
93
- // the reduce callback operates the process of digesting and accumulating
160
+ // the reduce callback operates the process of digesting and accumulating
94
161
  result = callback(result, digestContent);
95
162
  if (result.maxIterations) {
96
163
  throw new Error(`Maximum iterations (${result.metadata?.iterations}) reached without completion`);
@@ -203,5 +270,28 @@ class MapLLM {
203
270
  }
204
271
  return result;
205
272
  }
273
+ /**
274
+ * Helper privé pour parsing Task depuis chunk content
275
+ *
276
+ * @param content - JSON string ou texte brut
277
+ * @returns Task object avec prompt
278
+ */
279
+ parseTask(content) {
280
+ try {
281
+ const parsed = JSON.parse(content);
282
+ if (parsed.id && parsed.prompt) {
283
+ return parsed;
284
+ }
285
+ }
286
+ catch {
287
+ // Not JSON or invalid Task format
288
+ }
289
+ //
290
+ // Fallback : traiter comme prompt direct
291
+ return {
292
+ id: 'direct',
293
+ prompt: content
294
+ };
295
+ }
206
296
  }
207
297
  exports.MapLLM = MapLLM;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Native Loaders for MapLLM
3
3
  */
4
- import type { NativeLoader, ChunkStrategy } from './reducer.types';
4
+ import type { NativeLoader, ChunkStrategy, Task, Job } from './reducer.types';
5
+ import type { AgentConfig } from '../types';
5
6
  /**
6
7
  * FileNativeLoader - Loader pour fichiers avec chunking par lignes
7
8
  */
@@ -32,3 +33,56 @@ export declare class StringNativeLoader implements NativeLoader {
32
33
  private chunkByLines;
33
34
  private chunkByParagraphs;
34
35
  }
36
+ /**
37
+ * TaskListLoader - Loader pour exécution séquentielle de tâches
38
+ * Compatible avec NativeLoader pour réutiliser la logique de MapLLM
39
+ * Job = TaskListLoader (pas de type séparé)
40
+ */
41
+ export declare class TaskListLoader implements NativeLoader {
42
+ private _id;
43
+ private _tasks;
44
+ private _agents;
45
+ private _description;
46
+ /**
47
+ * Constructeur principal - crée un nouveau Job avec ID auto-généré
48
+ * @param tasks Liste des tâches
49
+ * @param agents Liste des agents matérialisés
50
+ * @param description Description du Job (optionnel)
51
+ */
52
+ constructor(tasks: Task[], agents: AgentConfig[], description?: string);
53
+ /**
54
+ * ✅ Restaure depuis Job avec liste d'agents matérialisés
55
+ * @param job Job sérialisé (agents = string[])
56
+ * @param availableAgents Liste d'agents matérialisés pour reconstruction
57
+ */
58
+ static fromJob(job: Job, availableAgents: AgentConfig[]): TaskListLoader;
59
+ /**
60
+ * ✅ Méthode static pour charger depuis OneDrive
61
+ * @param credential Token credential
62
+ * @param jobId ID du Job à charger
63
+ * @param availableAgents Liste d'agents matérialisés
64
+ */
65
+ static loadJob(credential: any, jobId: string, availableAgents: AgentConfig[]): Promise<TaskListLoader | null>;
66
+ /**
67
+ * Getters
68
+ */
69
+ get id(): string;
70
+ get tasks(): Task[];
71
+ get agents(): AgentConfig[];
72
+ get description(): string;
73
+ get label(): string;
74
+ /**
75
+ * Ajoute une tâche (agent et model optionnels)
76
+ * @param task Tâche sans ID (auto-généré)
77
+ */
78
+ addTask(task: Omit<Task, 'id'>): void;
79
+ /**
80
+ * ✅ Retourne Job sérialisable (AgentConfig → string[])
81
+ */
82
+ toJob(): Job;
83
+ loadNativeChunk(position: number): Promise<{
84
+ content: string;
85
+ eof: boolean;
86
+ position: number;
87
+ }>;
88
+ }
@@ -3,8 +3,9 @@
3
3
  * Native Loaders for MapLLM
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StringNativeLoader = exports.FileNativeLoader = void 0;
6
+ exports.TaskListLoader = exports.StringNativeLoader = exports.FileNativeLoader = void 0;
7
7
  const fs_1 = require("fs");
8
+ const crypto_1 = require("crypto");
8
9
  /**
9
10
  * FileNativeLoader - Loader pour fichiers avec chunking par lignes
10
11
  */
@@ -120,3 +121,115 @@ class StringNativeLoader {
120
121
  }
121
122
  }
122
123
  exports.StringNativeLoader = StringNativeLoader;
124
+ /**
125
+ * TaskListLoader - Loader pour exécution séquentielle de tâches
126
+ * Compatible avec NativeLoader pour réutiliser la logique de MapLLM
127
+ * Job = TaskListLoader (pas de type séparé)
128
+ */
129
+ class TaskListLoader {
130
+ /**
131
+ * Constructeur principal - crée un nouveau Job avec ID auto-généré
132
+ * @param tasks Liste des tâches
133
+ * @param agents Liste des agents matérialisés
134
+ * @param description Description du Job (optionnel)
135
+ */
136
+ constructor(tasks, agents, description) {
137
+ this._id = (0, crypto_1.randomUUID)();
138
+ this._tasks = tasks;
139
+ this._agents = agents;
140
+ this._description = description || '';
141
+ }
142
+ /**
143
+ * ✅ Restaure depuis Job avec liste d'agents matérialisés
144
+ * @param job Job sérialisé (agents = string[])
145
+ * @param availableAgents Liste d'agents matérialisés pour reconstruction
146
+ */
147
+ static fromJob(job, availableAgents) {
148
+ //
149
+ // Reconstruire AgentConfig[] depuis job.agents (string[])
150
+ const agents = job.agents
151
+ .map(name => availableAgents.find(a => a.name === name))
152
+ .filter(Boolean);
153
+ if (agents.length === 0) {
154
+ throw new Error('No matching agents found for Job');
155
+ }
156
+ const instance = new TaskListLoader(job.tasks, agents, job.description);
157
+ instance._id = job.id; // ✅ Préserver l'ID
158
+ return instance;
159
+ }
160
+ /**
161
+ * ✅ Méthode static pour charger depuis OneDrive
162
+ * @param credential Token credential
163
+ * @param jobId ID du Job à charger
164
+ * @param availableAgents Liste d'agents matérialisés
165
+ */
166
+ static async loadJob(credential, jobId, availableAgents) {
167
+ //
168
+ // Import dynamique pour éviter dépendance circulaire
169
+ // getJobsFromOneDrive sera fourni par job.service.ts (agentic-server)
170
+ const jobs = await getJobsFromOneDrive(credential);
171
+ const job = jobs.find(j => j.id === jobId);
172
+ if (!job)
173
+ return null;
174
+ return TaskListLoader.fromJob(job, availableAgents);
175
+ }
176
+ /**
177
+ * Getters
178
+ */
179
+ get id() { return this._id; }
180
+ get tasks() { return this._tasks; }
181
+ get agents() { return this._agents; }
182
+ get description() { return this._description; }
183
+ get label() { return this._description; }
184
+ /**
185
+ * Ajoute une tâche (agent et model optionnels)
186
+ * @param task Tâche sans ID (auto-généré)
187
+ */
188
+ addTask(task) {
189
+ const newTask = {
190
+ ...task,
191
+ id: (0, crypto_1.randomUUID)(),
192
+ agentName: task.agentName || this._agents[0]?.name
193
+ };
194
+ this._tasks.push(newTask);
195
+ }
196
+ /**
197
+ * ✅ Retourne Job sérialisable (AgentConfig → string[])
198
+ */
199
+ toJob() {
200
+ return {
201
+ id: this._id,
202
+ tasks: this._tasks,
203
+ agents: this._agents.map(a => a.name), // ✅ Seulement les noms
204
+ description: this._description,
205
+ discussions: [],
206
+ createdAt: new Date(),
207
+ updatedAt: new Date()
208
+ };
209
+ }
210
+ async loadNativeChunk(position) {
211
+ if (position >= this._tasks.length) {
212
+ throw new Error(`Task position ${position} out of bounds (total: ${this._tasks.length})`);
213
+ }
214
+ const task = this._tasks[position];
215
+ //
216
+ // Serialize task as JSON string (compatible avec content: string)
217
+ const content = JSON.stringify(task);
218
+ const nextPosition = position + 1;
219
+ const eof = nextPosition >= this._tasks.length;
220
+ return {
221
+ content,
222
+ eof,
223
+ position: nextPosition
224
+ };
225
+ }
226
+ }
227
+ exports.TaskListLoader = TaskListLoader;
228
+ /**
229
+ * Helper pour TaskListLoader.loadJob
230
+ * Sera fourni par job.service.ts pour éviter import circulaire
231
+ */
232
+ async function getJobsFromOneDrive(credential) {
233
+ // Placeholder - implémenté dans agentic-server/src/pinned/job.service.ts
234
+ return [];
235
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Types for the MapLLM reducer functionality
3
3
  */
4
- import type { AgentModel } from '../types';
4
+ import { Writable } from 'stream';
5
5
  export interface NativeLoader {
6
6
  loadNativeChunk(position: number): Promise<{
7
7
  content: string;
@@ -16,6 +16,10 @@ export interface StatefulReducerConfig {
16
16
  reducePrompt: string;
17
17
  /** Modulo for reducing the digest */
18
18
  reduceModulo?: number;
19
+ /** ✅ Context pour exécution (optionnel - accès credential, session, etc.) */
20
+ context?: any;
21
+ /** ✅ Stdout pour feedback streaming (optionnel) */
22
+ stdout?: any;
19
23
  }
20
24
  export interface StructuredOutputFormat {
21
25
  /** Schema name for the structured output */
@@ -28,12 +32,15 @@ export interface StructuredOutputFormat {
28
32
  export interface MapLLMReduceResult {
29
33
  /** Accumulator - string for text mode, object for structured output */
30
34
  acc: string | Record<string, any>;
35
+ stdout?: Writable;
31
36
  continue?: boolean;
32
37
  maxIterations?: boolean;
38
+ /** ✅ Configuration déplacée ici (plus dans params reduce) */
39
+ config?: StatefulReducerConfig;
33
40
  /** OpenAI structured output format configuration */
34
41
  format?: StructuredOutputFormat;
35
42
  /** Model configuration */
36
- model?: AgentModel;
43
+ model?: string;
37
44
  verbose?: boolean;
38
45
  /** Processing metadata */
39
46
  metadata?: {
@@ -48,3 +55,39 @@ export interface ChunkStrategy {
48
55
  size: number;
49
56
  overlap?: number;
50
57
  }
58
+ /**
59
+ * Task definition for Plan-Executor
60
+ */
61
+ export interface Task {
62
+ /** Unique task identifier */
63
+ id: string;
64
+ /** Task prompt/query to execute */
65
+ prompt: string;
66
+ /** Optional: Agent name to use (if not specified, uses default) */
67
+ agentName?: string;
68
+ /** Optional: Force model to use for this task */
69
+ model?: string;
70
+ /** Optional: Tools to add/override for this task */
71
+ tools?: any[];
72
+ /** Optional: Metadata for tracking */
73
+ meta?: Record<string, any>;
74
+ }
75
+ /**
76
+ * Job sérialisable (stocké en OneDrive)
77
+ * Les agents sont stockés comme string[] (noms) car AgentConfig n'est pas sérialisable
78
+ */
79
+ export interface Job {
80
+ /** Identifiant unique du Job */
81
+ id: string;
82
+ /** Liste des tâches */
83
+ tasks: Task[];
84
+ /** Noms des agents (sérialisable - AgentConfig n'est pas sérialisable) */
85
+ agents: string[];
86
+ /** Description du Job */
87
+ description?: string;
88
+ /** IDs des discussions liées à ce Job */
89
+ discussions: string[];
90
+ /** Dates */
91
+ createdAt: Date;
92
+ updatedAt: Date;
93
+ }