agentic-api 2.0.314 → 2.0.491

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 (48) hide show
  1. package/dist/src/agents/prompts.d.ts +1 -1
  2. package/dist/src/agents/prompts.js +9 -7
  3. package/dist/src/agents/simulator.d.ts +7 -3
  4. package/dist/src/agents/simulator.executor.d.ts +9 -3
  5. package/dist/src/agents/simulator.executor.js +43 -17
  6. package/dist/src/agents/simulator.js +47 -19
  7. package/dist/src/agents/simulator.prompts.d.ts +9 -8
  8. package/dist/src/agents/simulator.prompts.js +68 -62
  9. package/dist/src/agents/simulator.types.d.ts +4 -1
  10. package/dist/src/agents/simulator.utils.js +0 -2
  11. package/dist/src/execute/helpers.d.ts +75 -0
  12. package/dist/src/execute/helpers.js +139 -0
  13. package/dist/src/execute/index.d.ts +11 -0
  14. package/dist/src/execute/index.js +44 -0
  15. package/dist/src/execute/legacy.d.ts +46 -0
  16. package/dist/src/{execute.js → execute/legacy.js} +130 -232
  17. package/dist/src/execute/modelconfig.d.ts +19 -0
  18. package/dist/src/execute/modelconfig.js +56 -0
  19. package/dist/src/execute/responses.d.ts +55 -0
  20. package/dist/src/execute/responses.js +594 -0
  21. package/dist/src/execute/shared.d.ts +83 -0
  22. package/dist/src/execute/shared.js +188 -0
  23. package/dist/src/index.js +1 -1
  24. package/dist/src/pricing.llm.d.ts +1 -1
  25. package/dist/src/pricing.llm.js +39 -18
  26. package/dist/src/rag/embeddings.js +8 -2
  27. package/dist/src/rag/rag.manager.js +27 -15
  28. package/dist/src/rules/git/git.e2e.helper.js +21 -2
  29. package/dist/src/rules/git/git.health.d.ts +4 -2
  30. package/dist/src/rules/git/git.health.js +58 -16
  31. package/dist/src/rules/git/index.d.ts +1 -1
  32. package/dist/src/rules/git/index.js +3 -2
  33. package/dist/src/rules/git/repo.d.ts +46 -3
  34. package/dist/src/rules/git/repo.js +264 -23
  35. package/dist/src/rules/git/repo.pr.js +117 -13
  36. package/dist/src/rules/types.d.ts +11 -0
  37. package/dist/src/rules/utils.matter.js +16 -7
  38. package/dist/src/scrapper.js +1 -0
  39. package/dist/src/stategraph/stategraph.d.ts +26 -1
  40. package/dist/src/stategraph/stategraph.js +43 -2
  41. package/dist/src/stategraph/stategraph.storage.js +4 -0
  42. package/dist/src/stategraph/types.d.ts +5 -0
  43. package/dist/src/types.d.ts +42 -7
  44. package/dist/src/types.js +8 -7
  45. package/dist/src/usecase.js +1 -1
  46. package/dist/src/utils.js +28 -4
  47. package/package.json +9 -7
  48. package/dist/src/execute.d.ts +0 -63
@@ -321,7 +321,7 @@ async function gitLoadPR(git, branch) {
321
321
  if (!metadata) {
322
322
  throw new errors_1.GitOperationError(`PR not found for branch ${branch}`, 'pr_load', { branch });
323
323
  }
324
- const files = metadata.files || await (0, repo_tools_1.gitGetDiffFiles)(git, branch, metadata?.mergeBase, '.md');
324
+ const files = await (0, repo_tools_1.gitGetDiffFiles)(git, branch, metadata?.mergeBase, '.md');
325
325
  // Récupérer les infos du dernier commit de la branche
326
326
  const log = await git.log({ from: branch, to: branch, maxCount: 1 });
327
327
  const lastCommit = log.latest;
@@ -407,6 +407,21 @@ async function gitClosePRRobust(git, branch, closedBy, message, config) {
407
407
  if (!originalMetadata) {
408
408
  throw new errors_1.PRClosureError(`Could not find metadata on branch ${branch}. Cannot close.`, branch, 'metadata_not_found');
409
409
  }
410
+ // 2. Nettoyer tout état de merge en cours avant de commencer
411
+ try {
412
+ await git.raw(['merge', '--abort']).catch(() => {
413
+ // Ignorer si pas de merge en cours
414
+ });
415
+ // Reset de l'index au cas où il serait dans un état instable
416
+ await git.raw(['reset', '--merge']).catch(() => {
417
+ // Ignorer si pas nécessaire
418
+ });
419
+ }
420
+ catch (cleanupError) {
421
+ if (gitConf.verbose) {
422
+ console.warn('Cleanup before merge failed (non-critical):', cleanupError);
423
+ }
424
+ }
410
425
  // 3. Update the metadata note on the PR branch itself to mark it as closed
411
426
  const finalMetadata = {
412
427
  ...originalMetadata,
@@ -420,32 +435,106 @@ async function gitClosePRRobust(git, branch, closedBy, message, config) {
420
435
  await (0, repo_tools_1.gitWriteNote)(git, headCommitHash, finalMetadata, gitConf.gitNotes.namespace);
421
436
  // 4. Now, merge the updated PR branch into the target branch
422
437
  await git.checkout(originalMetadata.mergeBase || gitConf.draftBranch);
423
- const mergeResult = await git
424
- .env({
425
- GIT_AUTHOR_NAME: closedBy.name,
426
- GIT_AUTHOR_EMAIL: closedBy.email,
427
- GIT_COMMITTER_NAME: closedBy.name,
428
- GIT_COMMITTER_EMAIL: closedBy.email,
429
- })
430
- .merge([
431
- '--no-ff', '-X', 'theirs', '-m', `Merge branch '${branch}'`, branch
432
- ]);
438
+ // 5. Stratégie de merge robuste : FORCER la préservation des changements de la branche PR
439
+ // Note: "ours" dans ce contexte signifie "garder la version de la branche qu'on merge" (la PR)
440
+ // car nous sommes sur rule-editor et on merge la PR
441
+ let mergeResult;
442
+ try {
443
+ mergeResult = await git
444
+ .env({
445
+ GIT_AUTHOR_NAME: closedBy.name,
446
+ GIT_AUTHOR_EMAIL: closedBy.email,
447
+ GIT_COMMITTER_NAME: closedBy.name,
448
+ GIT_COMMITTER_EMAIL: closedBy.email,
449
+ })
450
+ .merge([
451
+ '--no-ff',
452
+ '--strategy', 'recursive',
453
+ '--strategy-option', 'theirs',
454
+ '-m', `Merge branch '${branch}'`,
455
+ branch
456
+ ]);
457
+ }
458
+ catch (mergeError) {
459
+ if (gitConf.verbose) {
460
+ console.error('Merge failed with recursive/theirs, trying ours strategy:', mergeError);
461
+ }
462
+ // Nettoyer le merge échoué
463
+ await git.raw(['merge', '--abort']).catch(() => { });
464
+ // Stratégie de fallback ultra-agressive: stratégie "ours" qui prend TOUJOURS la version de la branche source
465
+ // ATTENTION: Ici "ours" = la branche de destination (rule-editor), donc on inverse la logique
466
+ // Solution: utiliser --strategy-option theirs avec merge forcé
467
+ try {
468
+ // Récupérer les fichiers de la PR
469
+ const prFiles = originalMetadata.files || [];
470
+ // Merger avec stratégie ours d'abord (pour créer le commit de merge)
471
+ await git
472
+ .env({
473
+ GIT_AUTHOR_NAME: closedBy.name,
474
+ GIT_AUTHOR_EMAIL: closedBy.email,
475
+ GIT_COMMITTER_NAME: closedBy.name,
476
+ GIT_COMMITTER_EMAIL: closedBy.email,
477
+ })
478
+ .merge([
479
+ '--no-ff',
480
+ '--strategy', 'ours',
481
+ '-m', `Merge branch '${branch}'`,
482
+ branch
483
+ ]);
484
+ // Puis checkout des fichiers depuis la branche PR pour forcer leurs contenus
485
+ for (const file of prFiles) {
486
+ try {
487
+ await git.raw(['checkout', branch, '--', file]);
488
+ }
489
+ catch (fileError) {
490
+ if (gitConf.verbose) {
491
+ console.warn(`Could not checkout ${file} from ${branch}:`, fileError);
492
+ }
493
+ }
494
+ }
495
+ // Amend le commit de merge avec les bons contenus
496
+ await git.commit('--amend', ['--no-edit'], {
497
+ '--author': `${closedBy.name} <${closedBy.email}>`
498
+ });
499
+ mergeResult = { summary: { changes: prFiles.length } };
500
+ }
501
+ catch (fallbackError) {
502
+ throw new errors_1.PRClosureError(`Failed to merge PR ${branch} with all strategies: ${mergeError}\nFallback error: ${fallbackError}`, branch, 'merge_failed');
503
+ }
504
+ }
433
505
  const result = {
434
506
  metadata: finalMetadata,
435
507
  failed: false,
436
- conflicts: mergeResult.conflicts,
508
+ conflicts: mergeResult?.conflicts || [],
437
509
  raw: mergeResult,
438
510
  };
439
511
  return result;
440
512
  }
441
513
  catch (error) {
514
+ // Nettoyer l'état en cas d'erreur
515
+ try {
516
+ await git.raw(['merge', '--abort']).catch(() => { });
517
+ await git.raw(['reset', '--merge']).catch(() => { });
518
+ }
519
+ catch (cleanupError) {
520
+ if (gitConf.verbose) {
521
+ console.error('Failed to cleanup merge state:', cleanupError);
522
+ }
523
+ }
442
524
  if (error instanceof errors_1.PRClosureError)
443
525
  throw error;
444
526
  throw new errors_1.PRClosureError(`Failed to close PR ${branch}: ${error}`, branch, 'unknown');
445
527
  }
446
528
  finally {
447
529
  if (currentBranch) {
448
- await git.checkout(currentBranch);
530
+ try {
531
+ await git.checkout(currentBranch);
532
+ }
533
+ catch (checkoutError) {
534
+ if (gitConf.verbose) {
535
+ console.error(`Failed to checkout back to ${currentBranch}:`, checkoutError);
536
+ }
537
+ }
449
538
  }
450
539
  (0, repo_tools_1.unlock)('checkout');
451
540
  }
@@ -506,6 +595,21 @@ async function gitNewValidationRequest(git, files, description, author, options
506
595
  throw new errors_1.PRCreationError('Author is required', undefined, files);
507
596
  }
508
597
  try {
598
+ // ✅ CLEANUP: Nettoyer tout état de merge corrompu avant de créer la branche
599
+ // Cela évite l'erreur "you need to resolve your current index first"
600
+ try {
601
+ await git.raw(['merge', '--abort']).catch(() => {
602
+ // Ignorer si pas de merge en cours
603
+ });
604
+ await git.raw(['reset', '--merge']).catch(() => {
605
+ // Ignorer si pas nécessaire
606
+ });
607
+ }
608
+ catch (cleanupError) {
609
+ if (gitConfig.verbose) {
610
+ console.warn('Cleanup before branch creation failed (non-critical):', cleanupError);
611
+ }
612
+ }
509
613
  const nextID = await gitGetNextPRNumber(git, validationBranchPrefix);
510
614
  const newBranchName = `${validationBranchPrefix}${nextID}`;
511
615
  await git.checkoutBranch(newBranchName, sourceBranch);
@@ -510,3 +510,14 @@ export interface GitHealthStatus {
510
510
  /** Recommandations de réparation */
511
511
  recommendations: string[];
512
512
  }
513
+ /**
514
+ * Rapport de migration des notes Git
515
+ */
516
+ export interface GitPrNoteMigrationReport {
517
+ migrated: number;
518
+ alreadyOk: number;
519
+ lost: Array<{
520
+ branch: string;
521
+ prNumber: number;
522
+ }>;
523
+ }
@@ -53,9 +53,17 @@ function matterParse(markdown) {
53
53
  const [rawKey, ...rawValue] = line.split(':');
54
54
  const key = rawKey.trim();
55
55
  const value = rawValue.join(':').trim();
56
- // Ignorer les clés sans valeur
57
- if (!value)
56
+ // Détection de null explicite (YAML: null, ~) - ne pas créer la clé
57
+ if (value === 'null' || value === '~' || value === 'Null' || value === 'NULL') {
58
+ // Si la valeur est null, ne pas créer la clé (comme undefined)
58
59
  continue;
60
+ }
61
+ // Si la valeur est vide (chaîne vide après trim), définir comme chaîne vide
62
+ // L'utilisateur peut définir un string vide pour indiquer qu'il n'a pas de valeur pour ce champ
63
+ if (!value) {
64
+ matter[key] = '';
65
+ continue;
66
+ }
59
67
  // Détection et parsing des arrays YAML
60
68
  if (value.startsWith('[') && value.endsWith(']')) {
61
69
  try {
@@ -122,13 +130,10 @@ function matterSerializeFromRule(rule) {
122
130
  function matterSerialize(content, matter) {
123
131
  // Créer un objet propre pour le front-matter (exclure oldfile)
124
132
  const cleanMatter = { ...matter };
125
- // //
126
- // // FIX: Convertir la Date en string pour éviter l'erreur YAML
127
- // cleanMatter.lastModified = (cleanMatter.lastModified instanceof Date) ? `${new Date().toISOString()}` : `${cleanMatter.lastModified}`;
128
133
  const result = Object.keys(cleanMatter).reduce((acc, key) => {
129
134
  const value = cleanMatter[key];
130
- // Ignorer les valeurs undefined ou null
131
- if (value === undefined || value === null) {
135
+ // Ignorer les valeurs undefined, null ou chaînes vides
136
+ if (value === undefined || value === null || value === '') {
132
137
  return acc;
133
138
  }
134
139
  if (Array.isArray(value)) {
@@ -142,6 +147,10 @@ function matterSerialize(content, matter) {
142
147
  // ✅ FIX: Ne PAS mettre de guillemets autour des booléens
143
148
  return acc + `${key}: ${value}\n`;
144
149
  }
150
+ else if (value instanceof Date) {
151
+ // ✅ FIX: Convertir Date en ISO string avec guillemets
152
+ return acc + `${key}: '${value.toISOString()}'\n`;
153
+ }
145
154
  else {
146
155
  // Pour les strings, mettre des guillemets
147
156
  return acc + `${key}: '${value}'\n`;
@@ -190,6 +190,7 @@ async function pdf2markdown(outputDir, pdf, matter, model = "MEDIUM-fast") {
190
190
  // Ca ne marche pas mieux que pdftotext
191
191
  // const { stdout } = await execFileAsync("python3", ["./bin/extract_text_with_links.py", pdf]);
192
192
  // const { text, links } = JSON.parse(stdout);
193
+ // `pdftotext -f 1 -l 2 -layout -eol unix -nodiag "${pdf}" "${outputPath}"`;
193
194
  await execAsync(`pdftotext -nodiag -nopgbrk "${pdf}" "${outputPath}"`);
194
195
  const links = await extractLinksFromPDF(pdf, outputDir);
195
196
  const text = fs_1.default.readFileSync(outputPath, "utf8");
@@ -17,6 +17,14 @@ export declare class AgentStateGraph implements IAgentStateGraph {
17
17
  createOrRestore(agentName: string, description?: string): AgentDiscussion;
18
18
  /**
19
19
  * Ajoute un message à la discussion d'un agent
20
+ * Gère tous types de messages : user, assistant, system, tool, function_call_output, etc.
21
+ *
22
+ * Utilisée par:
23
+ * - readCompletionsStream (responses.ts) : messages assistant avec tool_calls, content
24
+ * - batchProcessToolCalls (helpers.ts) : messages function_call_output
25
+ * - executeAgentSet (responses.ts) : messages user
26
+ * - stategraph.storage.ts : migration ancien format
27
+ *
20
28
  * @param agentName Nom de l'agent
21
29
  * @param message Message sans ID ni timestamp (auto-générés)
22
30
  */
@@ -30,8 +38,14 @@ export declare class AgentStateGraph implements IAgentStateGraph {
30
38
  set(agentName: string, content: string): void;
31
39
  /**
32
40
  * Ajoute une étape au CONTEXT TRAIL et met à jour le message system
41
+ * Injecte automatiquement le trail dans le system message via updateSystemMessage()
42
+ *
43
+ * Utilisée par:
44
+ * - readCompletionsStream (responses.ts) : après chaque tool call exécuté
45
+ * - Tests d'intégration pour validation du context trail
46
+ *
33
47
  * @param agentName Nom de l'agent
34
- * @param step Étape à ajouter au trail
48
+ * @param step Étape à ajouter au trail (tool, context, reason, id optionnel)
35
49
  */
36
50
  addStep(agentName: string, step: StepTrail): void;
37
51
  /**
@@ -60,6 +74,17 @@ export declare class AgentStateGraph implements IAgentStateGraph {
60
74
  /**
61
75
  * Retourne une vue filtrée pour le client
62
76
  * Supprime les messages system et les métadonnées d'outils
77
+ *
78
+ * Filtre appliqué:
79
+ * - Exclut: system, tool, messages avec name (Chat Completions function results)
80
+ * - Exclut: function_call_output (Responses API)
81
+ * - Exclut: messages assistant avec tool_calls mais sans content
82
+ * - Nettoie: <memories> tags dans le content
83
+ *
84
+ * Utilisée par:
85
+ * - ctrl/agent.ts (agentic-server) : ctrlGetHistory, ctrlExecuteAgent
86
+ * - Tests d'intégration pour validation
87
+ *
63
88
  * @param agentName Nom de l'agent
64
89
  * @returns Discussion filtrée pour l'affichage client
65
90
  */
@@ -41,6 +41,14 @@ class AgentStateGraph {
41
41
  }
42
42
  /**
43
43
  * Ajoute un message à la discussion d'un agent
44
+ * Gère tous types de messages : user, assistant, system, tool, function_call_output, etc.
45
+ *
46
+ * Utilisée par:
47
+ * - readCompletionsStream (responses.ts) : messages assistant avec tool_calls, content
48
+ * - batchProcessToolCalls (helpers.ts) : messages function_call_output
49
+ * - executeAgentSet (responses.ts) : messages user
50
+ * - stategraph.storage.ts : migration ancien format
51
+ *
44
52
  * @param agentName Nom de l'agent
45
53
  * @param message Message sans ID ni timestamp (auto-générés)
46
54
  */
@@ -83,8 +91,14 @@ class AgentStateGraph {
83
91
  }
84
92
  /**
85
93
  * Ajoute une étape au CONTEXT TRAIL et met à jour le message system
94
+ * Injecte automatiquement le trail dans le system message via updateSystemMessage()
95
+ *
96
+ * Utilisée par:
97
+ * - readCompletionsStream (responses.ts) : après chaque tool call exécuté
98
+ * - Tests d'intégration pour validation du context trail
99
+ *
86
100
  * @param agentName Nom de l'agent
87
- * @param step Étape à ajouter au trail
101
+ * @param step Étape à ajouter au trail (tool, context, reason, id optionnel)
88
102
  */
89
103
  addStep(agentName, step) {
90
104
  const discussion = this.discussions.find(d => d.startAgent === agentName);
@@ -158,6 +172,17 @@ class AgentStateGraph {
158
172
  /**
159
173
  * Retourne une vue filtrée pour le client
160
174
  * Supprime les messages system et les métadonnées d'outils
175
+ *
176
+ * Filtre appliqué:
177
+ * - Exclut: system, tool, messages avec name (Chat Completions function results)
178
+ * - Exclut: function_call_output (Responses API)
179
+ * - Exclut: messages assistant avec tool_calls mais sans content
180
+ * - Nettoie: <memories> tags dans le content
181
+ *
182
+ * Utilisée par:
183
+ * - ctrl/agent.ts (agentic-server) : ctrlGetHistory, ctrlExecuteAgent
184
+ * - Tests d'intégration pour validation
185
+ *
161
186
  * @param agentName Nom de l'agent
162
187
  * @returns Discussion filtrée pour l'affichage client
163
188
  */
@@ -170,8 +195,23 @@ class AgentStateGraph {
170
195
  return content;
171
196
  };
172
197
  // Filtrer les messages pour le client - exclure system, tool et messages avec name
198
+ // ✅ Exclure aussi les messages Responses API (type: "function_call_output") et tool_calls sans content
173
199
  const clientMessages = discussion.messages
174
- .filter(msg => msg.role !== 'system' && msg.role !== 'tool' && !msg.name)
200
+ .filter((msg) => {
201
+ // Exclure system et tool
202
+ if (msg.role === 'system' || msg.role === 'tool')
203
+ return false;
204
+ // Exclure messages avec name (Chat Completions function results)
205
+ if (msg.name)
206
+ return false;
207
+ // Exclure messages Responses API: function_call_output
208
+ if (msg.type === 'function_call_output')
209
+ return false;
210
+ // Exclure messages assistant avec tool_calls mais sans content (métadonnées de tools)
211
+ if (msg.tool_calls && msg.tool_calls.length > 0 && !msg.content)
212
+ return false;
213
+ return true;
214
+ })
175
215
  .map(msg => ({
176
216
  id: msg.id,
177
217
  role: msg.role,
@@ -184,6 +224,7 @@ class AgentStateGraph {
184
224
  description: discussion.description,
185
225
  agent: agentName,
186
226
  messages: clientMessages,
227
+ steps: [...discussion.trailSteps],
187
228
  usage: discussion.usage,
188
229
  createdAt: discussion.createdAt,
189
230
  updatedAt: discussion.updatedAt
@@ -22,6 +22,10 @@ const SESSION_STATEGRAPH_KEY = 'agentStateGraph';
22
22
  * @returns StateGraph existant ou nouveau
23
23
  */
24
24
  function sessionStateGraphGet(context) {
25
+ // ✅ Si un stateGraph est passé directement dans le contexte (mode sans session)
26
+ if (context.stateGraph && context.stateGraph instanceof stategraph_1.AgentStateGraph) {
27
+ return context.stateGraph;
28
+ }
25
29
  const session = context.session;
26
30
  if (!session) {
27
31
  // Pour les tests, retourner un nouveau StateGraph si pas de session
@@ -19,6 +19,9 @@ export interface AgentMessage {
19
19
  agent?: string;
20
20
  /** Timestamp de création */
21
21
  timestamp: Date;
22
+ type?: string;
23
+ tool_call_id?: string;
24
+ output?: string;
22
25
  }
23
26
  /**
24
27
  * Usage des tokens et coût
@@ -146,6 +149,8 @@ export interface ClientDiscussion {
146
149
  content: string;
147
150
  timestamp: Date;
148
151
  }>;
152
+ /** Context trail steps (actions effectuées) */
153
+ steps: StepTrail[];
149
154
  /** Usage des tokens */
150
155
  usage: TokenUsage;
151
156
  /** Dates */
@@ -9,12 +9,20 @@ export interface ToolParameterProperty {
9
9
  required?: string[];
10
10
  additionalProperties?: boolean;
11
11
  items?: ToolParameterProperty;
12
+ minLength?: number;
13
+ maxLength?: number;
14
+ format?: string;
15
+ minimum?: number;
16
+ maximum?: number;
17
+ default?: any;
18
+ [key: string]: any;
12
19
  }
13
20
  export interface ToolParameters {
14
21
  type: string;
15
22
  properties: Record<string, ToolParameterProperty>;
16
23
  required?: string[];
17
24
  additionalProperties?: boolean;
25
+ [key: string]: any;
18
26
  }
19
27
  export interface Tool {
20
28
  type: "function";
@@ -25,6 +33,17 @@ export interface Tool {
25
33
  strict: boolean;
26
34
  };
27
35
  }
36
+ export type ToolContractOutput<T> = {
37
+ status: "ok" | "success" | "empty" | "error" | "transfer_required" | "multiple_results";
38
+ items?: T[];
39
+ meta?: Record<string, any>;
40
+ control?: {
41
+ next_hint?: string;
42
+ can_retry: boolean;
43
+ error_code?: string;
44
+ transfer_message?: string;
45
+ };
46
+ };
28
47
  export interface AgentModelMapping {
29
48
  [key: string]: string;
30
49
  }
@@ -35,16 +54,30 @@ export interface AgentModel {
35
54
  topP?: number;
36
55
  stream?: boolean;
37
56
  parallel_tool_calls: boolean;
38
- frequencyPenalty?: number;
39
- presencePenalty?: number;
40
57
  stop?: string[] | string;
41
58
  tool_choice?: "auto" | "none" | "required";
42
59
  /**
43
60
  * Timeout in milliseconds for a query.
44
- * If not specified, the default (10 minutes).
61
+ * If not specified, the default (10 minutes).
45
62
  * https://platform.openai.com/docs/guides/flex-processing#api-request-timeouts
46
63
  */
47
64
  timeout?: number;
65
+ verbosity?: string;
66
+ reasoning_effort?: string;
67
+ frequencyPenalty?: number;
68
+ presencePenalty?: number;
69
+ text?: {
70
+ verbosity?: string;
71
+ format?: {
72
+ type: string;
73
+ name?: string;
74
+ schema?: any;
75
+ strict?: boolean;
76
+ };
77
+ };
78
+ reasoning?: {
79
+ effort: string;
80
+ };
48
81
  }
49
82
  export interface AgentConfig {
50
83
  name: string;
@@ -85,6 +118,7 @@ export interface AgenticContext {
85
118
  session: any;
86
119
  [key: string]: any;
87
120
  currentAgent?: AgentConfig;
121
+ discussionRootAgent?: string;
88
122
  }
89
123
  export type AllAgentConfigsType = Record<string, AgentConfig[]>;
90
124
  export interface Usage {
@@ -130,7 +164,8 @@ export interface ExecutionAction {
130
164
  * - `lastMessage`: The final assistant message content after execution.
131
165
  * - `usage`: Token usage/cost snapshot for the whole execution.
132
166
  * - `error`: Optional error message if something went wrong (non-fatal).
133
- * - `moreThinkin`: When true, caller should continue the execution loop (retro-compat flag).
167
+ *
168
+ * NOTE: `moreThinkin` was removed (obsolete) - reasoning_effort in modelConfig handles this natively
134
169
  */
135
170
  export interface ExecutionResult {
136
171
  runId: string;
@@ -140,7 +175,6 @@ export interface ExecutionResult {
140
175
  lastMessage: string;
141
176
  usage: Usage;
142
177
  error?: string;
143
- moreThinkin: boolean;
144
178
  /**
145
179
  * Human-readable summary formatter. Optional to preserve backward compatibility.
146
180
  */
@@ -152,10 +186,11 @@ export interface ExecutionResult {
152
186
  * Merge strategy:
153
187
  * - `runId`: preserved from the primary accumulator `a`.
154
188
  * - `actions`: appended in order (a.actions then b.actions).
155
- * - `lastMessage`: preserved from `a` unless set elsewhere later in the workflow.
189
+ * - `lastMessage`: prioritize more recent (b) over older (a).
156
190
  * - `usage`: summed field-by-field to accumulate totals across steps.
157
191
  * - `error`: keep the latest non-undefined error (prefer `b`).
158
- * - `moreThinkin`: true if either `a` or `b` requests continued thinking.
192
+ *
193
+ * NOTE: moreThinkin removed (obsolete) - always returns false
159
194
  */
160
195
  export declare function enrichExecutionResult(result: ExecutionResult): ExecutionResult;
161
196
  export declare function executionResultMerge(a: ExecutionResult, b: ExecutionResult): ExecutionResult;
package/dist/src/types.js CHANGED
@@ -8,10 +8,11 @@ exports.executionResultMerge = executionResultMerge;
8
8
  * Merge strategy:
9
9
  * - `runId`: preserved from the primary accumulator `a`.
10
10
  * - `actions`: appended in order (a.actions then b.actions).
11
- * - `lastMessage`: preserved from `a` unless set elsewhere later in the workflow.
11
+ * - `lastMessage`: prioritize more recent (b) over older (a).
12
12
  * - `usage`: summed field-by-field to accumulate totals across steps.
13
13
  * - `error`: keep the latest non-undefined error (prefer `b`).
14
- * - `moreThinkin`: true if either `a` or `b` requests continued thinking.
14
+ *
15
+ * NOTE: moreThinkin removed (obsolete) - always returns false
15
16
  */
16
17
  function enrichExecutionResult(result) {
17
18
  const formatAction = (action, index) => {
@@ -29,7 +30,7 @@ function enrichExecutionResult(result) {
29
30
  if (result.error) {
30
31
  lines.push(`error: ${result.error}`);
31
32
  }
32
- lines.push(`moreThinkin: ${Boolean(result.moreThinkin)}`);
33
+ // moreThinkin removed (obsolete) - reasoning_effort fait le job
33
34
  const actions = result.actions || [];
34
35
  lines.push(`actions (${actions.length}):`);
35
36
  actions.forEach((a, i) => lines.push(` - ${formatAction(a, i)}`));
@@ -42,16 +43,16 @@ function executionResultMerge(a, b) {
42
43
  const merged = {
43
44
  runId: a.runId && a.runId.length > 0 ? a.runId : b.runId,
44
45
  startQuery: a.startQuery || b.startQuery || '',
45
- actions: [],
46
- lastMessage: a.lastMessage || '',
46
+ actions: [...(a.actions || []), ...(b.actions || [])], // ✅ BUG FIX: Fusionner les actions
47
+ lastMessage: b.lastMessage || a.lastMessage || '', // ✅ BUG FIX: Prioriser le plus récent (b)
47
48
  usage: {
48
49
  prompt: (a.usage?.prompt || 0) + (b.usage?.prompt || 0),
49
50
  completion: (a.usage?.completion || 0) + (b.usage?.completion || 0),
50
51
  total: (a.usage?.total || 0) + (b.usage?.total || 0),
51
52
  cost: (a.usage?.cost || 0) + (b.usage?.cost || 0),
52
53
  },
53
- error: b.error ?? a.error,
54
- moreThinkin: Boolean(a.moreThinkin || b.moreThinkin),
54
+ error: b.error ?? a.error
55
+ // moreThinkin removed (obsolete) - reasoning_effort fait le job
55
56
  };
56
57
  return enrichExecutionResult(merged);
57
58
  }
@@ -24,7 +24,7 @@ async function llmExtractUserQueries(inputsection, file, options = { model: "LOW
24
24
  // response_format: { type: "json_object" }
25
25
  const result = await (0, execute_1.executeQuery)({
26
26
  query,
27
- home: options.model,
27
+ model: options.model,
28
28
  stdout: execute_1.DummyWritable,
29
29
  verbose: false,
30
30
  json: true
package/dist/src/utils.js CHANGED
@@ -15,8 +15,10 @@ const openaiInstance = function (envKey, baseUrl) {
15
15
  if (!envKey) {
16
16
  throw new Error('AI API key is missing');
17
17
  }
18
+ //
19
+ // use multiple fallback if envKey is not set
18
20
  const options = {
19
- apiKey: process.env[envKey],
21
+ apiKey: process.env[envKey] || envKey || process.env.API_LLM_KEY || process.env.OPENAI_API_KEY,
20
22
  timeout: 60000 * 15
21
23
  };
22
24
  if (baseUrl) {
@@ -152,6 +154,14 @@ ${availableAgentsList}
152
154
  //
153
155
  // Fonction pour gérer un appel de fonction retourné par OpenAI
154
156
  // le contexte est un objet qui contient des informations supplémentaires de session
157
+ //
158
+ // TODO [Phase 2 - openai-agents-js]:
159
+ // Cette logique de handleTransferCall sera remplacée par le handoff natif
160
+ // de openai-agents-js (https://openai.github.io/openai-agents-js/)
161
+ // qui gère les transferts via policies et router intégrés.
162
+ // Les concepts de downstreamAgents et confidence seront mappés
163
+ // vers les primitives de l'Agent SDK (swarm.run, handoff strategies).
164
+ // Le stateGraph restera compatible car il utilise AgentMessage générique.
155
165
  async function handleTransferCall(discussion, currentAgentRef, agents, functionCallParams, context) {
156
166
  const currentAgentName = currentAgentRef.name;
157
167
  const args = JSON.parse(functionCallParams?.function?.arguments || '{}');
@@ -199,6 +209,7 @@ async function handleTransferCall(discussion, currentAgentRef, agents, functionC
199
209
  return {
200
210
  feedback: `❌ L'agent destination "${destinationAgentName}" n'a pas été trouvé.`,
201
211
  content: `❌L'agent destination "${destinationAgentName}" n'a pas été trouvé.`,
212
+ context: `❌L'agent destination "${destinationAgentName}" n'a pas été trouvé.`,
202
213
  did_transfer: false,
203
214
  name: functionCallParams.function.name
204
215
  };
@@ -219,11 +230,24 @@ async function handleTransferCall(discussion, currentAgentRef, agents, functionC
219
230
  // ⚠️ ALWAYS inject context in tool logic, ALWAYS!
220
231
  const agent = agents.find(a => a.name === currentAgentRef.name);
221
232
  if (agent?.toolLogic && agent.toolLogic[functionCallParams.function.name]) {
222
- const { content, usage } = await agent.toolLogic[functionCallParams.function.name](args, context);
233
+ const rawResult = await agent.toolLogic[functionCallParams.function.name](args, context);
234
+ //
235
+ // ✅ Le tool peut retourner { content, context, id, usage? } OU ToolContractOutput
236
+ // - Si content existe → utiliser le texte formaté
237
+ // - Sinon → préserver rawResult pour sérialisation (ToolContractOutput)
238
+ // - context: identifiant sémantique unique pour le trail (ex: "intention_123", "daily-events")
239
+ // - id: slug unique pour détection de boucles (généralement dérivé du context)
240
+ // Si le tool ne fournit pas context/id, on utilise le nom du tool comme fallback
241
+ const toolContext = rawResult.context || 'Null';
242
+ const toolId = rawResult.id || args.justification || JSON.stringify(args);
223
243
  return {
224
- content,
244
+ content: rawResult.content, // ✅ Peut être undefined pour ToolContractOutput
225
245
  name: functionCallParams.function.name,
226
- usage
246
+ context: toolContext,
247
+ id: toolId,
248
+ usage: rawResult.usage,
249
+ feedback: rawResult.feedback,
250
+ rawResult: rawResult // ✅ Préserver le résultat brut pour sérialisation
227
251
  };
228
252
  }
229
253
  else {