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