@contractspec/lib.knowledge 0.0.0-canary-20260113162409
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/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/access/guard.d.ts +20 -0
- package/dist/access/guard.d.ts.map +1 -0
- package/dist/access/guard.js +50 -0
- package/dist/access/guard.js.map +1 -0
- package/dist/access/index.d.ts +2 -0
- package/dist/access/index.js +3 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/ingestion/document-processor.d.ts +25 -0
- package/dist/ingestion/document-processor.d.ts.map +1 -0
- package/dist/ingestion/document-processor.js +55 -0
- package/dist/ingestion/document-processor.js.map +1 -0
- package/dist/ingestion/embedding-service.d.ts +13 -0
- package/dist/ingestion/embedding-service.d.ts.map +1 -0
- package/dist/ingestion/embedding-service.js +26 -0
- package/dist/ingestion/embedding-service.js.map +1 -0
- package/dist/ingestion/gmail-adapter.d.ts +19 -0
- package/dist/ingestion/gmail-adapter.d.ts.map +1 -0
- package/dist/ingestion/gmail-adapter.js +52 -0
- package/dist/ingestion/gmail-adapter.js.map +1 -0
- package/dist/ingestion/index.d.ts +6 -0
- package/dist/ingestion/index.js +7 -0
- package/dist/ingestion/storage-adapter.d.ts +16 -0
- package/dist/ingestion/storage-adapter.d.ts.map +1 -0
- package/dist/ingestion/storage-adapter.js +27 -0
- package/dist/ingestion/storage-adapter.js.map +1 -0
- package/dist/ingestion/vector-indexer.d.ts +18 -0
- package/dist/ingestion/vector-indexer.d.ts.map +1 -0
- package/dist/ingestion/vector-indexer.js +33 -0
- package/dist/ingestion/vector-indexer.js.map +1 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +3 -0
- package/dist/query/service.d.ts +28 -0
- package/dist/query/service.d.ts.map +1 -0
- package/dist/query/service.js +66 -0
- package/dist/query/service.js.map +1 -0
- package/dist/retriever/index.d.ts +4 -0
- package/dist/retriever/index.js +4 -0
- package/dist/retriever/interface.d.ts +56 -0
- package/dist/retriever/interface.d.ts.map +1 -0
- package/dist/retriever/interface.js +0 -0
- package/dist/retriever/static-retriever.d.ts +35 -0
- package/dist/retriever/static-retriever.d.ts.map +1 -0
- package/dist/retriever/static-retriever.js +48 -0
- package/dist/retriever/static-retriever.js.map +1 -0
- package/dist/retriever/vector-retriever.d.ts +43 -0
- package/dist/retriever/vector-retriever.d.ts.map +1 -0
- package/dist/retriever/vector-retriever.js +61 -0
- package/dist/retriever/vector-retriever.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Chaman Ventures, SASU
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# @contractspec/lib.knowledge
|
|
2
|
+
|
|
3
|
+
Website: https://contractspec.io/
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Knowledge retrieval and management library for ContractSpec. Provides the runtime implementation for knowledge spaces, including:
|
|
7
|
+
|
|
8
|
+
- **Retriever Interface**: Unified interface for knowledge retrieval (vector, static, hybrid)
|
|
9
|
+
- **Query Service**: RAG-powered question answering over knowledge spaces
|
|
10
|
+
- **Ingestion Pipeline**: Document processing, embedding, and vector indexing
|
|
11
|
+
- **Access Guard**: Policy-based access control for knowledge spaces
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add @contractspec/lib.knowledge
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Retriever
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { createVectorRetriever } from '@contractspec/lib.knowledge/retriever';
|
|
25
|
+
|
|
26
|
+
const retriever = createVectorRetriever({
|
|
27
|
+
embeddings: embeddingProvider,
|
|
28
|
+
vectorStore: vectorStoreProvider,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const results = await retriever.retrieve('How do I reset my password?', {
|
|
32
|
+
spaceKey: 'support-faq',
|
|
33
|
+
topK: 5,
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Static Knowledge
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { createStaticRetriever } from '@contractspec/lib.knowledge/retriever';
|
|
41
|
+
|
|
42
|
+
const retriever = createStaticRetriever({
|
|
43
|
+
'product-canon': 'Product specifications and documentation...',
|
|
44
|
+
'support-faq': 'Frequently asked questions...',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const content = await retriever.getStatic('product-canon');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
This package bridges `@contractspec/lib.contracts` (specs/types) with `@contractspec/lib.ai-agent` (AI SDK integration):
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
@contractspec/lib.contracts (specs/types)
|
|
56
|
+
↓
|
|
57
|
+
@contractspec/lib.knowledge (runtime)
|
|
58
|
+
↓
|
|
59
|
+
@contractspec/lib.ai-agent (AI SDK)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
MIT
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { KnowledgeAccessContext, KnowledgeAccessResult } from "../types.js";
|
|
2
|
+
import { KnowledgeCategory, ResolvedAppConfig, ResolvedKnowledge } from "@contractspec/lib.contracts";
|
|
3
|
+
|
|
4
|
+
//#region src/access/guard.d.ts
|
|
5
|
+
interface KnowledgeAccessGuardOptions {
|
|
6
|
+
disallowWriteCategories?: KnowledgeCategory[];
|
|
7
|
+
requireWorkflowBinding?: boolean;
|
|
8
|
+
requireAgentBinding?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare class KnowledgeAccessGuard {
|
|
11
|
+
private readonly disallowedWrite;
|
|
12
|
+
private readonly requireWorkflowBinding;
|
|
13
|
+
private readonly requireAgentBinding;
|
|
14
|
+
constructor(options?: KnowledgeAccessGuardOptions);
|
|
15
|
+
checkAccess(spaceBinding: ResolvedKnowledge, context: KnowledgeAccessContext, appConfig: ResolvedAppConfig): KnowledgeAccessResult;
|
|
16
|
+
private isSpaceBound;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { KnowledgeAccessGuard, KnowledgeAccessGuardOptions };
|
|
20
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","names":[],"sources":["../../src/access/guard.ts"],"sourcesContent":[],"mappings":";;;;UAOiB,2BAAA;4BACW;EADX,sBAAA,CAAA,EAAA,OAA2B;EAQ/B,mBAAA,CAAA,EAAA,OAAoB;;AAcf,cAdL,oBAAA,CAcK;EACL,iBAAA,eAAA;EACE,iBAAA,sBAAA;EACV,iBAAA,mBAAA;EAAqB,WAAA,CAAA,OAAA,CAAA,EAZH,2BAYG;4BAHR,4BACL,mCACE,oBACV"}
|
|
@@ -0,0 +1,50 @@
|
|
|
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 };
|
|
50
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","names":[],"sources":["../../src/access/guard.ts"],"sourcesContent":["import type {\n ResolvedAppConfig,\n ResolvedKnowledge,\n KnowledgeCategory,\n} from '@contractspec/lib.contracts';\nimport type { KnowledgeAccessContext, KnowledgeAccessResult } from '../types';\n\nexport interface KnowledgeAccessGuardOptions {\n disallowWriteCategories?: KnowledgeCategory[];\n requireWorkflowBinding?: boolean;\n requireAgentBinding?: boolean;\n}\n\nconst DEFAULT_DISALLOWED_WRITE: KnowledgeCategory[] = ['external', 'ephemeral'];\n\nexport class KnowledgeAccessGuard {\n private readonly disallowedWrite: Set<KnowledgeCategory>;\n private readonly requireWorkflowBinding: boolean;\n private readonly requireAgentBinding: boolean;\n\n constructor(options: KnowledgeAccessGuardOptions = {}) {\n this.disallowedWrite = new Set(\n options.disallowWriteCategories ?? DEFAULT_DISALLOWED_WRITE\n );\n this.requireWorkflowBinding = options.requireWorkflowBinding ?? true;\n this.requireAgentBinding = options.requireAgentBinding ?? false;\n }\n\n checkAccess(\n spaceBinding: ResolvedKnowledge,\n context: KnowledgeAccessContext,\n appConfig: ResolvedAppConfig\n ): KnowledgeAccessResult {\n const { binding, space } = spaceBinding;\n\n if (\n binding.required !== false &&\n !this.isSpaceBound(spaceBinding, appConfig)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is not bound in the resolved app config.`,\n };\n }\n\n if (\n context.operation === 'write' &&\n this.disallowedWrite.has(space.meta.category)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is category \"${space.meta.category}\" and is read-only.`,\n };\n }\n\n if (this.requireWorkflowBinding && context.workflowName) {\n const allowedWorkflows = binding.scope?.workflows;\n if (\n allowedWorkflows &&\n !allowedWorkflows.includes(context.workflowName)\n ) {\n return {\n allowed: false,\n reason: `Workflow \"${context.workflowName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (this.requireAgentBinding && context.agentName) {\n const allowedAgents = binding.scope?.agents;\n if (allowedAgents && !allowedAgents.includes(context.agentName)) {\n return {\n allowed: false,\n reason: `Agent \"${context.agentName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (space.meta.category === 'ephemeral') {\n return {\n allowed: true,\n severity: 'warning',\n reason: `Knowledge space \"${space.meta.key}\" is ephemeral; results may be transient.`,\n };\n }\n\n return { allowed: true };\n }\n\n private isSpaceBound(\n resolved: ResolvedKnowledge,\n appConfig: ResolvedAppConfig\n ): boolean {\n return appConfig.knowledge.some(\n (entry) =>\n entry.space.meta.key === resolved.space.meta.key &&\n (resolved.space.meta.version == null ||\n entry.space.meta.version === resolved.space.meta.version)\n );\n }\n}\n"],"mappings":";AAaA,MAAM,2BAAgD,CAAC,YAAY,YAAY;AAE/E,IAAa,uBAAb,MAAkC;CAChC,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAAuC,EAAE,EAAE;AACrD,OAAK,kBAAkB,IAAI,IACzB,QAAQ,2BAA2B,yBACpC;AACD,OAAK,yBAAyB,QAAQ,0BAA0B;AAChE,OAAK,sBAAsB,QAAQ,uBAAuB;;CAG5D,YACE,cACA,SACA,WACuB;EACvB,MAAM,EAAE,SAAS,UAAU;AAE3B,MACE,QAAQ,aAAa,SACrB,CAAC,KAAK,aAAa,cAAc,UAAU,CAE3C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,MACE,QAAQ,cAAc,WACtB,KAAK,gBAAgB,IAAI,MAAM,KAAK,SAAS,CAE7C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI,iBAAiB,MAAM,KAAK,SAAS;GACjF;AAGH,MAAI,KAAK,0BAA0B,QAAQ,cAAc;GACvD,MAAM,mBAAmB,QAAQ,OAAO;AACxC,OACE,oBACA,CAAC,iBAAiB,SAAS,QAAQ,aAAa,CAEhD,QAAO;IACL,SAAS;IACT,QAAQ,aAAa,QAAQ,aAAa,iDAAiD,MAAM,KAAK,IAAI;IAC3G;;AAIL,MAAI,KAAK,uBAAuB,QAAQ,WAAW;GACjD,MAAM,gBAAgB,QAAQ,OAAO;AACrC,OAAI,iBAAiB,CAAC,cAAc,SAAS,QAAQ,UAAU,CAC7D,QAAO;IACL,SAAS;IACT,QAAQ,UAAU,QAAQ,UAAU,iDAAiD,MAAM,KAAK,IAAI;IACrG;;AAIL,MAAI,MAAM,KAAK,aAAa,YAC1B,QAAO;GACL,SAAS;GACT,UAAU;GACV,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,SAAO,EAAE,SAAS,MAAM;;CAG1B,AAAQ,aACN,UACA,WACS;AACT,SAAO,UAAU,UAAU,MACxB,UACC,MAAM,MAAM,KAAK,QAAQ,SAAS,MAAM,KAAK,QAC5C,SAAS,MAAM,KAAK,WAAW,QAC9B,MAAM,MAAM,KAAK,YAAY,SAAS,MAAM,KAAK,SACtD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { KnowledgeAccessContext, KnowledgeAccessResult, RetrievalOptions, RetrievalResult } from "./types.js";
|
|
2
|
+
import { KnowledgeAccessGuard, KnowledgeAccessGuardOptions } from "./access/guard.js";
|
|
3
|
+
import { KnowledgeRetriever, RetrieverConfig } from "./retriever/interface.js";
|
|
4
|
+
import { StaticRetriever, StaticRetrieverConfig, createStaticRetriever } from "./retriever/static-retriever.js";
|
|
5
|
+
import { VectorRetriever, VectorRetrieverConfig, createVectorRetriever } from "./retriever/vector-retriever.js";
|
|
6
|
+
import { KnowledgeAnswer, KnowledgeQueryConfig, KnowledgeQueryService } from "./query/service.js";
|
|
7
|
+
import { DocumentFragment, DocumentProcessor, RawDocument } from "./ingestion/document-processor.js";
|
|
8
|
+
import { EmbeddingService } from "./ingestion/embedding-service.js";
|
|
9
|
+
import { VectorIndexConfig, VectorIndexer } from "./ingestion/vector-indexer.js";
|
|
10
|
+
import { GmailIngestionAdapter } from "./ingestion/gmail-adapter.js";
|
|
11
|
+
import { StorageIngestionAdapter } from "./ingestion/storage-adapter.js";
|
|
12
|
+
export { DocumentFragment, DocumentProcessor, EmbeddingService, GmailIngestionAdapter, KnowledgeAccessContext, KnowledgeAccessGuard, KnowledgeAccessGuardOptions, KnowledgeAccessResult, KnowledgeAnswer, KnowledgeQueryConfig, KnowledgeQueryService, KnowledgeRetriever, RawDocument, RetrievalOptions, RetrievalResult, RetrieverConfig, StaticRetriever, StaticRetrieverConfig, StorageIngestionAdapter, VectorIndexConfig, VectorIndexer, VectorRetriever, VectorRetrieverConfig, createStaticRetriever, createVectorRetriever };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
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 };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/ingestion/document-processor.d.ts
|
|
2
|
+
interface RawDocument {
|
|
3
|
+
id: string;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
data: Uint8Array;
|
|
6
|
+
metadata?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
interface DocumentFragment {
|
|
9
|
+
id: string;
|
|
10
|
+
documentId: string;
|
|
11
|
+
text: string;
|
|
12
|
+
metadata?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
type Extractor = (input: RawDocument) => Promise<DocumentFragment[]>;
|
|
15
|
+
declare class DocumentProcessor {
|
|
16
|
+
private readonly extractors;
|
|
17
|
+
constructor();
|
|
18
|
+
registerExtractor(mimeType: string, extractor: Extractor): void;
|
|
19
|
+
process(document: RawDocument): Promise<DocumentFragment[]>;
|
|
20
|
+
private extractText;
|
|
21
|
+
private extractJson;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { DocumentFragment, DocumentProcessor, RawDocument };
|
|
25
|
+
//# sourceMappingURL=document-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-processor.d.ts","names":[],"sources":["../../src/ingestion/document-processor.ts"],"sourcesContent":[],"mappings":";UAEiB,WAAA;EAAA,EAAA,EAAA,MAAA;EAOA,QAAA,EAAA,MAAA;EAOZ,IAAA,EAXG,UAWM;EAAW,QAAA,CAAA,EAVZ,MAUY,CAAA,MAAA,EAAA,MAAA,CAAA;;AAAgB,UAPxB,gBAAA,CAOwB;EAAO,EAAA,EAAA,MAAA;EAEnC,UAAA,EAAA,MAAA;EAQoC,IAAA,EAAA,MAAA;EAIvB,QAAA,CAAA,EAjBb,MAiBa,CAAA,MAAA,EAAA,MAAA,CAAA;;KAdrB,SAAA,GAcmC,CAAA,KAAA,EAdf,WAce,EAAA,GAdC,OAcD,CAdS,gBAcT,EAAA,CAAA;AAAO,cAZlC,iBAAA,CAYkC;;;iDAJE;oBAIvB,cAAc,QAAQ"}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 };
|
|
55
|
+
//# sourceMappingURL=document-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-processor.js","names":[],"sources":["../../src/ingestion/document-processor.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\n\nexport interface RawDocument {\n id: string;\n mimeType: string;\n data: Uint8Array;\n metadata?: Record<string, string>;\n}\n\nexport interface DocumentFragment {\n id: string;\n documentId: string;\n text: string;\n metadata?: Record<string, string>;\n}\n\ntype Extractor = (input: RawDocument) => Promise<DocumentFragment[]>;\n\nexport class DocumentProcessor {\n private readonly extractors = new Map<string, Extractor>();\n\n constructor() {\n this.registerExtractor('text/plain', this.extractText.bind(this));\n this.registerExtractor('application/json', this.extractJson.bind(this));\n }\n\n registerExtractor(mimeType: string, extractor: Extractor): void {\n this.extractors.set(mimeType.toLowerCase(), extractor);\n }\n\n async process(document: RawDocument): Promise<DocumentFragment[]> {\n const extractor =\n this.extractors.get(document.mimeType.toLowerCase()) ??\n this.extractors.get('*/*');\n if (!extractor) {\n throw new Error(\n `No extractor registered for mime type ${document.mimeType}`\n );\n }\n const fragments = await extractor(document);\n if (fragments.length === 0) {\n return [\n {\n id: `${document.id}:0`,\n documentId: document.id,\n text: '',\n metadata: document.metadata,\n },\n ];\n }\n return fragments;\n }\n\n private async extractText(\n document: RawDocument\n ): Promise<DocumentFragment[]> {\n const text = Buffer.from(document.data).toString('utf-8');\n return [\n {\n id: `${document.id}:0`,\n documentId: document.id,\n text,\n metadata: document.metadata,\n },\n ];\n }\n\n private async extractJson(\n document: RawDocument\n ): Promise<DocumentFragment[]> {\n const text = Buffer.from(document.data).toString('utf-8');\n try {\n const json = JSON.parse(text) as unknown;\n return [\n {\n id: `${document.id}:0`,\n documentId: document.id,\n text: JSON.stringify(json, null, 2),\n metadata: {\n ...document.metadata,\n contentType: 'application/json',\n },\n },\n ];\n } catch {\n return this.extractText(document);\n }\n }\n}\n"],"mappings":";;;AAkBA,IAAa,oBAAb,MAA+B;CAC7B,AAAiB,6BAAa,IAAI,KAAwB;CAE1D,cAAc;AACZ,OAAK,kBAAkB,cAAc,KAAK,YAAY,KAAK,KAAK,CAAC;AACjE,OAAK,kBAAkB,oBAAoB,KAAK,YAAY,KAAK,KAAK,CAAC;;CAGzE,kBAAkB,UAAkB,WAA4B;AAC9D,OAAK,WAAW,IAAI,SAAS,aAAa,EAAE,UAAU;;CAGxD,MAAM,QAAQ,UAAoD;EAChE,MAAM,YACJ,KAAK,WAAW,IAAI,SAAS,SAAS,aAAa,CAAC,IACpD,KAAK,WAAW,IAAI,MAAM;AAC5B,MAAI,CAAC,UACH,OAAM,IAAI,MACR,yCAAyC,SAAS,WACnD;EAEH,MAAM,YAAY,MAAM,UAAU,SAAS;AAC3C,MAAI,UAAU,WAAW,EACvB,QAAO,CACL;GACE,IAAI,GAAG,SAAS,GAAG;GACnB,YAAY,SAAS;GACrB,MAAM;GACN,UAAU,SAAS;GACpB,CACF;AAEH,SAAO;;CAGT,MAAc,YACZ,UAC6B;EAC7B,MAAM,OAAO,OAAO,KAAK,SAAS,KAAK,CAAC,SAAS,QAAQ;AACzD,SAAO,CACL;GACE,IAAI,GAAG,SAAS,GAAG;GACnB,YAAY,SAAS;GACrB;GACA,UAAU,SAAS;GACpB,CACF;;CAGH,MAAc,YACZ,UAC6B;EAC7B,MAAM,OAAO,OAAO,KAAK,SAAS,KAAK,CAAC,SAAS,QAAQ;AACzD,MAAI;GACF,MAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,UAAO,CACL;IACE,IAAI,GAAG,SAAS,GAAG;IACnB,YAAY,SAAS;IACrB,MAAM,KAAK,UAAU,MAAM,MAAM,EAAE;IACnC,UAAU;KACR,GAAG,SAAS;KACZ,aAAa;KACd;IACF,CACF;UACK;AACN,UAAO,KAAK,YAAY,SAAS"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DocumentFragment } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingProvider, EmbeddingResult } from "@contractspec/lib.contracts";
|
|
3
|
+
|
|
4
|
+
//#region src/ingestion/embedding-service.d.ts
|
|
5
|
+
declare class EmbeddingService {
|
|
6
|
+
private readonly provider;
|
|
7
|
+
private readonly batchSize;
|
|
8
|
+
constructor(provider: EmbeddingProvider, batchSize?: number);
|
|
9
|
+
embedFragments(fragments: DocumentFragment[]): Promise<EmbeddingResult[]>;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { EmbeddingService };
|
|
13
|
+
//# sourceMappingURL=embedding-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-service.d.ts","names":[],"sources":["../../src/ingestion/embedding-service.ts"],"sourcesContent":[],"mappings":";;;;cAOa,gBAAA;;EAAA,iBAAA,SAAgB;EAIL,WAAA,CAAA,QAAA,EAAA,iBAAA,EAAA,SAAA,CAAA,EAAA,MAAA;EAMT,cAAA,CAAA,SAAA,EAAA,gBAAA,EAAA,CAAA,EACV,OADU,CACF,eADE,EAAA,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 };
|
|
26
|
+
//# sourceMappingURL=embedding-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-service.js","names":[],"sources":["../../src/ingestion/embedding-service.ts"],"sourcesContent":["import type {\n EmbeddingDocument,\n EmbeddingProvider,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport class EmbeddingService {\n private readonly provider: EmbeddingProvider;\n private readonly batchSize: number;\n\n constructor(provider: EmbeddingProvider, batchSize = 16) {\n this.provider = provider;\n this.batchSize = batchSize;\n }\n\n async embedFragments(\n fragments: DocumentFragment[]\n ): Promise<EmbeddingResult[]> {\n const results: EmbeddingResult[] = [];\n for (let i = 0; i < fragments.length; i += this.batchSize) {\n const slice = fragments.slice(i, i + this.batchSize);\n const documents: EmbeddingDocument[] = slice.map((fragment) => ({\n id: fragment.id,\n text: fragment.text,\n metadata: fragment.metadata,\n }));\n const embeddings = await this.provider.embedDocuments(documents);\n results.push(...embeddings);\n }\n return results;\n }\n}\n"],"mappings":";AAOA,IAAa,mBAAb,MAA8B;CAC5B,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA6B,YAAY,IAAI;AACvD,OAAK,WAAW;AAChB,OAAK,YAAY;;CAGnB,MAAM,eACJ,WAC4B;EAC5B,MAAM,UAA6B,EAAE;AACrC,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,KAAK,WAAW;GAEzD,MAAM,YADQ,UAAU,MAAM,GAAG,IAAI,KAAK,UAAU,CACP,KAAK,cAAc;IAC9D,IAAI,SAAS;IACb,MAAM,SAAS;IACf,UAAU,SAAS;IACpB,EAAE;GACH,MAAM,aAAa,MAAM,KAAK,SAAS,eAAe,UAAU;AAChE,WAAQ,KAAK,GAAG,WAAW;;AAE7B,SAAO"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DocumentProcessor } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingService } from "./embedding-service.js";
|
|
3
|
+
import { VectorIndexer } from "./vector-indexer.js";
|
|
4
|
+
import { EmailInboundProvider, EmailThread } from "@contractspec/lib.contracts";
|
|
5
|
+
|
|
6
|
+
//#region src/ingestion/gmail-adapter.d.ts
|
|
7
|
+
declare class GmailIngestionAdapter {
|
|
8
|
+
private readonly gmail;
|
|
9
|
+
private readonly processor;
|
|
10
|
+
private readonly embeddings;
|
|
11
|
+
private readonly indexer;
|
|
12
|
+
constructor(gmail: EmailInboundProvider, processor: DocumentProcessor, embeddings: EmbeddingService, indexer: VectorIndexer);
|
|
13
|
+
syncThreads(query?: Parameters<EmailInboundProvider['listThreads']>[0]): Promise<void>;
|
|
14
|
+
ingestThread(thread: EmailThread): Promise<void>;
|
|
15
|
+
private toRawDocument;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { GmailIngestionAdapter };
|
|
19
|
+
//# sourceMappingURL=gmail-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail-adapter.d.ts","names":[],"sources":["../../src/ingestion/gmail-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;cAQa,qBAAA;;EAAA,iBAAA,SAAqB;EAEN,iBAAA,UAAA;EACI,iBAAA,OAAA;EACC,WAAA,CAAA,KAAA,EAFL,oBAEK,EAAA,SAAA,EADD,iBACC,EAAA,UAAA,EAAA,gBAAA,EAAA,OAAA,EACH,aADG;EACH,WAAA,CAAA,KAAA,CAAA,EAIlB,UAJkB,CAIP,oBAJO,CAAA,aAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAIgC,OAJhC,CAAA,IAAA,CAAA;EAIP,YAAA,CAAA,MAAA,EAQM,WARN,CAAA,EAQiB,OARjB,CAAA,IAAA,CAAA;EAAX,QAAA,aAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { GmailIngestionAdapter };
|
|
52
|
+
//# sourceMappingURL=gmail-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail-adapter.js","names":[],"sources":["../../src/ingestion/gmail-adapter.ts"],"sourcesContent":["import type {\n EmailInboundProvider,\n EmailThread,\n} from '@contractspec/lib.contracts';\nimport type { DocumentProcessor, RawDocument } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class GmailIngestionAdapter {\n constructor(\n private readonly gmail: EmailInboundProvider,\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async syncThreads(\n query?: Parameters<EmailInboundProvider['listThreads']>[0]\n ) {\n const threads = await this.gmail.listThreads(query);\n for (const thread of threads) {\n await this.ingestThread(thread);\n }\n }\n\n async ingestThread(thread: EmailThread) {\n const document = this.toRawDocument(thread);\n const fragments = await this.processor.process(document);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n\n private toRawDocument(thread: EmailThread): RawDocument {\n const content = composeThreadText(thread);\n return {\n id: thread.id,\n mimeType: 'text/plain',\n data: Buffer.from(content, 'utf-8'),\n metadata: {\n subject: thread.subject ?? '',\n participants: thread.participants.map((p) => p.email).join(', '),\n updatedAt: thread.updatedAt.toISOString(),\n },\n };\n }\n}\n\nfunction composeThreadText(thread: EmailThread): string {\n const header = [\n `Subject: ${thread.subject ?? ''}`,\n `Snippet: ${thread.snippet ?? ''}`,\n ];\n const messageTexts = thread.messages.map((message) => {\n const parts = [\n `From: ${formatAddress(message.from)}`,\n `To: ${message.to.map(formatAddress).join(', ')}`,\n ];\n if (message.sentAt) {\n parts.push(`Date: ${message.sentAt.toISOString()}`);\n }\n const body = message.textBody ?? stripHtml(message.htmlBody ?? '');\n return `${parts.join('\\n')}\\n\\n${body ?? ''}`;\n });\n return [...header, ...messageTexts].join('\\n\\n---\\n\\n');\n}\n\nfunction formatAddress(address: { email: string; name?: string }): string {\n return address.name ? `${address.name} <${address.email}>` : address.email;\n}\n\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]+>/g, ' ');\n}\n"],"mappings":";AAQA,IAAa,wBAAb,MAAmC;CACjC,YACE,AAAiB,OACjB,AAAiB,WACjB,AAAiB,YACjB,AAAiB,SACjB;EAJiB;EACA;EACA;EACA;;CAGnB,MAAM,YACJ,OACA;EACA,MAAM,UAAU,MAAM,KAAK,MAAM,YAAY,MAAM;AACnD,OAAK,MAAM,UAAU,QACnB,OAAM,KAAK,aAAa,OAAO;;CAInC,MAAM,aAAa,QAAqB;EACtC,MAAM,WAAW,KAAK,cAAc,OAAO;EAC3C,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,SAAS;EACxD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW;;CAGlD,AAAQ,cAAc,QAAkC;EACtD,MAAM,UAAU,kBAAkB,OAAO;AACzC,SAAO;GACL,IAAI,OAAO;GACX,UAAU;GACV,MAAM,OAAO,KAAK,SAAS,QAAQ;GACnC,UAAU;IACR,SAAS,OAAO,WAAW;IAC3B,cAAc,OAAO,aAAa,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK;IAChE,WAAW,OAAO,UAAU,aAAa;IAC1C;GACF;;;AAIL,SAAS,kBAAkB,QAA6B;CACtD,MAAM,SAAS,CACb,YAAY,OAAO,WAAW,MAC9B,YAAY,OAAO,WAAW,KAC/B;CACD,MAAM,eAAe,OAAO,SAAS,KAAK,YAAY;EACpD,MAAM,QAAQ,CACZ,SAAS,cAAc,QAAQ,KAAK,IACpC,OAAO,QAAQ,GAAG,IAAI,cAAc,CAAC,KAAK,KAAK,GAChD;AACD,MAAI,QAAQ,OACV,OAAM,KAAK,SAAS,QAAQ,OAAO,aAAa,GAAG;EAErD,MAAM,OAAO,QAAQ,YAAY,UAAU,QAAQ,YAAY,GAAG;AAClE,SAAO,GAAG,MAAM,KAAK,KAAK,CAAC,MAAM,QAAQ;GACzC;AACF,QAAO,CAAC,GAAG,QAAQ,GAAG,aAAa,CAAC,KAAK,cAAc;;AAGzD,SAAS,cAAc,SAAmD;AACxE,QAAO,QAAQ,OAAO,GAAG,QAAQ,KAAK,IAAI,QAAQ,MAAM,KAAK,QAAQ;;AAGvE,SAAS,UAAU,MAAsB;AACvC,QAAO,KAAK,QAAQ,YAAY,IAAI"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DocumentFragment, DocumentProcessor, RawDocument } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingService } from "./embedding-service.js";
|
|
3
|
+
import { VectorIndexConfig, VectorIndexer } from "./vector-indexer.js";
|
|
4
|
+
import { GmailIngestionAdapter } from "./gmail-adapter.js";
|
|
5
|
+
import { StorageIngestionAdapter } from "./storage-adapter.js";
|
|
6
|
+
export { DocumentFragment, DocumentProcessor, EmbeddingService, GmailIngestionAdapter, RawDocument, StorageIngestionAdapter, VectorIndexConfig, VectorIndexer };
|
|
@@ -0,0 +1,7 @@
|
|
|
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 };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DocumentProcessor } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingService } from "./embedding-service.js";
|
|
3
|
+
import { VectorIndexer } from "./vector-indexer.js";
|
|
4
|
+
import { GetObjectResult } from "@contractspec/lib.contracts";
|
|
5
|
+
|
|
6
|
+
//#region src/ingestion/storage-adapter.d.ts
|
|
7
|
+
declare class StorageIngestionAdapter {
|
|
8
|
+
private readonly processor;
|
|
9
|
+
private readonly embeddings;
|
|
10
|
+
private readonly indexer;
|
|
11
|
+
constructor(processor: DocumentProcessor, embeddings: EmbeddingService, indexer: VectorIndexer);
|
|
12
|
+
ingestObject(object: GetObjectResult): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { StorageIngestionAdapter };
|
|
16
|
+
//# sourceMappingURL=storage-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-adapter.d.ts","names":[],"sources":["../../src/ingestion/storage-adapter.ts"],"sourcesContent":[],"mappings":";;;;;;cAKa,uBAAA;;EAAA,iBAAA,UAAuB;EAEJ,iBAAA,OAAA;EACC,WAAA,CAAA,SAAA,EADD,iBACC,EAAA,UAAA,EAAA,gBAAA,EAAA,OAAA,EACH,aADG;EACH,YAAA,CAAA,MAAA,EAGD,eAHC,CAAA,EAGiB,OAHjB,CAAA,IAAA,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
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 };
|
|
27
|
+
//# sourceMappingURL=storage-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-adapter.js","names":[],"sources":["../../src/ingestion/storage-adapter.ts"],"sourcesContent":["import type { GetObjectResult } from '@contractspec/lib.contracts';\nimport type { DocumentProcessor } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class StorageIngestionAdapter {\n constructor(\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async ingestObject(object: GetObjectResult): Promise<void> {\n if (!('data' in object) || !object.data) {\n throw new Error('Storage ingestion requires object data');\n }\n\n const raw = {\n id: object.key,\n mimeType: object.contentType ?? 'application/octet-stream',\n data: object.data,\n metadata: {\n bucket: object.bucket,\n checksum: object.checksum ?? '',\n },\n };\n\n const fragments = await this.processor.process(raw);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n}\n"],"mappings":";AAKA,IAAa,0BAAb,MAAqC;CACnC,YACE,AAAiB,WACjB,AAAiB,YACjB,AAAiB,SACjB;EAHiB;EACA;EACA;;CAGnB,MAAM,aAAa,QAAwC;AACzD,MAAI,EAAE,UAAU,WAAW,CAAC,OAAO,KACjC,OAAM,IAAI,MAAM,yCAAyC;EAG3D,MAAM,MAAM;GACV,IAAI,OAAO;GACX,UAAU,OAAO,eAAe;GAChC,MAAM,OAAO;GACb,UAAU;IACR,QAAQ,OAAO;IACf,UAAU,OAAO,YAAY;IAC9B;GACF;EAED,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,IAAI;EACnD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DocumentFragment } from "./document-processor.js";
|
|
2
|
+
import { EmbeddingResult, VectorStoreProvider } from "@contractspec/lib.contracts";
|
|
3
|
+
|
|
4
|
+
//#region src/ingestion/vector-indexer.d.ts
|
|
5
|
+
interface VectorIndexConfig {
|
|
6
|
+
collection: string;
|
|
7
|
+
namespace?: string;
|
|
8
|
+
metadata?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
declare class VectorIndexer {
|
|
11
|
+
private readonly provider;
|
|
12
|
+
private readonly config;
|
|
13
|
+
constructor(provider: VectorStoreProvider, config: VectorIndexConfig);
|
|
14
|
+
upsert(fragments: DocumentFragment[], embeddings: EmbeddingResult[]): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { VectorIndexConfig, VectorIndexer };
|
|
18
|
+
//# sourceMappingURL=vector-indexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-indexer.d.ts","names":[],"sources":["../../src/ingestion/vector-indexer.ts"],"sourcesContent":[],"mappings":";;;;UAOiB,iBAAA;;EAAA,SAAA,CAAA,EAAA,MAAA;EAMJ,QAAA,CAAA,EAHA,MAGa,CAAA,MAAA,EAAA,MAAA,CAAA;;AAI2B,cAJxC,aAAA,CAIwC;EAMtC,iBAAA,QAAA;EACC,iBAAA,MAAA;EACX,WAAA,CAAA,QAAA,EARmB,mBAQnB,EAAA,MAAA,EARgD,iBAQhD;EAAO,MAAA,CAAA,SAAA,EAFG,gBAEH,EAAA,EAAA,UAAA,EADI,eACJ,EAAA,CAAA,EAAP,OAAO,CAAA,IAAA,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 };
|
|
33
|
+
//# sourceMappingURL=vector-indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-indexer.js","names":[],"sources":["../../src/ingestion/vector-indexer.ts"],"sourcesContent":["import type {\n VectorStoreProvider,\n VectorUpsertRequest,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport interface VectorIndexConfig {\n collection: string;\n namespace?: string;\n metadata?: Record<string, string>;\n}\n\nexport class VectorIndexer {\n private readonly provider: VectorStoreProvider;\n private readonly config: VectorIndexConfig;\n\n constructor(provider: VectorStoreProvider, config: VectorIndexConfig) {\n this.provider = provider;\n this.config = config;\n }\n\n async upsert(\n fragments: DocumentFragment[],\n embeddings: EmbeddingResult[]\n ): Promise<void> {\n const documents = embeddings.map((embedding) => {\n const fragment = fragments.find((f) => f.id === embedding.id);\n return {\n id: embedding.id,\n vector: embedding.vector,\n payload: {\n ...this.config.metadata,\n ...(fragment?.metadata ?? {}),\n documentId: fragment?.documentId,\n },\n namespace: this.config.namespace,\n };\n });\n\n const request: VectorUpsertRequest = {\n collection: this.config.collection,\n documents,\n };\n\n await this.provider.upsert(request);\n }\n}\n"],"mappings":";AAaA,IAAa,gBAAb,MAA2B;CACzB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA+B,QAA2B;AACpE,OAAK,WAAW;AAChB,OAAK,SAAS;;CAGhB,MAAM,OACJ,WACA,YACe;EACf,MAAM,YAAY,WAAW,KAAK,cAAc;GAC9C,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7D,UAAO;IACL,IAAI,UAAU;IACd,QAAQ,UAAU;IAClB,SAAS;KACP,GAAG,KAAK,OAAO;KACf,GAAI,UAAU,YAAY,EAAE;KAC5B,YAAY,UAAU;KACvB;IACD,WAAW,KAAK,OAAO;IACxB;IACD;EAEF,MAAM,UAA+B;GACnC,YAAY,KAAK,OAAO;GACxB;GACD;AAED,QAAM,KAAK,SAAS,OAAO,QAAQ"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EmbeddingProvider, LLMProvider, LLMResponse, VectorSearchResult, VectorStoreProvider } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/query/service.d.ts
|
|
4
|
+
interface KnowledgeQueryConfig {
|
|
5
|
+
collection: string;
|
|
6
|
+
namespace?: string;
|
|
7
|
+
topK?: number;
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
}
|
|
10
|
+
interface KnowledgeAnswer {
|
|
11
|
+
answer: string;
|
|
12
|
+
references: (VectorSearchResult & {
|
|
13
|
+
text?: string;
|
|
14
|
+
})[];
|
|
15
|
+
usage?: LLMResponse['usage'];
|
|
16
|
+
}
|
|
17
|
+
declare class KnowledgeQueryService {
|
|
18
|
+
private readonly embeddings;
|
|
19
|
+
private readonly vectorStore;
|
|
20
|
+
private readonly llm;
|
|
21
|
+
private readonly config;
|
|
22
|
+
constructor(embeddings: EmbeddingProvider, vectorStore: VectorStoreProvider, llm: LLMProvider, config: KnowledgeQueryConfig);
|
|
23
|
+
query(question: string): Promise<KnowledgeAnswer>;
|
|
24
|
+
private buildMessages;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { KnowledgeAnswer, KnowledgeQueryConfig, KnowledgeQueryService };
|
|
28
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","names":[],"sources":["../../src/query/service.ts"],"sourcesContent":[],"mappings":";;;UASiB,oBAAA;;EAAA,SAAA,CAAA,EAAA,MAAA;EAOA,IAAA,CAAA,EAAA,MAAA;EAQJ,YAAA,CAAA,EAAA,MAAA;;AAQI,UAhBA,eAAA,CAgBA;EACR,MAAA,EAAA,MAAA;EACG,UAAA,EAAA,CAhBG,kBAgBH,GAAA;IAQ6B,IAAA,CAAA,EAAA,MAAA;EAAR,CAAA,CAAA,EAAA;EAAO,KAAA,CAAA,EArB9B,WAqB8B,CAAA,OAAA,CAAA;;cAlB3B,qBAAA;;;;;0BAOG,gCACC,0BACR,qBACG;2BAQqB,QAAQ"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { KnowledgeQueryService };
|
|
66
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../src/query/service.ts"],"sourcesContent":["import type {\n EmbeddingProvider,\n VectorStoreProvider,\n VectorSearchResult,\n LLMProvider,\n LLMMessage,\n LLMResponse,\n} from '@contractspec/lib.contracts';\n\nexport interface KnowledgeQueryConfig {\n collection: string;\n namespace?: string;\n topK?: number;\n systemPrompt?: string;\n}\n\nexport interface KnowledgeAnswer {\n answer: string;\n references: (VectorSearchResult & {\n text?: string;\n })[];\n usage?: LLMResponse['usage'];\n}\n\nexport class KnowledgeQueryService {\n private readonly embeddings: EmbeddingProvider;\n private readonly vectorStore: VectorStoreProvider;\n private readonly llm: LLMProvider;\n private readonly config: KnowledgeQueryConfig;\n\n constructor(\n embeddings: EmbeddingProvider,\n vectorStore: VectorStoreProvider,\n llm: LLMProvider,\n config: KnowledgeQueryConfig\n ) {\n this.embeddings = embeddings;\n this.vectorStore = vectorStore;\n this.llm = llm;\n this.config = config;\n }\n\n async query(question: string): Promise<KnowledgeAnswer> {\n const embedding = await this.embeddings.embedQuery(question);\n const results = await this.vectorStore.search({\n collection: this.config.collection,\n vector: embedding.vector,\n topK: this.config.topK ?? 5,\n namespace: this.config.namespace,\n filter: undefined,\n });\n const context = buildContext(results);\n const messages = this.buildMessages(question, context);\n const response = await this.llm.chat(messages);\n return {\n answer: response.message.content\n .map((part) => ('text' in part ? part.text : ''))\n .join(''),\n references: results.map((result) => ({\n ...result,\n text: extractText(result),\n })),\n usage: response.usage,\n };\n }\n\n private buildMessages(question: string, context: string): LLMMessage[] {\n const systemPrompt =\n this.config.systemPrompt ??\n 'You are a knowledge assistant that answers questions using the provided context. Cite relevant sources if possible.';\n return [\n {\n role: 'system',\n content: [{ type: 'text', text: systemPrompt }],\n },\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `Question:\\n${question}\\n\\nContext:\\n${context}`,\n },\n ],\n },\n ];\n }\n}\n\nfunction buildContext(results: VectorSearchResult[]): string {\n if (results.length === 0) {\n return 'No relevant documents found.';\n }\n return results\n .map((result, index) => {\n const text = extractText(result);\n return `Source ${index + 1} (score: ${result.score.toFixed(3)}):\\n${text}`;\n })\n .join('\\n\\n');\n}\n\nfunction extractText(result: VectorSearchResult): string {\n const payload = result.payload ?? {};\n if (typeof payload.text === 'string') return payload.text;\n if (typeof payload.content === 'string') return payload.content;\n return JSON.stringify(payload);\n}\n"],"mappings":";AAwBA,IAAa,wBAAb,MAAmC;CACjC,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YACE,YACA,aACA,KACA,QACA;AACA,OAAK,aAAa;AAClB,OAAK,cAAc;AACnB,OAAK,MAAM;AACX,OAAK,SAAS;;CAGhB,MAAM,MAAM,UAA4C;EACtD,MAAM,YAAY,MAAM,KAAK,WAAW,WAAW,SAAS;EAC5D,MAAM,UAAU,MAAM,KAAK,YAAY,OAAO;GAC5C,YAAY,KAAK,OAAO;GACxB,QAAQ,UAAU;GAClB,MAAM,KAAK,OAAO,QAAQ;GAC1B,WAAW,KAAK,OAAO;GACvB,QAAQ;GACT,CAAC;EACF,MAAM,UAAU,aAAa,QAAQ;EACrC,MAAM,WAAW,KAAK,cAAc,UAAU,QAAQ;EACtD,MAAM,WAAW,MAAM,KAAK,IAAI,KAAK,SAAS;AAC9C,SAAO;GACL,QAAQ,SAAS,QAAQ,QACtB,KAAK,SAAU,UAAU,OAAO,KAAK,OAAO,GAAI,CAChD,KAAK,GAAG;GACX,YAAY,QAAQ,KAAK,YAAY;IACnC,GAAG;IACH,MAAM,YAAY,OAAO;IAC1B,EAAE;GACH,OAAO,SAAS;GACjB;;CAGH,AAAQ,cAAc,UAAkB,SAA+B;AAIrE,SAAO,CACL;GACE,MAAM;GACN,SAAS,CAAC;IAAE,MAAM;IAAQ,MAL5B,KAAK,OAAO,gBACZ;IAIgD,CAAC;GAChD,EACD;GACE,MAAM;GACN,SAAS,CACP;IACE,MAAM;IACN,MAAM,cAAc,SAAS,gBAAgB;IAC9C,CACF;GACF,CACF;;;AAIL,SAAS,aAAa,SAAuC;AAC3D,KAAI,QAAQ,WAAW,EACrB,QAAO;AAET,QAAO,QACJ,KAAK,QAAQ,UAAU;EACtB,MAAM,OAAO,YAAY,OAAO;AAChC,SAAO,UAAU,QAAQ,EAAE,WAAW,OAAO,MAAM,QAAQ,EAAE,CAAC,MAAM;GACpE,CACD,KAAK,OAAO;;AAGjB,SAAS,YAAY,QAAoC;CACvD,MAAM,UAAU,OAAO,WAAW,EAAE;AACpC,KAAI,OAAO,QAAQ,SAAS,SAAU,QAAO,QAAQ;AACrD,KAAI,OAAO,QAAQ,YAAY,SAAU,QAAO,QAAQ;AACxD,QAAO,KAAK,UAAU,QAAQ"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { KnowledgeRetriever, RetrieverConfig } from "./interface.js";
|
|
2
|
+
import { StaticRetriever, StaticRetrieverConfig, createStaticRetriever } from "./static-retriever.js";
|
|
3
|
+
import { VectorRetriever, VectorRetrieverConfig, createVectorRetriever } from "./vector-retriever.js";
|
|
4
|
+
export { KnowledgeRetriever, RetrieverConfig, StaticRetriever, StaticRetrieverConfig, VectorRetriever, VectorRetrieverConfig, createStaticRetriever, createVectorRetriever };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { RetrievalOptions, RetrievalResult } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/retriever/interface.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Unified interface for knowledge retrieval.
|
|
7
|
+
*
|
|
8
|
+
* Implementations can use vector stores, static content, or hybrid approaches.
|
|
9
|
+
* This interface is consumed by @contractspec/lib.ai-agent for both static injection
|
|
10
|
+
* and dynamic RAG tool queries.
|
|
11
|
+
*/
|
|
12
|
+
interface KnowledgeRetriever {
|
|
13
|
+
/**
|
|
14
|
+
* Retrieve relevant content for a query using semantic search.
|
|
15
|
+
*
|
|
16
|
+
* @param query - The search query or question
|
|
17
|
+
* @param options - Retrieval options including space key and filters
|
|
18
|
+
* @returns Array of retrieval results sorted by relevance
|
|
19
|
+
*/
|
|
20
|
+
retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Get static content by space key (for required knowledge injection).
|
|
23
|
+
*
|
|
24
|
+
* Used for injecting required knowledge into agent system prompts
|
|
25
|
+
* without performing semantic search.
|
|
26
|
+
*
|
|
27
|
+
* @param spaceKey - The knowledge space key
|
|
28
|
+
* @returns The static content or null if not available
|
|
29
|
+
*/
|
|
30
|
+
getStatic(spaceKey: string): Promise<string | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Check if this retriever supports a given knowledge space.
|
|
33
|
+
*
|
|
34
|
+
* @param spaceKey - The knowledge space key to check
|
|
35
|
+
* @returns True if the space is supported
|
|
36
|
+
*/
|
|
37
|
+
supportsSpace(spaceKey: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* List all supported knowledge space keys.
|
|
40
|
+
*
|
|
41
|
+
* @returns Array of supported space keys
|
|
42
|
+
*/
|
|
43
|
+
listSpaces(): string[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Configuration for creating a retriever.
|
|
47
|
+
*/
|
|
48
|
+
interface RetrieverConfig {
|
|
49
|
+
/** Default number of results to return */
|
|
50
|
+
defaultTopK?: number;
|
|
51
|
+
/** Default minimum score threshold */
|
|
52
|
+
defaultMinScore?: number;
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { KnowledgeRetriever, RetrieverConfig };
|
|
56
|
+
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","names":[],"sources":["../../src/retriever/interface.ts"],"sourcesContent":[],"mappings":";;;;;;AASA;;;;;AAsBsC,UAtBrB,kBAAA,CAsBqB;EAqBrB;;;;;;;mCAjCJ,mBACR,QAAQ;;;;;;;;;;+BAWkB;;;;;;;;;;;;;;;;;;UAqBd,eAAA"}
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RetrievalOptions, RetrievalResult } from "../types.js";
|
|
2
|
+
import { KnowledgeRetriever, RetrieverConfig } from "./interface.js";
|
|
3
|
+
|
|
4
|
+
//#region src/retriever/static-retriever.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration for the static retriever.
|
|
8
|
+
*/
|
|
9
|
+
interface StaticRetrieverConfig extends RetrieverConfig {
|
|
10
|
+
/** Map of space key to static content */
|
|
11
|
+
content: Map<string, string> | Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A simple in-memory retriever for static knowledge content.
|
|
15
|
+
*
|
|
16
|
+
* Useful for:
|
|
17
|
+
* - Required knowledge that doesn't need semantic search
|
|
18
|
+
* - Testing and development
|
|
19
|
+
* - Small knowledge bases that fit in memory
|
|
20
|
+
*/
|
|
21
|
+
declare class StaticRetriever implements KnowledgeRetriever {
|
|
22
|
+
private readonly content;
|
|
23
|
+
constructor(config: StaticRetrieverConfig);
|
|
24
|
+
retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
|
|
25
|
+
getStatic(spaceKey: string): Promise<string | null>;
|
|
26
|
+
supportsSpace(spaceKey: string): boolean;
|
|
27
|
+
listSpaces(): string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a static retriever from a content map.
|
|
31
|
+
*/
|
|
32
|
+
declare function createStaticRetriever(content: Record<string, string> | Map<string, string>): StaticRetriever;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { StaticRetriever, StaticRetrieverConfig, createStaticRetriever };
|
|
35
|
+
//# sourceMappingURL=static-retriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-retriever.d.ts","names":[],"sources":["../../src/retriever/static-retriever.ts"],"sourcesContent":[],"mappings":";;;;;;;AAMA;AAEW,UAFM,qBAAA,SAA8B,eAEpC,CAAA;EAAsB;EAFc,OAAA,EAEpC,GAFoC,CAAA,MAAA,EAAA,MAAA,CAAA,GAEd,MAFc,CAAA,MAAA,EAAA,MAAA,CAAA;;AAa/C;;;;;;;;AAoDgB,cApDH,eAAA,YAA2B,kBAoDH,CAAA;EAC1B,iBAAA,OAAA;EAAyB,WAAA,CAAA,MAAA,EAlDd,qBAkDc;EACjC,QAAA,CAAA,KAAA,EAAA,MAAA,EAAA,OAAA,EA1CU,gBA0CV,CAAA,EAzCE,OAyCF,CAzCU,eAyCV,EAAA,CAAA;EAAe,SAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EAlBmB,OAkBnB,CAAA,MAAA,GAAA,IAAA,CAAA;;;;;;;iBAFF,qBAAA,UACL,yBAAyB,sBACjC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
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 };
|
|
48
|
+
//# sourceMappingURL=static-retriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-retriever.js","names":[],"sources":["../../src/retriever/static-retriever.ts"],"sourcesContent":["import type { RetrievalResult, RetrievalOptions } from '../types';\nimport type { KnowledgeRetriever, RetrieverConfig } from './interface';\n\n/**\n * Configuration for the static retriever.\n */\nexport interface StaticRetrieverConfig extends RetrieverConfig {\n /** Map of space key to static content */\n content: Map<string, string> | Record<string, string>;\n}\n\n/**\n * A simple in-memory retriever for static knowledge content.\n *\n * Useful for:\n * - Required knowledge that doesn't need semantic search\n * - Testing and development\n * - Small knowledge bases that fit in memory\n */\nexport class StaticRetriever implements KnowledgeRetriever {\n private readonly content: Map<string, string>;\n\n constructor(config: StaticRetrieverConfig) {\n this.content =\n config.content instanceof Map\n ? config.content\n : new Map(Object.entries(config.content));\n }\n\n async retrieve(\n query: string,\n options: RetrievalOptions\n ): Promise<RetrievalResult[]> {\n const content = this.content.get(options.spaceKey);\n if (!content) return [];\n\n // Simple keyword matching for static retriever\n const queryLower = query.toLowerCase();\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const results: RetrievalResult[] = [];\n for (const line of lines) {\n if (line.toLowerCase().includes(queryLower)) {\n results.push({\n content: line,\n source: options.spaceKey,\n score: 1.0,\n metadata: { type: 'static' },\n });\n }\n }\n\n return results.slice(0, options.topK ?? 5);\n }\n\n async getStatic(spaceKey: string): Promise<string | null> {\n return this.content.get(spaceKey) ?? null;\n }\n\n supportsSpace(spaceKey: string): boolean {\n return this.content.has(spaceKey);\n }\n\n listSpaces(): string[] {\n return [...this.content.keys()];\n }\n}\n\n/**\n * Create a static retriever from a content map.\n */\nexport function createStaticRetriever(\n content: Record<string, string> | Map<string, string>\n): StaticRetriever {\n return new StaticRetriever({ content });\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAa,kBAAb,MAA2D;CACzD,AAAiB;CAEjB,YAAY,QAA+B;AACzC,OAAK,UACH,OAAO,mBAAmB,MACtB,OAAO,UACP,IAAI,IAAI,OAAO,QAAQ,OAAO,QAAQ,CAAC;;CAG/C,MAAM,SACJ,OACA,SAC4B;EAC5B,MAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,SAAS;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE;EAGvB,MAAM,aAAa,MAAM,aAAa;EACtC,MAAM,QAAQ,QAAQ,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,MAAM,CAAC;EAE/D,MAAM,UAA6B,EAAE;AACrC,OAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,aAAa,CAAC,SAAS,WAAW,CACzC,SAAQ,KAAK;GACX,SAAS;GACT,QAAQ,QAAQ;GAChB,OAAO;GACP,UAAU,EAAE,MAAM,UAAU;GAC7B,CAAC;AAIN,SAAO,QAAQ,MAAM,GAAG,QAAQ,QAAQ,EAAE;;CAG5C,MAAM,UAAU,UAA0C;AACxD,SAAO,KAAK,QAAQ,IAAI,SAAS,IAAI;;CAGvC,cAAc,UAA2B;AACvC,SAAO,KAAK,QAAQ,IAAI,SAAS;;CAGnC,aAAuB;AACrB,SAAO,CAAC,GAAG,KAAK,QAAQ,MAAM,CAAC;;;;;;AAOnC,SAAgB,sBACd,SACiB;AACjB,QAAO,IAAI,gBAAgB,EAAE,SAAS,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { RetrievalOptions, RetrievalResult } from "../types.js";
|
|
2
|
+
import { KnowledgeRetriever, RetrieverConfig } from "./interface.js";
|
|
3
|
+
import { EmbeddingProvider, VectorStoreProvider } from "@contractspec/lib.contracts";
|
|
4
|
+
|
|
5
|
+
//#region src/retriever/vector-retriever.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for the vector retriever.
|
|
9
|
+
*/
|
|
10
|
+
interface VectorRetrieverConfig extends RetrieverConfig {
|
|
11
|
+
/** Embedding provider for query vectorization */
|
|
12
|
+
embeddings: EmbeddingProvider;
|
|
13
|
+
/** Vector store provider for similarity search */
|
|
14
|
+
vectorStore: VectorStoreProvider;
|
|
15
|
+
/** Map of space key to collection name */
|
|
16
|
+
spaceCollections: Map<string, string> | Record<string, string>;
|
|
17
|
+
/** Optional static content for getStatic() calls */
|
|
18
|
+
staticContent?: Map<string, string> | Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A retriever that uses vector similarity search.
|
|
22
|
+
*
|
|
23
|
+
* Uses embedding provider to vectorize queries and vector store
|
|
24
|
+
* provider to perform similarity search.
|
|
25
|
+
*/
|
|
26
|
+
declare class VectorRetriever implements KnowledgeRetriever {
|
|
27
|
+
private readonly config;
|
|
28
|
+
private readonly spaceCollections;
|
|
29
|
+
private readonly staticContent;
|
|
30
|
+
constructor(config: VectorRetrieverConfig);
|
|
31
|
+
retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
|
|
32
|
+
getStatic(spaceKey: string): Promise<string | null>;
|
|
33
|
+
supportsSpace(spaceKey: string): boolean;
|
|
34
|
+
listSpaces(): string[];
|
|
35
|
+
private extractContent;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a vector retriever from configuration.
|
|
39
|
+
*/
|
|
40
|
+
declare function createVectorRetriever(config: VectorRetrieverConfig): VectorRetriever;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { VectorRetriever, VectorRetrieverConfig, createVectorRetriever };
|
|
43
|
+
//# sourceMappingURL=vector-retriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-retriever.d.ts","names":[],"sources":["../../src/retriever/vector-retriever.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAUA;AAEc,UAFG,qBAAA,SAA8B,eAEjC,CAAA;EAEC;EAEK,UAAA,EAJN,iBAIM;EAAsB;EAExB,WAAA,EAJH,mBAIG;EAAsB;EARO,gBAAA,EAM3B,GAN2B,CAAA,MAAA,EAAA,MAAA,CAAA,GAML,MANK,CAAA,MAAA,EAAA,MAAA,CAAA;EAAe;EAiBjD,aAAA,CAAA,EATK,GASW,CAAA,MAAA,EAAA,MAAA,CAAA,GATW,MASX,CAAA,MAAA,EAAA,MAAA,CAAA;;;;;;;;AA2Eb,cA3EH,eAAA,YAA2B,kBA6ErC,CAAA;;;;sBAxEmB;mCAeT,mBACR,QAAQ;+BA+BwB;;;;;;;;iBAuBrB,qBAAA,SACN,wBACP"}
|
|
@@ -0,0 +1,61 @@
|
|
|
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 };
|
|
61
|
+
//# sourceMappingURL=vector-retriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-retriever.js","names":[],"sources":["../../src/retriever/vector-retriever.ts"],"sourcesContent":["import type {\n EmbeddingProvider,\n VectorStoreProvider,\n} from '@contractspec/lib.contracts';\nimport type { RetrievalResult, RetrievalOptions } from '../types';\nimport type { KnowledgeRetriever, RetrieverConfig } from './interface';\n\n/**\n * Configuration for the vector retriever.\n */\nexport interface VectorRetrieverConfig extends RetrieverConfig {\n /** Embedding provider for query vectorization */\n embeddings: EmbeddingProvider;\n /** Vector store provider for similarity search */\n vectorStore: VectorStoreProvider;\n /** Map of space key to collection name */\n spaceCollections: Map<string, string> | Record<string, string>;\n /** Optional static content for getStatic() calls */\n staticContent?: Map<string, string> | Record<string, string>;\n}\n\n/**\n * A retriever that uses vector similarity search.\n *\n * Uses embedding provider to vectorize queries and vector store\n * provider to perform similarity search.\n */\nexport class VectorRetriever implements KnowledgeRetriever {\n private readonly config: VectorRetrieverConfig;\n private readonly spaceCollections: Map<string, string>;\n private readonly staticContent: Map<string, string>;\n\n constructor(config: VectorRetrieverConfig) {\n this.config = config;\n this.spaceCollections =\n config.spaceCollections instanceof Map\n ? config.spaceCollections\n : new Map(Object.entries(config.spaceCollections));\n this.staticContent = config.staticContent\n ? config.staticContent instanceof Map\n ? config.staticContent\n : new Map(Object.entries(config.staticContent))\n : new Map();\n }\n\n async retrieve(\n query: string,\n options: RetrievalOptions\n ): Promise<RetrievalResult[]> {\n const collection = this.spaceCollections.get(options.spaceKey);\n if (!collection) {\n return [];\n }\n\n // Embed the query\n const embedding = await this.config.embeddings.embedQuery(query);\n\n // Search the vector store\n const results = await this.config.vectorStore.search({\n collection,\n vector: embedding.vector,\n topK: options.topK ?? this.config.defaultTopK ?? 5,\n namespace: options.tenantId,\n filter: options.filter,\n });\n\n // Filter by minimum score\n const minScore = options.minScore ?? this.config.defaultMinScore ?? 0;\n const filtered = results.filter((r) => r.score >= minScore);\n\n // Map to RetrievalResult\n return filtered.map((result) => ({\n content: this.extractContent(result.payload),\n source: result.id,\n score: result.score,\n metadata: result.payload as Record<string, unknown> | undefined,\n }));\n }\n\n async getStatic(spaceKey: string): Promise<string | null> {\n return this.staticContent.get(spaceKey) ?? null;\n }\n\n supportsSpace(spaceKey: string): boolean {\n return this.spaceCollections.has(spaceKey);\n }\n\n listSpaces(): string[] {\n return [...this.spaceCollections.keys()];\n }\n\n private extractContent(payload: Record<string, unknown> | undefined): string {\n if (!payload) return '';\n if (typeof payload.text === 'string') return payload.text;\n if (typeof payload.content === 'string') return payload.content;\n return JSON.stringify(payload);\n }\n}\n\n/**\n * Create a vector retriever from configuration.\n */\nexport function createVectorRetriever(\n config: VectorRetrieverConfig\n): VectorRetriever {\n return new VectorRetriever(config);\n}\n"],"mappings":";;;;;;;AA2BA,IAAa,kBAAb,MAA2D;CACzD,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,QAA+B;AACzC,OAAK,SAAS;AACd,OAAK,mBACH,OAAO,4BAA4B,MAC/B,OAAO,mBACP,IAAI,IAAI,OAAO,QAAQ,OAAO,iBAAiB,CAAC;AACtD,OAAK,gBAAgB,OAAO,gBACxB,OAAO,yBAAyB,MAC9B,OAAO,gBACP,IAAI,IAAI,OAAO,QAAQ,OAAO,cAAc,CAAC,mBAC/C,IAAI,KAAK;;CAGf,MAAM,SACJ,OACA,SAC4B;EAC5B,MAAM,aAAa,KAAK,iBAAiB,IAAI,QAAQ,SAAS;AAC9D,MAAI,CAAC,WACH,QAAO,EAAE;EAIX,MAAM,YAAY,MAAM,KAAK,OAAO,WAAW,WAAW,MAAM;EAGhE,MAAM,UAAU,MAAM,KAAK,OAAO,YAAY,OAAO;GACnD;GACA,QAAQ,UAAU;GAClB,MAAM,QAAQ,QAAQ,KAAK,OAAO,eAAe;GACjD,WAAW,QAAQ;GACnB,QAAQ,QAAQ;GACjB,CAAC;EAGF,MAAM,WAAW,QAAQ,YAAY,KAAK,OAAO,mBAAmB;AAIpE,SAHiB,QAAQ,QAAQ,MAAM,EAAE,SAAS,SAAS,CAG3C,KAAK,YAAY;GAC/B,SAAS,KAAK,eAAe,OAAO,QAAQ;GAC5C,QAAQ,OAAO;GACf,OAAO,OAAO;GACd,UAAU,OAAO;GAClB,EAAE;;CAGL,MAAM,UAAU,UAA0C;AACxD,SAAO,KAAK,cAAc,IAAI,SAAS,IAAI;;CAG7C,cAAc,UAA2B;AACvC,SAAO,KAAK,iBAAiB,IAAI,SAAS;;CAG5C,aAAuB;AACrB,SAAO,CAAC,GAAG,KAAK,iBAAiB,MAAM,CAAC;;CAG1C,AAAQ,eAAe,SAAsD;AAC3E,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO,QAAQ,SAAS,SAAU,QAAO,QAAQ;AACrD,MAAI,OAAO,QAAQ,YAAY,SAAU,QAAO,QAAQ;AACxD,SAAO,KAAK,UAAU,QAAQ;;;;;;AAOlC,SAAgB,sBACd,QACiB;AACjB,QAAO,IAAI,gBAAgB,OAAO"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { KnowledgeCategory } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Result from a knowledge retrieval operation.
|
|
7
|
+
*/
|
|
8
|
+
interface RetrievalResult {
|
|
9
|
+
/** The retrieved content/text */
|
|
10
|
+
content: string;
|
|
11
|
+
/** Source identifier (document ID, URL, etc.) */
|
|
12
|
+
source: string;
|
|
13
|
+
/** Relevance score (0-1, higher is more relevant) */
|
|
14
|
+
score: number;
|
|
15
|
+
/** Additional metadata about the result */
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options for knowledge retrieval.
|
|
20
|
+
*/
|
|
21
|
+
interface RetrievalOptions {
|
|
22
|
+
/** Knowledge space key to query */
|
|
23
|
+
spaceKey: string;
|
|
24
|
+
/** Maximum number of results to return */
|
|
25
|
+
topK?: number;
|
|
26
|
+
/** Minimum relevance score threshold */
|
|
27
|
+
minScore?: number;
|
|
28
|
+
/** Filter by knowledge category */
|
|
29
|
+
category?: KnowledgeCategory;
|
|
30
|
+
/** Tenant-scoped retrieval */
|
|
31
|
+
tenantId?: string;
|
|
32
|
+
/** Additional filter criteria */
|
|
33
|
+
filter?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Context for knowledge access operations.
|
|
37
|
+
*/
|
|
38
|
+
interface KnowledgeAccessContext {
|
|
39
|
+
tenantId: string;
|
|
40
|
+
appId: string;
|
|
41
|
+
environment?: string;
|
|
42
|
+
workflowName?: string;
|
|
43
|
+
agentName?: string;
|
|
44
|
+
operation: 'read' | 'write' | 'search';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of an access check.
|
|
48
|
+
*/
|
|
49
|
+
interface KnowledgeAccessResult {
|
|
50
|
+
allowed: boolean;
|
|
51
|
+
reason?: string;
|
|
52
|
+
severity?: 'error' | 'warning';
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { KnowledgeAccessContext, KnowledgeAccessResult, RetrievalOptions, RetrievalResult };
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAciB,UAdA,eAAA,CAcgB;EAkBhB;EAYA,OAAA,EAAA,MAAA;;;;;;aApCJ;;;;;UAMI,gBAAA;;;;;;;;aAQJ;;;;WAIF;;;;;UAMM,sBAAA;;;;;;;;;;;UAYA,qBAAA"}
|
package/dist/types.js
ADDED
|
File without changes
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contractspec/lib.knowledge",
|
|
3
|
+
"version": "0.0.0-canary-20260113162409",
|
|
4
|
+
"description": "RAG and knowledge base primitives",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"contractspec",
|
|
7
|
+
"rag",
|
|
8
|
+
"knowledge-base",
|
|
9
|
+
"embeddings",
|
|
10
|
+
"typescript"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
20
|
+
"publish:pkg:canary": "bun publish:pkg --tag canary",
|
|
21
|
+
"build": "bun build:types && bun build:bundle",
|
|
22
|
+
"build:bundle": "tsdown",
|
|
23
|
+
"build:types": "tsc --noEmit",
|
|
24
|
+
"dev": "bun build:bundle --watch",
|
|
25
|
+
"clean": "rimraf dist .turbo",
|
|
26
|
+
"lint": "bun lint:fix",
|
|
27
|
+
"lint:fix": "eslint src --fix",
|
|
28
|
+
"lint:check": "eslint src",
|
|
29
|
+
"test": "bun test"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@contractspec/lib.contracts": "0.0.0-canary-20260113162409"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@contractspec/tool.tsdown": "0.0.0-canary-20260113162409",
|
|
36
|
+
"@contractspec/tool.typescript": "0.0.0-canary-20260113162409",
|
|
37
|
+
"tsdown": "^0.19.0",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
39
|
+
},
|
|
40
|
+
"exports": {
|
|
41
|
+
".": "./dist/index.js",
|
|
42
|
+
"./access": "./dist/access/index.js",
|
|
43
|
+
"./access/guard": "./dist/access/guard.js",
|
|
44
|
+
"./ingestion": "./dist/ingestion/index.js",
|
|
45
|
+
"./ingestion/document-processor": "./dist/ingestion/document-processor.js",
|
|
46
|
+
"./ingestion/embedding-service": "./dist/ingestion/embedding-service.js",
|
|
47
|
+
"./ingestion/gmail-adapter": "./dist/ingestion/gmail-adapter.js",
|
|
48
|
+
"./ingestion/storage-adapter": "./dist/ingestion/storage-adapter.js",
|
|
49
|
+
"./ingestion/vector-indexer": "./dist/ingestion/vector-indexer.js",
|
|
50
|
+
"./query": "./dist/query/index.js",
|
|
51
|
+
"./query/service": "./dist/query/service.js",
|
|
52
|
+
"./retriever": "./dist/retriever/index.js",
|
|
53
|
+
"./retriever/interface": "./dist/retriever/interface.js",
|
|
54
|
+
"./retriever/static-retriever": "./dist/retriever/static-retriever.js",
|
|
55
|
+
"./retriever/vector-retriever": "./dist/retriever/vector-retriever.js",
|
|
56
|
+
"./types": "./dist/types.js",
|
|
57
|
+
"./*": "./*"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public",
|
|
61
|
+
"exports": {
|
|
62
|
+
".": "./dist/index.js",
|
|
63
|
+
"./access": "./dist/access/index.js",
|
|
64
|
+
"./access/guard": "./dist/access/guard.js",
|
|
65
|
+
"./ingestion": "./dist/ingestion/index.js",
|
|
66
|
+
"./ingestion/document-processor": "./dist/ingestion/document-processor.js",
|
|
67
|
+
"./ingestion/embedding-service": "./dist/ingestion/embedding-service.js",
|
|
68
|
+
"./ingestion/gmail-adapter": "./dist/ingestion/gmail-adapter.js",
|
|
69
|
+
"./ingestion/storage-adapter": "./dist/ingestion/storage-adapter.js",
|
|
70
|
+
"./ingestion/vector-indexer": "./dist/ingestion/vector-indexer.js",
|
|
71
|
+
"./query": "./dist/query/index.js",
|
|
72
|
+
"./query/service": "./dist/query/service.js",
|
|
73
|
+
"./retriever": "./dist/retriever/index.js",
|
|
74
|
+
"./retriever/interface": "./dist/retriever/interface.js",
|
|
75
|
+
"./retriever/static-retriever": "./dist/retriever/static-retriever.js",
|
|
76
|
+
"./retriever/vector-retriever": "./dist/retriever/vector-retriever.js",
|
|
77
|
+
"./types": "./dist/types.js",
|
|
78
|
+
"./*": "./*"
|
|
79
|
+
},
|
|
80
|
+
"registry": "https://registry.npmjs.org/"
|
|
81
|
+
},
|
|
82
|
+
"license": "MIT",
|
|
83
|
+
"repository": {
|
|
84
|
+
"type": "git",
|
|
85
|
+
"url": "https://github.com/lssm-tech/contractspec.git",
|
|
86
|
+
"directory": "packages/libs/knowledge"
|
|
87
|
+
},
|
|
88
|
+
"homepage": "https://contractspec.io"
|
|
89
|
+
}
|