agentic-api 1.0.6 → 2.0.31
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/README.md +336 -76
- package/dist/src/agents/agents.example.d.ts +3 -0
- package/dist/src/agents/agents.example.js +38 -0
- package/dist/src/agents/authentication.js +2 -0
- package/dist/src/agents/prompts.d.ts +2 -2
- package/dist/src/agents/prompts.js +112 -49
- package/dist/src/agents/reducer.core.d.ts +12 -0
- package/dist/src/agents/reducer.core.js +207 -0
- package/dist/src/agents/reducer.d.ts +3 -0
- package/dist/src/agents/reducer.example.d.ts +28 -0
- package/dist/src/agents/reducer.example.js +118 -0
- package/dist/src/agents/reducer.js +19 -0
- package/dist/src/agents/reducer.loaders.d.ts +34 -0
- package/dist/src/agents/reducer.loaders.js +122 -0
- package/dist/src/agents/reducer.process.d.ts +16 -0
- package/dist/src/agents/reducer.process.js +143 -0
- package/dist/src/agents/reducer.tools.d.ts +29 -0
- package/dist/src/agents/reducer.tools.js +157 -0
- package/dist/src/agents/reducer.types.d.ts +50 -0
- package/dist/src/agents/reducer.types.js +5 -0
- package/dist/src/agents/simulator.d.ts +47 -0
- package/dist/src/agents/simulator.executor.d.ts +26 -0
- package/dist/src/agents/simulator.executor.js +132 -0
- package/dist/src/agents/simulator.js +205 -0
- package/dist/src/agents/simulator.prompts.d.ts +16 -0
- package/dist/src/agents/simulator.prompts.js +108 -0
- package/dist/src/agents/simulator.types.d.ts +42 -0
- package/dist/src/agents/simulator.types.js +2 -0
- package/dist/src/agents/simulator.utils.d.ts +20 -0
- package/dist/src/agents/simulator.utils.js +87 -0
- package/dist/src/execute.d.ts +13 -6
- package/dist/src/execute.js +351 -85
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +14 -0
- package/dist/src/princing.openai.d.ts +9 -2
- package/dist/src/princing.openai.js +15 -11
- package/dist/src/prompts.d.ts +3 -2
- package/dist/src/prompts.js +159 -19
- package/dist/src/rag/embeddings.d.ts +103 -0
- package/dist/src/rag/embeddings.js +466 -0
- package/dist/src/rag/index.d.ts +12 -0
- package/dist/src/rag/index.js +40 -0
- package/dist/src/rag/lucene.d.ts +45 -0
- package/dist/src/rag/lucene.js +227 -0
- package/dist/src/rag/parser.d.ts +68 -0
- package/dist/src/rag/parser.js +192 -0
- package/dist/src/rag/tools.d.ts +76 -0
- package/dist/src/rag/tools.js +196 -0
- package/dist/src/rag/types.d.ts +178 -0
- package/dist/src/rag/types.js +21 -0
- package/dist/src/rag/usecase.d.ts +16 -0
- package/dist/src/rag/usecase.js +79 -0
- package/dist/src/rules/errors.d.ts +60 -0
- package/dist/src/rules/errors.js +97 -0
- package/dist/src/rules/git/git.e2e.helper.d.ts +104 -0
- package/dist/src/rules/git/git.e2e.helper.js +488 -0
- package/dist/src/rules/git/git.health.d.ts +66 -0
- package/dist/src/rules/git/git.health.js +354 -0
- package/dist/src/rules/git/git.helper.d.ts +129 -0
- package/dist/src/rules/git/git.helper.js +53 -0
- package/dist/src/rules/git/index.d.ts +6 -0
- package/dist/src/rules/git/index.js +76 -0
- package/dist/src/rules/git/repo.d.ts +128 -0
- package/dist/src/rules/git/repo.js +900 -0
- package/dist/src/rules/git/repo.pr.d.ts +137 -0
- package/dist/src/rules/git/repo.pr.js +589 -0
- package/dist/src/rules/git/repo.tools.d.ts +134 -0
- package/dist/src/rules/git/repo.tools.js +730 -0
- package/dist/src/rules/index.d.ts +8 -0
- package/dist/src/rules/index.js +25 -0
- package/dist/src/rules/messages.d.ts +17 -0
- package/dist/src/rules/messages.js +21 -0
- package/dist/src/rules/types.ctrl.d.ts +28 -0
- package/dist/src/rules/types.ctrl.js +2 -0
- package/dist/src/rules/types.d.ts +510 -0
- package/dist/src/rules/types.helpers.d.ts +132 -0
- package/dist/src/rules/types.helpers.js +2 -0
- package/dist/src/rules/types.js +33 -0
- package/dist/src/rules/user.mapper.d.ts +61 -0
- package/dist/src/rules/user.mapper.js +160 -0
- package/dist/src/rules/utils/slug.d.ts +22 -0
- package/dist/src/rules/utils/slug.js +35 -0
- package/dist/src/rules/utils.matter.d.ts +66 -0
- package/dist/src/rules/utils.matter.js +208 -0
- package/dist/src/rules/utils.slug.d.ts +22 -0
- package/dist/src/rules/utils.slug.js +35 -0
- package/dist/src/scrapper.d.ts +3 -2
- package/dist/src/scrapper.js +33 -37
- package/dist/src/stategraph/index.d.ts +8 -0
- package/dist/src/stategraph/index.js +21 -0
- package/dist/src/stategraph/stategraph.d.ts +91 -0
- package/dist/src/stategraph/stategraph.js +241 -0
- package/dist/src/stategraph/stategraph.storage.d.ts +41 -0
- package/dist/src/stategraph/stategraph.storage.js +166 -0
- package/dist/src/stategraph/types.d.ts +139 -0
- package/dist/src/stategraph/types.js +19 -0
- package/dist/src/types.d.ts +62 -39
- package/dist/src/types.js +53 -89
- package/dist/src/usecase.d.ts +4 -0
- package/dist/src/usecase.js +44 -0
- package/dist/src/utils.d.ts +12 -5
- package/dist/src/utils.js +30 -13
- package/package.json +9 -3
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LuceneManager = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
// @ts-ignore - MiniSearch sera ajouté comme dépendance
|
|
10
|
+
const minisearch_1 = __importDefault(require("minisearch"));
|
|
11
|
+
// Import des stopwords français (devra être installé comme dépendance)
|
|
12
|
+
let stopwordsFr = [];
|
|
13
|
+
try {
|
|
14
|
+
// Fallback si le package n'est pas disponible
|
|
15
|
+
const sw = require('stopwords-fr');
|
|
16
|
+
stopwordsFr = sw.default || sw;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
// Liste réduite de stopwords français de base
|
|
20
|
+
stopwordsFr = [
|
|
21
|
+
'le', 'de', 'et', 'à', 'un', 'il', 'être', 'et', 'en', 'avoir', 'que', 'pour',
|
|
22
|
+
'dans', 'ce', 'son', 'une', 'sur', 'avec', 'ne', 'se', 'pas', 'tout', 'plus',
|
|
23
|
+
'par', 'grand', 'en', 'me', 'bien', 'elle', 'si', 'tout', 'son', 'nous', 'te',
|
|
24
|
+
'ou', 'mais', 'y', 'mon', 'lui', 'nous', 'comme', 'a', 'les', 'du', 'au', 'des'
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
class LuceneManager {
|
|
28
|
+
constructor(config, baseDir) {
|
|
29
|
+
this.config = {
|
|
30
|
+
fields: ['query'],
|
|
31
|
+
storeFields: ['query', 'service', 'filename'],
|
|
32
|
+
...config
|
|
33
|
+
};
|
|
34
|
+
this.indexFile = config.outputFile
|
|
35
|
+
? path_1.default.join(baseDir, config.outputFile)
|
|
36
|
+
: path_1.default.join(baseDir, 'minisearch-queries.json');
|
|
37
|
+
this.miniSearch = new minisearch_1.default({
|
|
38
|
+
fields: this.config.fields,
|
|
39
|
+
storeFields: this.config.storeFields,
|
|
40
|
+
processTerm: this.processTerm.bind(this)
|
|
41
|
+
});
|
|
42
|
+
// Charger l'index existant si disponible
|
|
43
|
+
this.loadIndex();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Traitement des termes pour la recherche
|
|
47
|
+
*/
|
|
48
|
+
processTerm(term) {
|
|
49
|
+
// Ignorer les stopwords et les termes trop courts
|
|
50
|
+
if (stopwordsFr.includes(term.toLowerCase()) || term.length <= 2) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return term.toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Charge un index existant
|
|
57
|
+
*/
|
|
58
|
+
loadIndex() {
|
|
59
|
+
if ((0, fs_1.existsSync)(this.indexFile)) {
|
|
60
|
+
try {
|
|
61
|
+
const indexData = JSON.parse((0, fs_1.readFileSync)(this.indexFile, 'utf8'));
|
|
62
|
+
this.miniSearch = minisearch_1.default.loadJSON(JSON.stringify(indexData), {
|
|
63
|
+
fields: this.config.fields,
|
|
64
|
+
storeFields: this.config.storeFields,
|
|
65
|
+
processTerm: this.processTerm.bind(this)
|
|
66
|
+
});
|
|
67
|
+
console.log('Index Lucene chargé:', this.indexFile);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error('Erreur lors du chargement de l\'index Lucene:', error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Construit l'index Lucene à partir des fichiers de requêtes
|
|
76
|
+
*/
|
|
77
|
+
async buildIndex(queriesDir) {
|
|
78
|
+
const queriesPath = queriesDir || this.config.queriesDir || './queries/';
|
|
79
|
+
if (!(0, fs_1.existsSync)(queriesPath)) {
|
|
80
|
+
throw new Error(`Répertoire des requêtes non trouvé: ${queriesPath}`);
|
|
81
|
+
}
|
|
82
|
+
// Lister tous les fichiers JSON dans le répertoire
|
|
83
|
+
const jsonFiles = (0, fs_1.readdirSync)(queriesPath)
|
|
84
|
+
.filter(file => file.endsWith('.json'))
|
|
85
|
+
.filter(file => !file.includes('unauthorized') && !file.startsWith('skip.'))
|
|
86
|
+
.map(file => path_1.default.join(queriesPath, file));
|
|
87
|
+
if (jsonFiles.length === 0) {
|
|
88
|
+
throw new Error(`Aucun fichier JSON trouvé dans: ${queriesPath}`);
|
|
89
|
+
}
|
|
90
|
+
let indexId = 1;
|
|
91
|
+
const documents = [];
|
|
92
|
+
const services = new Set();
|
|
93
|
+
for (const file of jsonFiles) {
|
|
94
|
+
const filename = path_1.default.basename(file, path_1.default.extname(file));
|
|
95
|
+
// Le service est décrit dans le nom du fichier (premier mot avant le premier "-")
|
|
96
|
+
const service = filename.split('-')[0];
|
|
97
|
+
services.add(service);
|
|
98
|
+
process.stdout.write(`Préparation index Lucene pour ${filename} : `);
|
|
99
|
+
try {
|
|
100
|
+
const content = JSON.parse((0, fs_1.readFileSync)(file, 'utf8'));
|
|
101
|
+
if (!Array.isArray(content) || content.length === 0) {
|
|
102
|
+
console.log('❌ Aucune requête trouvée dans', file);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
for (const coverage of content) {
|
|
106
|
+
if (coverage.question) {
|
|
107
|
+
documents.push({
|
|
108
|
+
id: (indexId++).toString(),
|
|
109
|
+
query: coverage.question,
|
|
110
|
+
service,
|
|
111
|
+
filename
|
|
112
|
+
});
|
|
113
|
+
process.stdout.write('.');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
console.log(' ✅');
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
console.log(`❌ Erreur lors de la lecture de ${file}:`, error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (documents.length === 0) {
|
|
123
|
+
throw new Error('Aucun document à indexer');
|
|
124
|
+
}
|
|
125
|
+
// Construire l'index
|
|
126
|
+
console.log(`Construction de l'index Lucene avec ${documents.length} documents...`);
|
|
127
|
+
this.miniSearch.addAll(documents);
|
|
128
|
+
// Sauvegarder l'index
|
|
129
|
+
this.saveIndex();
|
|
130
|
+
console.log(`Index Lucene créé avec succès: ${documents.length} requêtes, ${services.size} services`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Sauvegarde l'index
|
|
135
|
+
*/
|
|
136
|
+
saveIndex() {
|
|
137
|
+
try {
|
|
138
|
+
const indexData = this.miniSearch.toJSON();
|
|
139
|
+
(0, fs_1.writeFileSync)(this.indexFile, JSON.stringify(indexData), { encoding: 'utf8', flag: 'w' });
|
|
140
|
+
console.log('Index Lucene sauvegardé:', this.indexFile);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('Erreur lors de la sauvegarde de l\'index Lucene:', error);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Recherche dans l'index Lucene
|
|
148
|
+
*/
|
|
149
|
+
// search(query: string, options?: {
|
|
150
|
+
// limit?: number;
|
|
151
|
+
// fuzzy?: boolean | number;
|
|
152
|
+
// prefix?: boolean;
|
|
153
|
+
// filter?: (result: LuceneIndexDocument & { score: number }) => boolean;
|
|
154
|
+
// }): LuceneSearchResult {
|
|
155
|
+
// const startTime = Date.now();
|
|
156
|
+
// const searchOptions = {
|
|
157
|
+
// fuzzy: options?.fuzzy ?? 0.2,
|
|
158
|
+
// prefix: options?.prefix ?? true,
|
|
159
|
+
// ...options
|
|
160
|
+
// };
|
|
161
|
+
// try {
|
|
162
|
+
// const rawResults = this.miniSearch.search(query, searchOptions as any);
|
|
163
|
+
// let results = rawResults.map((result: any) => ({
|
|
164
|
+
// id: result.id,
|
|
165
|
+
// query: result.query,
|
|
166
|
+
// service: result.service,
|
|
167
|
+
// filename: result.filename,
|
|
168
|
+
// score: result.score
|
|
169
|
+
// }));
|
|
170
|
+
// // Appliquer un filtre personnalisé si fourni
|
|
171
|
+
// if (options?.filter) {
|
|
172
|
+
// results = results.filter(options.filter);
|
|
173
|
+
// }
|
|
174
|
+
// // Limiter les résultats
|
|
175
|
+
// if (options?.limit) {
|
|
176
|
+
// results = results.slice(0, options.limit);
|
|
177
|
+
// }
|
|
178
|
+
// return {
|
|
179
|
+
// results,
|
|
180
|
+
// searchTime: Date.now() - startTime
|
|
181
|
+
// };
|
|
182
|
+
// } catch (error) {
|
|
183
|
+
// console.error('Erreur lors de la recherche Lucene:', error);
|
|
184
|
+
// return {
|
|
185
|
+
// results: [],
|
|
186
|
+
// searchTime: Date.now() - startTime
|
|
187
|
+
// };
|
|
188
|
+
// }
|
|
189
|
+
// }
|
|
190
|
+
/**
|
|
191
|
+
* Obtient les statistiques de l'index
|
|
192
|
+
*/
|
|
193
|
+
getStats() {
|
|
194
|
+
const documentCount = this.miniSearch.documentCount;
|
|
195
|
+
const services = new Set();
|
|
196
|
+
// Parcourir tous les documents pour compter les services
|
|
197
|
+
try {
|
|
198
|
+
// Note: MiniSearch ne fournit pas directement accès aux documents
|
|
199
|
+
// Cette méthode pourrait nécessiter une amélioration
|
|
200
|
+
const indexData = this.miniSearch.toJSON();
|
|
201
|
+
if (indexData && typeof indexData === 'object') {
|
|
202
|
+
// Estimation basée sur la taille de l'index sérialisé
|
|
203
|
+
const indexSizeKB = Math.round(JSON.stringify(indexData).length / 1024);
|
|
204
|
+
return {
|
|
205
|
+
totalDocuments: documentCount,
|
|
206
|
+
totalServices: services.size,
|
|
207
|
+
indexSize: indexSizeKB > 1024 ? `${Math.round(indexSizeKB / 1024)}MB` : `${indexSizeKB}KB`
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
console.error('Erreur lors du calcul des statistiques:', error);
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
totalDocuments: documentCount,
|
|
216
|
+
totalServices: 0,
|
|
217
|
+
indexSize: 'inconnu'
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Vérifie si l'index est prêt
|
|
222
|
+
*/
|
|
223
|
+
isReady() {
|
|
224
|
+
return this.miniSearch.documentCount > 0;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.LuceneManager = LuceneManager;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ParsedDocument, DocumentSection } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Découpe le contenu d'un document en sections séparées par '---'
|
|
4
|
+
*
|
|
5
|
+
* @param content Contenu du document
|
|
6
|
+
* @param filename Nom du fichier (pour le titre par défaut)
|
|
7
|
+
* @returns Sections et header du document
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSections(content: string, filename: string): ParsedDocument;
|
|
10
|
+
/**
|
|
11
|
+
* Récupère une section spécifique d'un document à partir de son ID
|
|
12
|
+
*
|
|
13
|
+
* @param id - ID numérique du document dans l'index
|
|
14
|
+
* @param ids - Mapping des IDs vers les noms de fichiers avec références de sections
|
|
15
|
+
* @param prefix - Chemin de base vers les documents
|
|
16
|
+
* @returns Objet contenant la source, le titre et le contenu de la section
|
|
17
|
+
* @throws Error si l'ID de document est invalide ou si la section n'existe pas
|
|
18
|
+
*/
|
|
19
|
+
export declare const getDocumentBySection: (id: number, ids: any, prefix: string) => {
|
|
20
|
+
source: any;
|
|
21
|
+
content: string;
|
|
22
|
+
title?: undefined;
|
|
23
|
+
} | {
|
|
24
|
+
source: any;
|
|
25
|
+
title: string | undefined;
|
|
26
|
+
content: DocumentSection;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Normalise un vecteur avec la norme L2
|
|
30
|
+
*
|
|
31
|
+
* @param vector Vecteur à normaliser
|
|
32
|
+
* @returns Vecteur normalisé
|
|
33
|
+
*/
|
|
34
|
+
export declare function l2Normalize(vector: number[]): number[];
|
|
35
|
+
/**
|
|
36
|
+
* Génère un slug unique pour un fichier
|
|
37
|
+
*
|
|
38
|
+
* @param filename Nom du fichier
|
|
39
|
+
* @param sectionIndex Index de la section (optionnel)
|
|
40
|
+
* @returns Slug unique
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateDocumentRef(filename: string, sectionIndex?: number): string;
|
|
43
|
+
/**
|
|
44
|
+
* Parse une référence de document pour extraire le nom de fichier et l'index de section
|
|
45
|
+
*
|
|
46
|
+
* @param ref Référence du document (filename#section-X)
|
|
47
|
+
* @returns Nom de fichier et index de section
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseDocumentRef(ref: string): {
|
|
50
|
+
filename: string;
|
|
51
|
+
sectionIndex?: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Nettoie un bloc Markdown : supprime les préfixes « Titre: » et « Section: »
|
|
55
|
+
* (placés en début de ligne, avec ou sans espaces avant/après les deux-points).
|
|
56
|
+
*
|
|
57
|
+
* @param input Texte brut à nettoyer
|
|
58
|
+
* @returns Texte sans les entités Titre: et Section:
|
|
59
|
+
*/
|
|
60
|
+
export declare function sectionParseValues(input: string): string;
|
|
61
|
+
export declare function sectionParseKey(key: string, input: string): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Supprime les blocs <thinking> du contenu généré par l'IA
|
|
64
|
+
*
|
|
65
|
+
* @param content Contenu markdown avec potentiels blocs <thinking>
|
|
66
|
+
* @returns Contenu nettoyé sans les blocs <thinking>
|
|
67
|
+
*/
|
|
68
|
+
export declare function removeThinkingBlocks(content: string): string;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDocumentBySection = void 0;
|
|
7
|
+
exports.getSections = getSections;
|
|
8
|
+
exports.l2Normalize = l2Normalize;
|
|
9
|
+
exports.generateDocumentRef = generateDocumentRef;
|
|
10
|
+
exports.parseDocumentRef = parseDocumentRef;
|
|
11
|
+
exports.sectionParseValues = sectionParseValues;
|
|
12
|
+
exports.sectionParseKey = sectionParseKey;
|
|
13
|
+
exports.removeThinkingBlocks = removeThinkingBlocks;
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const rules_1 = require("../rules");
|
|
17
|
+
/**
|
|
18
|
+
* Découpe le contenu d'un document en sections séparées par '---'
|
|
19
|
+
*
|
|
20
|
+
* @param content Contenu du document
|
|
21
|
+
* @param filename Nom du fichier (pour le titre par défaut)
|
|
22
|
+
* @returns Sections et header du document
|
|
23
|
+
*/
|
|
24
|
+
function getSections(content, filename) {
|
|
25
|
+
// IMPORTANT: Cette fonction traite les fichiers transformés par RAGGenerator
|
|
26
|
+
// qui utilisent le format "Titre: ..." et "Section: ..." délimité par "---"
|
|
27
|
+
// Vérifier si le contenu contient un front-matter,
|
|
28
|
+
// celui-ci contient le nom du fichier d'origine et le nom du service!
|
|
29
|
+
let { matter, content: contentWithoutMatter } = (0, rules_1.matterParse)(content);
|
|
30
|
+
// imprimer une alarm
|
|
31
|
+
if (matter?.mergeBase && matter?.createdBy) {
|
|
32
|
+
console.log('🔔 No standard matter found in file:', matter);
|
|
33
|
+
}
|
|
34
|
+
// S'assurer que matter contient au minimum filename et title
|
|
35
|
+
matter = {
|
|
36
|
+
...matter,
|
|
37
|
+
filename,
|
|
38
|
+
title: matter.title || filename // Utiliser le filename comme titre par défaut
|
|
39
|
+
};
|
|
40
|
+
content = contentWithoutMatter || content;
|
|
41
|
+
//
|
|
42
|
+
// le contenu est toujours sans le front-matter!
|
|
43
|
+
const rawSections = content.split('---').map(section => section.trim());
|
|
44
|
+
if (!rawSections.length) {
|
|
45
|
+
return {
|
|
46
|
+
filename,
|
|
47
|
+
sections: [],
|
|
48
|
+
content,
|
|
49
|
+
matter
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Transformer les sections brutes en DocumentSection
|
|
53
|
+
const sections = rawSections
|
|
54
|
+
.map((content, index) => ({
|
|
55
|
+
content: content.trim(),
|
|
56
|
+
index,
|
|
57
|
+
lines: content.split('\n').length,
|
|
58
|
+
title: sectionParseKey('titre', content) || undefined
|
|
59
|
+
}))
|
|
60
|
+
.filter(section => section.lines > 2); // Filtrer les sections trop courtes
|
|
61
|
+
//
|
|
62
|
+
// le matter contient les informations du fichier d'origine! (service, responssable, fichier, etc.)
|
|
63
|
+
return {
|
|
64
|
+
filename,
|
|
65
|
+
sections,
|
|
66
|
+
content,
|
|
67
|
+
matter
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Récupère une section spécifique d'un document à partir de son ID
|
|
72
|
+
*
|
|
73
|
+
* @param id - ID numérique du document dans l'index
|
|
74
|
+
* @param ids - Mapping des IDs vers les noms de fichiers avec références de sections
|
|
75
|
+
* @param prefix - Chemin de base vers les documents
|
|
76
|
+
* @returns Objet contenant la source, le titre et le contenu de la section
|
|
77
|
+
* @throws Error si l'ID de document est invalide ou si la section n'existe pas
|
|
78
|
+
*/
|
|
79
|
+
const getDocumentBySection = (id, ids, prefix) => {
|
|
80
|
+
const fullname = ids[id + ''];
|
|
81
|
+
const [filename, ref] = fullname?.split('#') || [];
|
|
82
|
+
if (!filename) {
|
|
83
|
+
console.log('❌❌ Invalid document id :' + fullname, id);
|
|
84
|
+
throw new Error('Invalid document id :' + fullname);
|
|
85
|
+
}
|
|
86
|
+
const content = (0, fs_1.readFileSync)(path_1.default.join(prefix, filename), 'utf8');
|
|
87
|
+
const { sections } = getSections(content, filename);
|
|
88
|
+
if (!sections.length) {
|
|
89
|
+
return {
|
|
90
|
+
source: fullname,
|
|
91
|
+
content: 'Le document n\'est plus disponible'
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Parse number of 'section-123'
|
|
95
|
+
const sectionNumber = parseInt(ref.match(/\d+/)[0]);
|
|
96
|
+
const section = sections[sectionNumber];
|
|
97
|
+
// console.log('--- DBG getDocument : section', sectionNumber, section?.length);
|
|
98
|
+
return {
|
|
99
|
+
source: fullname,
|
|
100
|
+
title: section.title,
|
|
101
|
+
content: section
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
exports.getDocumentBySection = getDocumentBySection;
|
|
105
|
+
// extractSectionTitle supprimée - remplacée par sectionParseKey('titre', content)
|
|
106
|
+
/**
|
|
107
|
+
* Normalise un vecteur avec la norme L2
|
|
108
|
+
*
|
|
109
|
+
* @param vector Vecteur à normaliser
|
|
110
|
+
* @returns Vecteur normalisé
|
|
111
|
+
*/
|
|
112
|
+
function l2Normalize(vector) {
|
|
113
|
+
const norm = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0));
|
|
114
|
+
return vector.map(val => val / norm);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Génère un slug unique pour un fichier
|
|
118
|
+
*
|
|
119
|
+
* @param filename Nom du fichier
|
|
120
|
+
* @param sectionIndex Index de la section (optionnel)
|
|
121
|
+
* @returns Slug unique
|
|
122
|
+
*/
|
|
123
|
+
function generateDocumentRef(filename, sectionIndex) {
|
|
124
|
+
const baseRef = filename.replace(/\.[^/.]+$/, ''); // Retirer l'extension
|
|
125
|
+
return sectionIndex !== undefined ? `${baseRef}#section-${sectionIndex}` : baseRef;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Parse une référence de document pour extraire le nom de fichier et l'index de section
|
|
129
|
+
*
|
|
130
|
+
* @param ref Référence du document (filename#section-X)
|
|
131
|
+
* @returns Nom de fichier et index de section
|
|
132
|
+
*/
|
|
133
|
+
function parseDocumentRef(ref) {
|
|
134
|
+
const [filename, sectionPart] = ref.split('#');
|
|
135
|
+
if (!sectionPart) {
|
|
136
|
+
return { filename };
|
|
137
|
+
}
|
|
138
|
+
const match = sectionPart.match(/section-(\d+)/);
|
|
139
|
+
if (match) {
|
|
140
|
+
return { filename, sectionIndex: parseInt(match[1]) };
|
|
141
|
+
}
|
|
142
|
+
return { filename };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Nettoie un bloc Markdown : supprime les préfixes « Titre: » et « Section: »
|
|
146
|
+
* (placés en début de ligne, avec ou sans espaces avant/après les deux-points).
|
|
147
|
+
*
|
|
148
|
+
* @param input Texte brut à nettoyer
|
|
149
|
+
* @returns Texte sans les entités Titre: et Section:
|
|
150
|
+
*/
|
|
151
|
+
function sectionParseValues(input) {
|
|
152
|
+
return input
|
|
153
|
+
// 1. Retirer les lignes vides en tête pour éviter des espaces résiduels
|
|
154
|
+
.replace(/^\s*\n/, '')
|
|
155
|
+
// 2. Supprimer « Titre: » ou « Section: » exclusivement en début de ligne
|
|
156
|
+
.replace(/^\s*(Titre|Section)\s*:\s*/gim, '')
|
|
157
|
+
// 3. Supprimer les espaces superflus qui pourraient rester
|
|
158
|
+
.trim();
|
|
159
|
+
}
|
|
160
|
+
function sectionParseKey(key, input) {
|
|
161
|
+
// Normaliser la clé recherchée en minuscules
|
|
162
|
+
const normalizedKey = key.toLowerCase().trim();
|
|
163
|
+
// Diviser le texte en lignes
|
|
164
|
+
const lines = input.split('\n');
|
|
165
|
+
// Chercher la ligne qui commence par la clé (case-insensitive)
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
const trimmedLine = line.trim();
|
|
168
|
+
// Vérifier si la ligne contient un ':'
|
|
169
|
+
if (trimmedLine.includes(':')) {
|
|
170
|
+
const [lineKey, ...valueParts] = trimmedLine.split(':');
|
|
171
|
+
const normalizedLineKey = lineKey.trim().toLowerCase();
|
|
172
|
+
// Comparer les clés en mode case-insensitive
|
|
173
|
+
if (normalizedLineKey === normalizedKey) {
|
|
174
|
+
const value = valueParts.join(':').trim();
|
|
175
|
+
// Retourner la valeur, même si elle est vide
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Si la clé n'est pas trouvée, lever une exception
|
|
181
|
+
// throw new Error(`Clé "${key}" non trouvée dans la section`);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Supprime les blocs <thinking> du contenu généré par l'IA
|
|
186
|
+
*
|
|
187
|
+
* @param content Contenu markdown avec potentiels blocs <thinking>
|
|
188
|
+
* @returns Contenu nettoyé sans les blocs <thinking>
|
|
189
|
+
*/
|
|
190
|
+
function removeThinkingBlocks(content) {
|
|
191
|
+
return content.replace(/<thinking>[\s\S]*?<\/thinking>/g, '').trim();
|
|
192
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { RAGConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Crée les outils RAG pour un agent
|
|
5
|
+
*/
|
|
6
|
+
declare const createTools: (openai: OpenAI, config: RAGConfig) => {
|
|
7
|
+
toolsReferencesContent: {
|
|
8
|
+
type: "function";
|
|
9
|
+
function: {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
parameters: {
|
|
13
|
+
type: string;
|
|
14
|
+
properties: {
|
|
15
|
+
service: {
|
|
16
|
+
type: string;
|
|
17
|
+
description: string;
|
|
18
|
+
};
|
|
19
|
+
source: {
|
|
20
|
+
type: string;
|
|
21
|
+
description: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
required: never[];
|
|
25
|
+
additionalProperties: boolean;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
toolsKnowledge: {
|
|
30
|
+
type: "function";
|
|
31
|
+
function: {
|
|
32
|
+
name: string;
|
|
33
|
+
description: string;
|
|
34
|
+
parameters: {
|
|
35
|
+
type: string;
|
|
36
|
+
properties: {
|
|
37
|
+
question: {
|
|
38
|
+
type: string;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
justification: {
|
|
42
|
+
type: string;
|
|
43
|
+
description: string;
|
|
44
|
+
};
|
|
45
|
+
action_suivante: {
|
|
46
|
+
type: string;
|
|
47
|
+
description: string;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
required: string[];
|
|
51
|
+
additionalProperties: boolean;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
lookupReferencesContent: ({ service, source }: {
|
|
56
|
+
service?: string;
|
|
57
|
+
source?: string;
|
|
58
|
+
}) => Promise<{
|
|
59
|
+
content: string;
|
|
60
|
+
}>;
|
|
61
|
+
lookupKnowledge: (args: any, debug?: boolean) => Promise<{
|
|
62
|
+
content: string;
|
|
63
|
+
documents?: undefined;
|
|
64
|
+
scores?: undefined;
|
|
65
|
+
} | {
|
|
66
|
+
documents: {
|
|
67
|
+
id: number;
|
|
68
|
+
ref: string;
|
|
69
|
+
score: number;
|
|
70
|
+
content: string;
|
|
71
|
+
}[];
|
|
72
|
+
scores: number[];
|
|
73
|
+
content?: undefined;
|
|
74
|
+
}>;
|
|
75
|
+
};
|
|
76
|
+
export { createTools };
|