@contractspec/lib.knowledge 2.4.0 → 2.6.0
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/access/guard.d.ts +3 -0
- package/dist/access/guard.js +290 -5
- package/dist/access/index.js +290 -5
- package/dist/i18n/catalogs/en.d.ts +8 -0
- package/dist/i18n/catalogs/en.js +107 -0
- package/dist/i18n/catalogs/es.d.ts +6 -0
- package/dist/i18n/catalogs/es.js +80 -0
- package/dist/i18n/catalogs/fr.d.ts +6 -0
- package/dist/i18n/catalogs/fr.js +80 -0
- package/dist/i18n/catalogs/index.d.ts +8 -0
- package/dist/i18n/catalogs/index.js +263 -0
- package/dist/i18n/i18n.test.d.ts +1 -0
- package/dist/i18n/index.d.ts +27 -0
- package/dist/i18n/index.js +321 -0
- package/dist/i18n/keys.d.ts +74 -0
- package/dist/i18n/keys.js +33 -0
- package/dist/i18n/locale.d.ts +8 -0
- package/dist/i18n/locale.js +14 -0
- package/dist/i18n/messages.d.ts +14 -0
- package/dist/i18n/messages.js +275 -0
- package/dist/index.js +316 -23
- package/dist/ingestion/gmail-adapter.d.ts +2 -1
- package/dist/ingestion/gmail-adapter.js +284 -8
- package/dist/ingestion/index.js +284 -8
- package/dist/node/access/guard.js +290 -5
- package/dist/node/access/index.js +290 -5
- package/dist/node/i18n/catalogs/en.js +106 -0
- package/dist/node/i18n/catalogs/es.js +79 -0
- package/dist/node/i18n/catalogs/fr.js +79 -0
- package/dist/node/i18n/catalogs/index.js +262 -0
- package/dist/node/i18n/index.js +320 -0
- package/dist/node/i18n/keys.js +32 -0
- package/dist/node/i18n/locale.js +13 -0
- package/dist/node/i18n/messages.js +274 -0
- package/dist/node/index.js +316 -23
- package/dist/node/ingestion/gmail-adapter.js +284 -8
- package/dist/node/ingestion/index.js +284 -8
- package/dist/node/query/index.js +282 -10
- package/dist/node/query/service.js +282 -10
- package/dist/query/index.js +282 -10
- package/dist/query/service.d.ts +3 -0
- package/dist/query/service.js +282 -10
- package/dist/types.d.ts +2 -0
- package/package.json +125 -5
package/dist/node/index.js
CHANGED
|
@@ -1,3 +1,273 @@
|
|
|
1
|
+
// src/i18n/catalogs/en.ts
|
|
2
|
+
import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
|
|
3
|
+
var enMessages = defineTranslation({
|
|
4
|
+
meta: {
|
|
5
|
+
key: "knowledge.messages",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
domain: "knowledge",
|
|
8
|
+
description: "All user-facing and LLM-facing strings for the knowledge package",
|
|
9
|
+
owners: ["platform"],
|
|
10
|
+
stability: "experimental"
|
|
11
|
+
},
|
|
12
|
+
locale: "en",
|
|
13
|
+
fallback: "en",
|
|
14
|
+
messages: {
|
|
15
|
+
"access.notBound": {
|
|
16
|
+
value: 'Knowledge space "{spaceKey}" is not bound in the resolved app config.',
|
|
17
|
+
description: "Denial reason when a knowledge space is not bound",
|
|
18
|
+
placeholders: [{ name: "spaceKey", type: "string" }]
|
|
19
|
+
},
|
|
20
|
+
"access.readOnly": {
|
|
21
|
+
value: 'Knowledge space "{spaceKey}" is category "{category}" and is read-only.',
|
|
22
|
+
description: "Denial reason when write is attempted on a read-only space",
|
|
23
|
+
placeholders: [
|
|
24
|
+
{ name: "spaceKey", type: "string" },
|
|
25
|
+
{ name: "category", type: "string" }
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"access.workflowUnauthorized": {
|
|
29
|
+
value: 'Workflow "{workflowName}" is not authorized to access knowledge space "{spaceKey}".',
|
|
30
|
+
description: "Denial reason when a workflow lacks space access",
|
|
31
|
+
placeholders: [
|
|
32
|
+
{ name: "workflowName", type: "string" },
|
|
33
|
+
{ name: "spaceKey", type: "string" }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"access.agentUnauthorized": {
|
|
37
|
+
value: 'Agent "{agentName}" is not authorized to access knowledge space "{spaceKey}".',
|
|
38
|
+
description: "Denial reason when an agent lacks space access",
|
|
39
|
+
placeholders: [
|
|
40
|
+
{ name: "agentName", type: "string" },
|
|
41
|
+
{ name: "spaceKey", type: "string" }
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"access.ephemeralWarning": {
|
|
45
|
+
value: 'Knowledge space "{spaceKey}" is ephemeral; results may be transient.',
|
|
46
|
+
description: "Warning for ephemeral knowledge spaces",
|
|
47
|
+
placeholders: [{ name: "spaceKey", type: "string" }]
|
|
48
|
+
},
|
|
49
|
+
"query.systemPrompt": {
|
|
50
|
+
value: "You are a knowledge assistant that answers questions using the provided context. Cite relevant sources if possible.",
|
|
51
|
+
description: "Default LLM system prompt for knowledge queries"
|
|
52
|
+
},
|
|
53
|
+
"query.userMessage": {
|
|
54
|
+
value: `Question:
|
|
55
|
+
{question}
|
|
56
|
+
|
|
57
|
+
Context:
|
|
58
|
+
{context}`,
|
|
59
|
+
description: "User message template combining question and context",
|
|
60
|
+
placeholders: [
|
|
61
|
+
{ name: "question", type: "string" },
|
|
62
|
+
{ name: "context", type: "string" }
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"query.noResults": {
|
|
66
|
+
value: "No relevant documents found.",
|
|
67
|
+
description: "Displayed when vector search returns zero results"
|
|
68
|
+
},
|
|
69
|
+
"query.sourceLabel": {
|
|
70
|
+
value: "Source {index} (score: {score}):",
|
|
71
|
+
description: "Label prefix for each source in the context block",
|
|
72
|
+
placeholders: [
|
|
73
|
+
{ name: "index", type: "number" },
|
|
74
|
+
{ name: "score", type: "string" }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"ingestion.gmail.subject": {
|
|
78
|
+
value: "Subject: {subject}",
|
|
79
|
+
description: "Gmail thread subject label",
|
|
80
|
+
placeholders: [{ name: "subject", type: "string" }]
|
|
81
|
+
},
|
|
82
|
+
"ingestion.gmail.snippet": {
|
|
83
|
+
value: "Snippet: {snippet}",
|
|
84
|
+
description: "Gmail thread snippet label",
|
|
85
|
+
placeholders: [{ name: "snippet", type: "string" }]
|
|
86
|
+
},
|
|
87
|
+
"ingestion.gmail.from": {
|
|
88
|
+
value: "From: {from}",
|
|
89
|
+
description: "Gmail message sender label",
|
|
90
|
+
placeholders: [{ name: "from", type: "string" }]
|
|
91
|
+
},
|
|
92
|
+
"ingestion.gmail.to": {
|
|
93
|
+
value: "To: {to}",
|
|
94
|
+
description: "Gmail message recipients label",
|
|
95
|
+
placeholders: [{ name: "to", type: "string" }]
|
|
96
|
+
},
|
|
97
|
+
"ingestion.gmail.date": {
|
|
98
|
+
value: "Date: {date}",
|
|
99
|
+
description: "Gmail message date label",
|
|
100
|
+
placeholders: [{ name: "date", type: "string" }]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// src/i18n/catalogs/fr.ts
|
|
106
|
+
import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
|
|
107
|
+
var frMessages = defineTranslation2({
|
|
108
|
+
meta: {
|
|
109
|
+
key: "knowledge.messages",
|
|
110
|
+
version: "1.0.0",
|
|
111
|
+
domain: "knowledge",
|
|
112
|
+
description: "All user-facing and LLM-facing strings for the knowledge package (French)",
|
|
113
|
+
owners: ["platform"],
|
|
114
|
+
stability: "experimental"
|
|
115
|
+
},
|
|
116
|
+
locale: "fr",
|
|
117
|
+
fallback: "en",
|
|
118
|
+
messages: {
|
|
119
|
+
"access.notBound": {
|
|
120
|
+
value: `L'espace de connaissances "{spaceKey}" n'est pas lié dans la configuration de l'application.`,
|
|
121
|
+
description: "Denial reason when a knowledge space is not bound"
|
|
122
|
+
},
|
|
123
|
+
"access.readOnly": {
|
|
124
|
+
value: `L'espace de connaissances "{spaceKey}" est de catégorie "{category}" et est en lecture seule.`,
|
|
125
|
+
description: "Denial reason when write is attempted on a read-only space"
|
|
126
|
+
},
|
|
127
|
+
"access.workflowUnauthorized": {
|
|
128
|
+
value: `Le workflow "{workflowName}" n'est pas autorisé à accéder à l'espace de connaissances "{spaceKey}".`,
|
|
129
|
+
description: "Denial reason when a workflow lacks space access"
|
|
130
|
+
},
|
|
131
|
+
"access.agentUnauthorized": {
|
|
132
|
+
value: `L'agent "{agentName}" n'est pas autorisé à accéder à l'espace de connaissances "{spaceKey}".`,
|
|
133
|
+
description: "Denial reason when an agent lacks space access"
|
|
134
|
+
},
|
|
135
|
+
"access.ephemeralWarning": {
|
|
136
|
+
value: `L'espace de connaissances "{spaceKey}" est éphémère ; les résultats peuvent être transitoires.`,
|
|
137
|
+
description: "Warning for ephemeral knowledge spaces"
|
|
138
|
+
},
|
|
139
|
+
"query.systemPrompt": {
|
|
140
|
+
value: "Vous êtes un assistant de connaissances qui répond aux questions en utilisant le contexte fourni. Citez les sources pertinentes si possible.",
|
|
141
|
+
description: "Default LLM system prompt for knowledge queries"
|
|
142
|
+
},
|
|
143
|
+
"query.userMessage": {
|
|
144
|
+
value: `Question :
|
|
145
|
+
{question}
|
|
146
|
+
|
|
147
|
+
Contexte :
|
|
148
|
+
{context}`,
|
|
149
|
+
description: "User message template combining question and context"
|
|
150
|
+
},
|
|
151
|
+
"query.noResults": {
|
|
152
|
+
value: "Aucun document pertinent trouvé.",
|
|
153
|
+
description: "Displayed when vector search returns zero results"
|
|
154
|
+
},
|
|
155
|
+
"query.sourceLabel": {
|
|
156
|
+
value: "Source {index} (score : {score}) :",
|
|
157
|
+
description: "Label prefix for each source in the context block"
|
|
158
|
+
},
|
|
159
|
+
"ingestion.gmail.subject": {
|
|
160
|
+
value: "Objet : {subject}",
|
|
161
|
+
description: "Gmail thread subject label"
|
|
162
|
+
},
|
|
163
|
+
"ingestion.gmail.snippet": {
|
|
164
|
+
value: "Extrait : {snippet}",
|
|
165
|
+
description: "Gmail thread snippet label"
|
|
166
|
+
},
|
|
167
|
+
"ingestion.gmail.from": {
|
|
168
|
+
value: "De : {from}",
|
|
169
|
+
description: "Gmail message sender label"
|
|
170
|
+
},
|
|
171
|
+
"ingestion.gmail.to": {
|
|
172
|
+
value: "À : {to}",
|
|
173
|
+
description: "Gmail message recipients label"
|
|
174
|
+
},
|
|
175
|
+
"ingestion.gmail.date": {
|
|
176
|
+
value: "Date : {date}",
|
|
177
|
+
description: "Gmail message date label"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// src/i18n/catalogs/es.ts
|
|
183
|
+
import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
|
|
184
|
+
var esMessages = defineTranslation3({
|
|
185
|
+
meta: {
|
|
186
|
+
key: "knowledge.messages",
|
|
187
|
+
version: "1.0.0",
|
|
188
|
+
domain: "knowledge",
|
|
189
|
+
description: "All user-facing and LLM-facing strings for the knowledge package (Spanish)",
|
|
190
|
+
owners: ["platform"],
|
|
191
|
+
stability: "experimental"
|
|
192
|
+
},
|
|
193
|
+
locale: "es",
|
|
194
|
+
fallback: "en",
|
|
195
|
+
messages: {
|
|
196
|
+
"access.notBound": {
|
|
197
|
+
value: 'El espacio de conocimiento "{spaceKey}" no está vinculado en la configuración de la aplicación.',
|
|
198
|
+
description: "Denial reason when a knowledge space is not bound"
|
|
199
|
+
},
|
|
200
|
+
"access.readOnly": {
|
|
201
|
+
value: 'El espacio de conocimiento "{spaceKey}" es de categoría "{category}" y es de solo lectura.',
|
|
202
|
+
description: "Denial reason when write is attempted on a read-only space"
|
|
203
|
+
},
|
|
204
|
+
"access.workflowUnauthorized": {
|
|
205
|
+
value: 'El flujo de trabajo "{workflowName}" no está autorizado para acceder al espacio de conocimiento "{spaceKey}".',
|
|
206
|
+
description: "Denial reason when a workflow lacks space access"
|
|
207
|
+
},
|
|
208
|
+
"access.agentUnauthorized": {
|
|
209
|
+
value: 'El agente "{agentName}" no está autorizado para acceder al espacio de conocimiento "{spaceKey}".',
|
|
210
|
+
description: "Denial reason when an agent lacks space access"
|
|
211
|
+
},
|
|
212
|
+
"access.ephemeralWarning": {
|
|
213
|
+
value: 'El espacio de conocimiento "{spaceKey}" es efímero; los resultados pueden ser transitorios.',
|
|
214
|
+
description: "Warning for ephemeral knowledge spaces"
|
|
215
|
+
},
|
|
216
|
+
"query.systemPrompt": {
|
|
217
|
+
value: "Eres un asistente de conocimiento que responde preguntas utilizando el contexto proporcionado. Cita las fuentes relevantes si es posible.",
|
|
218
|
+
description: "Default LLM system prompt for knowledge queries"
|
|
219
|
+
},
|
|
220
|
+
"query.userMessage": {
|
|
221
|
+
value: `Pregunta:
|
|
222
|
+
{question}
|
|
223
|
+
|
|
224
|
+
Contexto:
|
|
225
|
+
{context}`,
|
|
226
|
+
description: "User message template combining question and context"
|
|
227
|
+
},
|
|
228
|
+
"query.noResults": {
|
|
229
|
+
value: "No se encontraron documentos relevantes.",
|
|
230
|
+
description: "Displayed when vector search returns zero results"
|
|
231
|
+
},
|
|
232
|
+
"query.sourceLabel": {
|
|
233
|
+
value: "Fuente {index} (puntuación: {score}):",
|
|
234
|
+
description: "Label prefix for each source in the context block"
|
|
235
|
+
},
|
|
236
|
+
"ingestion.gmail.subject": {
|
|
237
|
+
value: "Asunto: {subject}",
|
|
238
|
+
description: "Gmail thread subject label"
|
|
239
|
+
},
|
|
240
|
+
"ingestion.gmail.snippet": {
|
|
241
|
+
value: "Extracto: {snippet}",
|
|
242
|
+
description: "Gmail thread snippet label"
|
|
243
|
+
},
|
|
244
|
+
"ingestion.gmail.from": {
|
|
245
|
+
value: "De: {from}",
|
|
246
|
+
description: "Gmail message sender label"
|
|
247
|
+
},
|
|
248
|
+
"ingestion.gmail.to": {
|
|
249
|
+
value: "Para: {to}",
|
|
250
|
+
description: "Gmail message recipients label"
|
|
251
|
+
},
|
|
252
|
+
"ingestion.gmail.date": {
|
|
253
|
+
value: "Fecha: {date}",
|
|
254
|
+
description: "Gmail message date label"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// src/i18n/messages.ts
|
|
260
|
+
import {
|
|
261
|
+
createI18nFactory
|
|
262
|
+
} from "@contractspec/lib.contracts-spec/translations";
|
|
263
|
+
var factory = createI18nFactory({
|
|
264
|
+
specKey: "knowledge.messages",
|
|
265
|
+
catalogs: [enMessages, frMessages, esMessages]
|
|
266
|
+
});
|
|
267
|
+
var createKnowledgeI18n = factory.create;
|
|
268
|
+
var getDefaultI18n = factory.getDefault;
|
|
269
|
+
var resetI18nRegistry = factory.resetRegistry;
|
|
270
|
+
|
|
1
271
|
// src/access/guard.ts
|
|
2
272
|
var DEFAULT_DISALLOWED_WRITE = ["external", "ephemeral"];
|
|
3
273
|
|
|
@@ -5,23 +275,30 @@ class KnowledgeAccessGuard {
|
|
|
5
275
|
disallowedWrite;
|
|
6
276
|
requireWorkflowBinding;
|
|
7
277
|
requireAgentBinding;
|
|
278
|
+
i18n;
|
|
8
279
|
constructor(options = {}) {
|
|
9
280
|
this.disallowedWrite = new Set(options.disallowWriteCategories ?? DEFAULT_DISALLOWED_WRITE);
|
|
10
281
|
this.requireWorkflowBinding = options.requireWorkflowBinding ?? true;
|
|
11
282
|
this.requireAgentBinding = options.requireAgentBinding ?? false;
|
|
283
|
+
this.i18n = options.locale ? createKnowledgeI18n(options.locale) : getDefaultI18n();
|
|
12
284
|
}
|
|
13
285
|
checkAccess(spaceBinding, context, appConfig) {
|
|
14
286
|
const { binding, space } = spaceBinding;
|
|
15
287
|
if (binding.required !== false && !this.isSpaceBound(spaceBinding, appConfig)) {
|
|
16
288
|
return {
|
|
17
289
|
allowed: false,
|
|
18
|
-
reason:
|
|
290
|
+
reason: this.i18n.t("access.notBound", {
|
|
291
|
+
spaceKey: space.meta.key
|
|
292
|
+
})
|
|
19
293
|
};
|
|
20
294
|
}
|
|
21
295
|
if (context.operation === "write" && this.disallowedWrite.has(space.meta.category)) {
|
|
22
296
|
return {
|
|
23
297
|
allowed: false,
|
|
24
|
-
reason:
|
|
298
|
+
reason: this.i18n.t("access.readOnly", {
|
|
299
|
+
spaceKey: space.meta.key,
|
|
300
|
+
category: space.meta.category
|
|
301
|
+
})
|
|
25
302
|
};
|
|
26
303
|
}
|
|
27
304
|
if (this.requireWorkflowBinding && context.workflowName) {
|
|
@@ -29,7 +306,10 @@ class KnowledgeAccessGuard {
|
|
|
29
306
|
if (allowedWorkflows && !allowedWorkflows.includes(context.workflowName)) {
|
|
30
307
|
return {
|
|
31
308
|
allowed: false,
|
|
32
|
-
reason:
|
|
309
|
+
reason: this.i18n.t("access.workflowUnauthorized", {
|
|
310
|
+
workflowName: context.workflowName,
|
|
311
|
+
spaceKey: space.meta.key
|
|
312
|
+
})
|
|
33
313
|
};
|
|
34
314
|
}
|
|
35
315
|
}
|
|
@@ -38,7 +318,10 @@ class KnowledgeAccessGuard {
|
|
|
38
318
|
if (allowedAgents && !allowedAgents.includes(context.agentName)) {
|
|
39
319
|
return {
|
|
40
320
|
allowed: false,
|
|
41
|
-
reason:
|
|
321
|
+
reason: this.i18n.t("access.agentUnauthorized", {
|
|
322
|
+
agentName: context.agentName,
|
|
323
|
+
spaceKey: space.meta.key
|
|
324
|
+
})
|
|
42
325
|
};
|
|
43
326
|
}
|
|
44
327
|
}
|
|
@@ -46,7 +329,9 @@ class KnowledgeAccessGuard {
|
|
|
46
329
|
return {
|
|
47
330
|
allowed: true,
|
|
48
331
|
severity: "warning",
|
|
49
|
-
reason:
|
|
332
|
+
reason: this.i18n.t("access.ephemeralWarning", {
|
|
333
|
+
spaceKey: space.meta.key
|
|
334
|
+
})
|
|
50
335
|
};
|
|
51
336
|
}
|
|
52
337
|
return { allowed: true };
|
|
@@ -155,11 +440,13 @@ class KnowledgeQueryService {
|
|
|
155
440
|
vectorStore;
|
|
156
441
|
llm;
|
|
157
442
|
config;
|
|
443
|
+
i18n;
|
|
158
444
|
constructor(embeddings, vectorStore, llm, config) {
|
|
159
445
|
this.embeddings = embeddings;
|
|
160
446
|
this.vectorStore = vectorStore;
|
|
161
447
|
this.llm = llm;
|
|
162
448
|
this.config = config;
|
|
449
|
+
this.i18n = config.locale ? createKnowledgeI18n(config.locale) : getDefaultI18n();
|
|
163
450
|
}
|
|
164
451
|
async query(question) {
|
|
165
452
|
const embedding = await this.embeddings.embedQuery(question);
|
|
@@ -170,7 +457,7 @@ class KnowledgeQueryService {
|
|
|
170
457
|
namespace: this.config.namespace,
|
|
171
458
|
filter: undefined
|
|
172
459
|
});
|
|
173
|
-
const context = buildContext(results);
|
|
460
|
+
const context = buildContext(results, this.i18n);
|
|
174
461
|
const messages = this.buildMessages(question, context);
|
|
175
462
|
const response = await this.llm.chat(messages);
|
|
176
463
|
return {
|
|
@@ -183,7 +470,7 @@ class KnowledgeQueryService {
|
|
|
183
470
|
};
|
|
184
471
|
}
|
|
185
472
|
buildMessages(question, context) {
|
|
186
|
-
const systemPrompt = this.config.systemPrompt ??
|
|
473
|
+
const systemPrompt = this.config.systemPrompt ?? this.i18n.t("query.systemPrompt");
|
|
187
474
|
return [
|
|
188
475
|
{
|
|
189
476
|
role: "system",
|
|
@@ -194,24 +481,24 @@ class KnowledgeQueryService {
|
|
|
194
481
|
content: [
|
|
195
482
|
{
|
|
196
483
|
type: "text",
|
|
197
|
-
text:
|
|
198
|
-
${question}
|
|
199
|
-
|
|
200
|
-
Context:
|
|
201
|
-
${context}`
|
|
484
|
+
text: this.i18n.t("query.userMessage", { question, context })
|
|
202
485
|
}
|
|
203
486
|
]
|
|
204
487
|
}
|
|
205
488
|
];
|
|
206
489
|
}
|
|
207
490
|
}
|
|
208
|
-
function buildContext(results) {
|
|
491
|
+
function buildContext(results, i18n) {
|
|
209
492
|
if (results.length === 0) {
|
|
210
|
-
return "
|
|
493
|
+
return i18n.t("query.noResults");
|
|
211
494
|
}
|
|
212
495
|
return results.map((result, index) => {
|
|
213
496
|
const text = extractText(result);
|
|
214
|
-
|
|
497
|
+
const label = i18n.t("query.sourceLabel", {
|
|
498
|
+
index: index + 1,
|
|
499
|
+
score: result.score.toFixed(3)
|
|
500
|
+
});
|
|
501
|
+
return `${label}
|
|
215
502
|
${text}`;
|
|
216
503
|
}).join(`
|
|
217
504
|
|
|
@@ -347,11 +634,13 @@ class GmailIngestionAdapter {
|
|
|
347
634
|
processor;
|
|
348
635
|
embeddings;
|
|
349
636
|
indexer;
|
|
350
|
-
|
|
637
|
+
i18n;
|
|
638
|
+
constructor(gmail, processor, embeddings, indexer, locale) {
|
|
351
639
|
this.gmail = gmail;
|
|
352
640
|
this.processor = processor;
|
|
353
641
|
this.embeddings = embeddings;
|
|
354
642
|
this.indexer = indexer;
|
|
643
|
+
this.i18n = locale ? createKnowledgeI18n(locale) : getDefaultI18n();
|
|
355
644
|
}
|
|
356
645
|
async syncThreads(query) {
|
|
357
646
|
const threads = await this.gmail.listThreads(query);
|
|
@@ -366,7 +655,7 @@ class GmailIngestionAdapter {
|
|
|
366
655
|
await this.indexer.upsert(fragments, embeddings);
|
|
367
656
|
}
|
|
368
657
|
toRawDocument(thread) {
|
|
369
|
-
const content = composeThreadText(thread);
|
|
658
|
+
const content = composeThreadText(thread, this.i18n);
|
|
370
659
|
return {
|
|
371
660
|
id: thread.id,
|
|
372
661
|
mimeType: "text/plain",
|
|
@@ -379,18 +668,22 @@ class GmailIngestionAdapter {
|
|
|
379
668
|
};
|
|
380
669
|
}
|
|
381
670
|
}
|
|
382
|
-
function composeThreadText(thread) {
|
|
671
|
+
function composeThreadText(thread, i18n) {
|
|
383
672
|
const header = [
|
|
384
|
-
|
|
385
|
-
|
|
673
|
+
i18n.t("ingestion.gmail.subject", { subject: thread.subject ?? "" }),
|
|
674
|
+
i18n.t("ingestion.gmail.snippet", { snippet: thread.snippet ?? "" })
|
|
386
675
|
];
|
|
387
676
|
const messageTexts = thread.messages.map((message) => {
|
|
388
677
|
const parts = [
|
|
389
|
-
|
|
390
|
-
|
|
678
|
+
i18n.t("ingestion.gmail.from", { from: formatAddress(message.from) }),
|
|
679
|
+
i18n.t("ingestion.gmail.to", {
|
|
680
|
+
to: message.to.map(formatAddress).join(", ")
|
|
681
|
+
})
|
|
391
682
|
];
|
|
392
683
|
if (message.sentAt) {
|
|
393
|
-
parts.push(
|
|
684
|
+
parts.push(i18n.t("ingestion.gmail.date", {
|
|
685
|
+
date: message.sentAt.toISOString()
|
|
686
|
+
}));
|
|
394
687
|
}
|
|
395
688
|
const body = message.textBody ?? stripHtml(message.htmlBody ?? "");
|
|
396
689
|
return `${parts.join(`
|