@lssm/lib.knowledge 0.0.0-canary-20251217062943 → 0.0.0-canary-20251217072406
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.js +49 -1
- package/dist/access/index.js +3 -1
- package/dist/index.js +12 -1
- package/dist/ingestion/document-processor.js +54 -1
- package/dist/ingestion/embedding-service.js +25 -1
- package/dist/ingestion/gmail-adapter.js +50 -5
- package/dist/ingestion/index.js +7 -1
- package/dist/ingestion/storage-adapter.js +26 -1
- package/dist/ingestion/vector-indexer.js +32 -1
- package/dist/query/index.js +3 -1
- package/dist/query/service.js +64 -2
- package/dist/retriever/index.js +4 -1
- package/dist/retriever/static-retriever.js +47 -2
- package/dist/retriever/vector-retriever.js +60 -1
- package/package.json +4 -4
package/dist/access/guard.js
CHANGED
|
@@ -1 +1,49 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/access/guard.ts
|
|
2
|
+
const DEFAULT_DISALLOWED_WRITE = ["external", "ephemeral"];
|
|
3
|
+
var KnowledgeAccessGuard = class {
|
|
4
|
+
disallowedWrite;
|
|
5
|
+
requireWorkflowBinding;
|
|
6
|
+
requireAgentBinding;
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.disallowedWrite = new Set(options.disallowWriteCategories ?? DEFAULT_DISALLOWED_WRITE);
|
|
9
|
+
this.requireWorkflowBinding = options.requireWorkflowBinding ?? true;
|
|
10
|
+
this.requireAgentBinding = options.requireAgentBinding ?? false;
|
|
11
|
+
}
|
|
12
|
+
checkAccess(spaceBinding, context, appConfig) {
|
|
13
|
+
const { binding, space } = spaceBinding;
|
|
14
|
+
if (binding.required !== false && !this.isSpaceBound(spaceBinding, appConfig)) return {
|
|
15
|
+
allowed: false,
|
|
16
|
+
reason: `Knowledge space "${space.meta.key}" is not bound in the resolved app config.`
|
|
17
|
+
};
|
|
18
|
+
if (context.operation === "write" && this.disallowedWrite.has(space.meta.category)) return {
|
|
19
|
+
allowed: false,
|
|
20
|
+
reason: `Knowledge space "${space.meta.key}" is category "${space.meta.category}" and is read-only.`
|
|
21
|
+
};
|
|
22
|
+
if (this.requireWorkflowBinding && context.workflowName) {
|
|
23
|
+
const allowedWorkflows = binding.scope?.workflows;
|
|
24
|
+
if (allowedWorkflows && !allowedWorkflows.includes(context.workflowName)) return {
|
|
25
|
+
allowed: false,
|
|
26
|
+
reason: `Workflow "${context.workflowName}" is not authorized to access knowledge space "${space.meta.key}".`
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (this.requireAgentBinding && context.agentName) {
|
|
30
|
+
const allowedAgents = binding.scope?.agents;
|
|
31
|
+
if (allowedAgents && !allowedAgents.includes(context.agentName)) return {
|
|
32
|
+
allowed: false,
|
|
33
|
+
reason: `Agent "${context.agentName}" is not authorized to access knowledge space "${space.meta.key}".`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (space.meta.category === "ephemeral") return {
|
|
37
|
+
allowed: true,
|
|
38
|
+
severity: "warning",
|
|
39
|
+
reason: `Knowledge space "${space.meta.key}" is ephemeral; results may be transient.`
|
|
40
|
+
};
|
|
41
|
+
return { allowed: true };
|
|
42
|
+
}
|
|
43
|
+
isSpaceBound(resolved, appConfig) {
|
|
44
|
+
return appConfig.knowledge.some((entry) => entry.space.meta.key === resolved.space.meta.key && (resolved.space.meta.version == null || entry.space.meta.version === resolved.space.meta.version));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { KnowledgeAccessGuard };
|
package/dist/access/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
import{StaticRetriever
|
|
1
|
+
import { StaticRetriever, createStaticRetriever } from "./retriever/static-retriever.js";
|
|
2
|
+
import { VectorRetriever, createVectorRetriever } from "./retriever/vector-retriever.js";
|
|
3
|
+
import { KnowledgeQueryService } from "./query/service.js";
|
|
4
|
+
import { DocumentProcessor } from "./ingestion/document-processor.js";
|
|
5
|
+
import { EmbeddingService } from "./ingestion/embedding-service.js";
|
|
6
|
+
import { VectorIndexer } from "./ingestion/vector-indexer.js";
|
|
7
|
+
import { GmailIngestionAdapter } from "./ingestion/gmail-adapter.js";
|
|
8
|
+
import { StorageIngestionAdapter } from "./ingestion/storage-adapter.js";
|
|
9
|
+
import "./ingestion/index.js";
|
|
10
|
+
import { KnowledgeAccessGuard } from "./access/guard.js";
|
|
11
|
+
|
|
12
|
+
export { DocumentProcessor, EmbeddingService, GmailIngestionAdapter, KnowledgeAccessGuard, KnowledgeQueryService, StaticRetriever, StorageIngestionAdapter, VectorIndexer, VectorRetriever, createStaticRetriever, createVectorRetriever };
|
|
@@ -1 +1,54 @@
|
|
|
1
|
-
import{Buffer
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
|
|
3
|
+
//#region src/ingestion/document-processor.ts
|
|
4
|
+
var DocumentProcessor = class {
|
|
5
|
+
extractors = /* @__PURE__ */ new Map();
|
|
6
|
+
constructor() {
|
|
7
|
+
this.registerExtractor("text/plain", this.extractText.bind(this));
|
|
8
|
+
this.registerExtractor("application/json", this.extractJson.bind(this));
|
|
9
|
+
}
|
|
10
|
+
registerExtractor(mimeType, extractor) {
|
|
11
|
+
this.extractors.set(mimeType.toLowerCase(), extractor);
|
|
12
|
+
}
|
|
13
|
+
async process(document) {
|
|
14
|
+
const extractor = this.extractors.get(document.mimeType.toLowerCase()) ?? this.extractors.get("*/*");
|
|
15
|
+
if (!extractor) throw new Error(`No extractor registered for mime type ${document.mimeType}`);
|
|
16
|
+
const fragments = await extractor(document);
|
|
17
|
+
if (fragments.length === 0) return [{
|
|
18
|
+
id: `${document.id}:0`,
|
|
19
|
+
documentId: document.id,
|
|
20
|
+
text: "",
|
|
21
|
+
metadata: document.metadata
|
|
22
|
+
}];
|
|
23
|
+
return fragments;
|
|
24
|
+
}
|
|
25
|
+
async extractText(document) {
|
|
26
|
+
const text = Buffer.from(document.data).toString("utf-8");
|
|
27
|
+
return [{
|
|
28
|
+
id: `${document.id}:0`,
|
|
29
|
+
documentId: document.id,
|
|
30
|
+
text,
|
|
31
|
+
metadata: document.metadata
|
|
32
|
+
}];
|
|
33
|
+
}
|
|
34
|
+
async extractJson(document) {
|
|
35
|
+
const text = Buffer.from(document.data).toString("utf-8");
|
|
36
|
+
try {
|
|
37
|
+
const json = JSON.parse(text);
|
|
38
|
+
return [{
|
|
39
|
+
id: `${document.id}:0`,
|
|
40
|
+
documentId: document.id,
|
|
41
|
+
text: JSON.stringify(json, null, 2),
|
|
42
|
+
metadata: {
|
|
43
|
+
...document.metadata,
|
|
44
|
+
contentType: "application/json"
|
|
45
|
+
}
|
|
46
|
+
}];
|
|
47
|
+
} catch {
|
|
48
|
+
return this.extractText(document);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
export { DocumentProcessor };
|
|
@@ -1 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/ingestion/embedding-service.ts
|
|
2
|
+
var EmbeddingService = class {
|
|
3
|
+
provider;
|
|
4
|
+
batchSize;
|
|
5
|
+
constructor(provider, batchSize = 16) {
|
|
6
|
+
this.provider = provider;
|
|
7
|
+
this.batchSize = batchSize;
|
|
8
|
+
}
|
|
9
|
+
async embedFragments(fragments) {
|
|
10
|
+
const results = [];
|
|
11
|
+
for (let i = 0; i < fragments.length; i += this.batchSize) {
|
|
12
|
+
const documents = fragments.slice(i, i + this.batchSize).map((fragment) => ({
|
|
13
|
+
id: fragment.id,
|
|
14
|
+
text: fragment.text,
|
|
15
|
+
metadata: fragment.metadata
|
|
16
|
+
}));
|
|
17
|
+
const embeddings = await this.provider.embedDocuments(documents);
|
|
18
|
+
results.push(...embeddings);
|
|
19
|
+
}
|
|
20
|
+
return results;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { EmbeddingService };
|
|
@@ -1,6 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/ingestion/gmail-adapter.ts
|
|
2
|
+
var GmailIngestionAdapter = class {
|
|
3
|
+
constructor(gmail, processor, embeddings, indexer) {
|
|
4
|
+
this.gmail = gmail;
|
|
5
|
+
this.processor = processor;
|
|
6
|
+
this.embeddings = embeddings;
|
|
7
|
+
this.indexer = indexer;
|
|
8
|
+
}
|
|
9
|
+
async syncThreads(query) {
|
|
10
|
+
const threads = await this.gmail.listThreads(query);
|
|
11
|
+
for (const thread of threads) await this.ingestThread(thread);
|
|
12
|
+
}
|
|
13
|
+
async ingestThread(thread) {
|
|
14
|
+
const document = this.toRawDocument(thread);
|
|
15
|
+
const fragments = await this.processor.process(document);
|
|
16
|
+
const embeddings = await this.embeddings.embedFragments(fragments);
|
|
17
|
+
await this.indexer.upsert(fragments, embeddings);
|
|
18
|
+
}
|
|
19
|
+
toRawDocument(thread) {
|
|
20
|
+
const content = composeThreadText(thread);
|
|
21
|
+
return {
|
|
22
|
+
id: thread.id,
|
|
23
|
+
mimeType: "text/plain",
|
|
24
|
+
data: Buffer.from(content, "utf-8"),
|
|
25
|
+
metadata: {
|
|
26
|
+
subject: thread.subject ?? "",
|
|
27
|
+
participants: thread.participants.map((p) => p.email).join(", "),
|
|
28
|
+
updatedAt: thread.updatedAt.toISOString()
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function composeThreadText(thread) {
|
|
34
|
+
const header = [`Subject: ${thread.subject ?? ""}`, `Snippet: ${thread.snippet ?? ""}`];
|
|
35
|
+
const messageTexts = thread.messages.map((message) => {
|
|
36
|
+
const parts = [`From: ${formatAddress(message.from)}`, `To: ${message.to.map(formatAddress).join(", ")}`];
|
|
37
|
+
if (message.sentAt) parts.push(`Date: ${message.sentAt.toISOString()}`);
|
|
38
|
+
const body = message.textBody ?? stripHtml(message.htmlBody ?? "");
|
|
39
|
+
return `${parts.join("\n")}\n\n${body ?? ""}`;
|
|
40
|
+
});
|
|
41
|
+
return [...header, ...messageTexts].join("\n\n---\n\n");
|
|
42
|
+
}
|
|
43
|
+
function formatAddress(address) {
|
|
44
|
+
return address.name ? `${address.name} <${address.email}>` : address.email;
|
|
45
|
+
}
|
|
46
|
+
function stripHtml(html) {
|
|
47
|
+
return html.replace(/<[^>]+>/g, " ");
|
|
48
|
+
}
|
|
3
49
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`)}function n(e){return e.name?`${e.name} <${e.email}>`:e.email}function r(e){return e.replace(/<[^>]+>/g,` `)}export{e as GmailIngestionAdapter};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { GmailIngestionAdapter };
|
package/dist/ingestion/index.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DocumentProcessor } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingService } from "./embedding-service.js";
|
|
3
|
+
import { VectorIndexer } from "./vector-indexer.js";
|
|
4
|
+
import { GmailIngestionAdapter } from "./gmail-adapter.js";
|
|
5
|
+
import { StorageIngestionAdapter } from "./storage-adapter.js";
|
|
6
|
+
|
|
7
|
+
export { DocumentProcessor, EmbeddingService, GmailIngestionAdapter, StorageIngestionAdapter, VectorIndexer };
|
|
@@ -1 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/ingestion/storage-adapter.ts
|
|
2
|
+
var StorageIngestionAdapter = class {
|
|
3
|
+
constructor(processor, embeddings, indexer) {
|
|
4
|
+
this.processor = processor;
|
|
5
|
+
this.embeddings = embeddings;
|
|
6
|
+
this.indexer = indexer;
|
|
7
|
+
}
|
|
8
|
+
async ingestObject(object) {
|
|
9
|
+
if (!("data" in object) || !object.data) throw new Error("Storage ingestion requires object data");
|
|
10
|
+
const raw = {
|
|
11
|
+
id: object.key,
|
|
12
|
+
mimeType: object.contentType ?? "application/octet-stream",
|
|
13
|
+
data: object.data,
|
|
14
|
+
metadata: {
|
|
15
|
+
bucket: object.bucket,
|
|
16
|
+
checksum: object.checksum ?? ""
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const fragments = await this.processor.process(raw);
|
|
20
|
+
const embeddings = await this.embeddings.embedFragments(fragments);
|
|
21
|
+
await this.indexer.upsert(fragments, embeddings);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { StorageIngestionAdapter };
|
|
@@ -1 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/ingestion/vector-indexer.ts
|
|
2
|
+
var VectorIndexer = class {
|
|
3
|
+
provider;
|
|
4
|
+
config;
|
|
5
|
+
constructor(provider, config) {
|
|
6
|
+
this.provider = provider;
|
|
7
|
+
this.config = config;
|
|
8
|
+
}
|
|
9
|
+
async upsert(fragments, embeddings) {
|
|
10
|
+
const documents = embeddings.map((embedding) => {
|
|
11
|
+
const fragment = fragments.find((f) => f.id === embedding.id);
|
|
12
|
+
return {
|
|
13
|
+
id: embedding.id,
|
|
14
|
+
vector: embedding.vector,
|
|
15
|
+
payload: {
|
|
16
|
+
...this.config.metadata,
|
|
17
|
+
...fragment?.metadata ?? {},
|
|
18
|
+
documentId: fragment?.documentId
|
|
19
|
+
},
|
|
20
|
+
namespace: this.config.namespace
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
const request = {
|
|
24
|
+
collection: this.config.collection,
|
|
25
|
+
documents
|
|
26
|
+
};
|
|
27
|
+
await this.provider.upsert(request);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { VectorIndexer };
|
package/dist/query/index.js
CHANGED
package/dist/query/service.js
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/query/service.ts
|
|
2
|
+
var KnowledgeQueryService = class {
|
|
3
|
+
embeddings;
|
|
4
|
+
vectorStore;
|
|
5
|
+
llm;
|
|
6
|
+
config;
|
|
7
|
+
constructor(embeddings, vectorStore, llm, config) {
|
|
8
|
+
this.embeddings = embeddings;
|
|
9
|
+
this.vectorStore = vectorStore;
|
|
10
|
+
this.llm = llm;
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
async query(question) {
|
|
14
|
+
const embedding = await this.embeddings.embedQuery(question);
|
|
15
|
+
const results = await this.vectorStore.search({
|
|
16
|
+
collection: this.config.collection,
|
|
17
|
+
vector: embedding.vector,
|
|
18
|
+
topK: this.config.topK ?? 5,
|
|
19
|
+
namespace: this.config.namespace,
|
|
20
|
+
filter: void 0
|
|
21
|
+
});
|
|
22
|
+
const context = buildContext(results);
|
|
23
|
+
const messages = this.buildMessages(question, context);
|
|
24
|
+
const response = await this.llm.chat(messages);
|
|
25
|
+
return {
|
|
26
|
+
answer: response.message.content.map((part) => "text" in part ? part.text : "").join(""),
|
|
27
|
+
references: results.map((result) => ({
|
|
28
|
+
...result,
|
|
29
|
+
text: extractText(result)
|
|
30
|
+
})),
|
|
31
|
+
usage: response.usage
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
buildMessages(question, context) {
|
|
35
|
+
return [{
|
|
36
|
+
role: "system",
|
|
37
|
+
content: [{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: this.config.systemPrompt ?? "You are a knowledge assistant that answers questions using the provided context. Cite relevant sources if possible."
|
|
40
|
+
}]
|
|
41
|
+
}, {
|
|
42
|
+
role: "user",
|
|
43
|
+
content: [{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: `Question:\n${question}\n\nContext:\n${context}`
|
|
46
|
+
}]
|
|
47
|
+
}];
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function buildContext(results) {
|
|
51
|
+
if (results.length === 0) return "No relevant documents found.";
|
|
52
|
+
return results.map((result, index) => {
|
|
53
|
+
const text = extractText(result);
|
|
54
|
+
return `Source ${index + 1} (score: ${result.score.toFixed(3)}):\n${text}`;
|
|
55
|
+
}).join("\n\n");
|
|
56
|
+
}
|
|
57
|
+
function extractText(result) {
|
|
58
|
+
const payload = result.payload ?? {};
|
|
59
|
+
if (typeof payload.text === "string") return payload.text;
|
|
60
|
+
if (typeof payload.content === "string") return payload.content;
|
|
61
|
+
return JSON.stringify(payload);
|
|
62
|
+
}
|
|
2
63
|
|
|
3
|
-
|
|
64
|
+
//#endregion
|
|
65
|
+
export { KnowledgeQueryService };
|
package/dist/retriever/index.js
CHANGED
|
@@ -1 +1,4 @@
|
|
|
1
|
-
import{StaticRetriever
|
|
1
|
+
import { StaticRetriever, createStaticRetriever } from "./static-retriever.js";
|
|
2
|
+
import { VectorRetriever, createVectorRetriever } from "./vector-retriever.js";
|
|
3
|
+
|
|
4
|
+
export { StaticRetriever, VectorRetriever, createStaticRetriever, createVectorRetriever };
|
|
@@ -1,2 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/retriever/static-retriever.ts
|
|
2
|
+
/**
|
|
3
|
+
* A simple in-memory retriever for static knowledge content.
|
|
4
|
+
*
|
|
5
|
+
* Useful for:
|
|
6
|
+
* - Required knowledge that doesn't need semantic search
|
|
7
|
+
* - Testing and development
|
|
8
|
+
* - Small knowledge bases that fit in memory
|
|
9
|
+
*/
|
|
10
|
+
var StaticRetriever = class {
|
|
11
|
+
content;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.content = config.content instanceof Map ? config.content : new Map(Object.entries(config.content));
|
|
14
|
+
}
|
|
15
|
+
async retrieve(query, options) {
|
|
16
|
+
const content = this.content.get(options.spaceKey);
|
|
17
|
+
if (!content) return [];
|
|
18
|
+
const queryLower = query.toLowerCase();
|
|
19
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
20
|
+
const results = [];
|
|
21
|
+
for (const line of lines) if (line.toLowerCase().includes(queryLower)) results.push({
|
|
22
|
+
content: line,
|
|
23
|
+
source: options.spaceKey,
|
|
24
|
+
score: 1,
|
|
25
|
+
metadata: { type: "static" }
|
|
26
|
+
});
|
|
27
|
+
return results.slice(0, options.topK ?? 5);
|
|
28
|
+
}
|
|
29
|
+
async getStatic(spaceKey) {
|
|
30
|
+
return this.content.get(spaceKey) ?? null;
|
|
31
|
+
}
|
|
32
|
+
supportsSpace(spaceKey) {
|
|
33
|
+
return this.content.has(spaceKey);
|
|
34
|
+
}
|
|
35
|
+
listSpaces() {
|
|
36
|
+
return [...this.content.keys()];
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Create a static retriever from a content map.
|
|
41
|
+
*/
|
|
42
|
+
function createStaticRetriever(content) {
|
|
43
|
+
return new StaticRetriever({ content });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { StaticRetriever, createStaticRetriever };
|
|
@@ -1 +1,60 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/retriever/vector-retriever.ts
|
|
2
|
+
/**
|
|
3
|
+
* A retriever that uses vector similarity search.
|
|
4
|
+
*
|
|
5
|
+
* Uses embedding provider to vectorize queries and vector store
|
|
6
|
+
* provider to perform similarity search.
|
|
7
|
+
*/
|
|
8
|
+
var VectorRetriever = class {
|
|
9
|
+
config;
|
|
10
|
+
spaceCollections;
|
|
11
|
+
staticContent;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.spaceCollections = config.spaceCollections instanceof Map ? config.spaceCollections : new Map(Object.entries(config.spaceCollections));
|
|
15
|
+
this.staticContent = config.staticContent ? config.staticContent instanceof Map ? config.staticContent : new Map(Object.entries(config.staticContent)) : /* @__PURE__ */ new Map();
|
|
16
|
+
}
|
|
17
|
+
async retrieve(query, options) {
|
|
18
|
+
const collection = this.spaceCollections.get(options.spaceKey);
|
|
19
|
+
if (!collection) return [];
|
|
20
|
+
const embedding = await this.config.embeddings.embedQuery(query);
|
|
21
|
+
const results = await this.config.vectorStore.search({
|
|
22
|
+
collection,
|
|
23
|
+
vector: embedding.vector,
|
|
24
|
+
topK: options.topK ?? this.config.defaultTopK ?? 5,
|
|
25
|
+
namespace: options.tenantId,
|
|
26
|
+
filter: options.filter
|
|
27
|
+
});
|
|
28
|
+
const minScore = options.minScore ?? this.config.defaultMinScore ?? 0;
|
|
29
|
+
return results.filter((r) => r.score >= minScore).map((result) => ({
|
|
30
|
+
content: this.extractContent(result.payload),
|
|
31
|
+
source: result.id,
|
|
32
|
+
score: result.score,
|
|
33
|
+
metadata: result.payload
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
async getStatic(spaceKey) {
|
|
37
|
+
return this.staticContent.get(spaceKey) ?? null;
|
|
38
|
+
}
|
|
39
|
+
supportsSpace(spaceKey) {
|
|
40
|
+
return this.spaceCollections.has(spaceKey);
|
|
41
|
+
}
|
|
42
|
+
listSpaces() {
|
|
43
|
+
return [...this.spaceCollections.keys()];
|
|
44
|
+
}
|
|
45
|
+
extractContent(payload) {
|
|
46
|
+
if (!payload) return "";
|
|
47
|
+
if (typeof payload.text === "string") return payload.text;
|
|
48
|
+
if (typeof payload.content === "string") return payload.content;
|
|
49
|
+
return JSON.stringify(payload);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Create a vector retriever from configuration.
|
|
54
|
+
*/
|
|
55
|
+
function createVectorRetriever(config) {
|
|
56
|
+
return new VectorRetriever(config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { VectorRetriever, createVectorRetriever };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/lib.knowledge",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20251217072406",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"test": "bun test"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@lssm/lib.contracts": "0.0.0-canary-
|
|
26
|
+
"@lssm/lib.contracts": "0.0.0-canary-20251217072406"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@lssm/tool.tsdown": "0.0.0-canary-
|
|
30
|
-
"@lssm/tool.typescript": "0.0.0-canary-
|
|
29
|
+
"@lssm/tool.tsdown": "0.0.0-canary-20251217072406",
|
|
30
|
+
"@lssm/tool.typescript": "0.0.0-canary-20251217072406",
|
|
31
31
|
"tsdown": "^0.17.4",
|
|
32
32
|
"typescript": "^5.9.3"
|
|
33
33
|
},
|