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.
- package/dist/src/agents/prompts.d.ts +1 -1
- package/dist/src/agents/prompts.js +9 -7
- package/dist/src/agents/simulator.d.ts +7 -3
- package/dist/src/agents/simulator.executor.d.ts +9 -3
- package/dist/src/agents/simulator.executor.js +43 -17
- package/dist/src/agents/simulator.js +47 -19
- package/dist/src/agents/simulator.prompts.d.ts +9 -8
- package/dist/src/agents/simulator.prompts.js +68 -62
- package/dist/src/agents/simulator.types.d.ts +4 -1
- package/dist/src/agents/simulator.utils.js +0 -2
- package/dist/src/execute/helpers.d.ts +75 -0
- package/dist/src/execute/helpers.js +139 -0
- package/dist/src/execute/index.d.ts +11 -0
- package/dist/src/execute/index.js +44 -0
- package/dist/src/execute/legacy.d.ts +46 -0
- package/dist/src/{execute.js → execute/legacy.js} +130 -232
- package/dist/src/execute/modelconfig.d.ts +19 -0
- package/dist/src/execute/modelconfig.js +56 -0
- package/dist/src/execute/responses.d.ts +55 -0
- package/dist/src/execute/responses.js +594 -0
- package/dist/src/execute/shared.d.ts +83 -0
- package/dist/src/execute/shared.js +188 -0
- package/dist/src/index.js +1 -1
- package/dist/src/pricing.llm.d.ts +1 -1
- package/dist/src/pricing.llm.js +39 -18
- package/dist/src/rag/embeddings.js +8 -2
- package/dist/src/rag/rag.manager.js +27 -15
- package/dist/src/rules/git/git.e2e.helper.js +21 -2
- package/dist/src/rules/git/git.health.d.ts +4 -2
- package/dist/src/rules/git/git.health.js +58 -16
- package/dist/src/rules/git/index.d.ts +1 -1
- package/dist/src/rules/git/index.js +3 -2
- package/dist/src/rules/git/repo.d.ts +46 -3
- package/dist/src/rules/git/repo.js +264 -23
- package/dist/src/rules/git/repo.pr.js +117 -13
- package/dist/src/rules/types.d.ts +11 -0
- package/dist/src/rules/utils.matter.js +16 -7
- package/dist/src/scrapper.js +1 -0
- package/dist/src/stategraph/stategraph.d.ts +26 -1
- package/dist/src/stategraph/stategraph.js +43 -2
- package/dist/src/stategraph/stategraph.storage.js +4 -0
- package/dist/src/stategraph/types.d.ts +5 -0
- package/dist/src/types.d.ts +42 -7
- package/dist/src/types.js +8 -7
- package/dist/src/usecase.js +1 -1
- package/dist/src/utils.js +28 -4
- package/package.json +9 -7
- 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 =
|
|
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
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
57
|
-
if (
|
|
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
|
|
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`;
|
package/dist/src/scrapper.js
CHANGED
|
@@ -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 =>
|
|
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 */
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
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`:
|
|
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
|
-
*
|
|
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`:
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
|
54
|
+
error: b.error ?? a.error
|
|
55
|
+
// moreThinkin removed (obsolete) - reasoning_effort fait le job
|
|
55
56
|
};
|
|
56
57
|
return enrichExecutionResult(merged);
|
|
57
58
|
}
|
package/dist/src/usecase.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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 {
|