@dangao/bun-server 1.12.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/ai/ai-module.d.ts +24 -0
- package/dist/ai/ai-module.d.ts.map +1 -0
- package/dist/ai/decorators.d.ts +25 -0
- package/dist/ai/decorators.d.ts.map +1 -0
- package/dist/ai/errors.d.ts +39 -0
- package/dist/ai/errors.d.ts.map +1 -0
- package/dist/ai/index.d.ts +12 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/providers/anthropic-provider.d.ts +23 -0
- package/dist/ai/providers/anthropic-provider.d.ts.map +1 -0
- package/dist/ai/providers/google-provider.d.ts +20 -0
- package/dist/ai/providers/google-provider.d.ts.map +1 -0
- package/dist/ai/providers/ollama-provider.d.ts +17 -0
- package/dist/ai/providers/ollama-provider.d.ts.map +1 -0
- package/dist/ai/providers/openai-provider.d.ts +28 -0
- package/dist/ai/providers/openai-provider.d.ts.map +1 -0
- package/dist/ai/service.d.ts +40 -0
- package/dist/ai/service.d.ts.map +1 -0
- package/dist/ai/tools/tool-executor.d.ts +15 -0
- package/dist/ai/tools/tool-executor.d.ts.map +1 -0
- package/dist/ai/tools/tool-registry.d.ts +39 -0
- package/dist/ai/tools/tool-registry.d.ts.map +1 -0
- package/dist/ai/types.d.ts +134 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai-guard/ai-guard-module.d.ts +18 -0
- package/dist/ai-guard/ai-guard-module.d.ts.map +1 -0
- package/dist/ai-guard/decorators.d.ts +16 -0
- package/dist/ai-guard/decorators.d.ts.map +1 -0
- package/dist/ai-guard/detectors/content-moderator.d.ts +26 -0
- package/dist/ai-guard/detectors/content-moderator.d.ts.map +1 -0
- package/dist/ai-guard/detectors/injection-detector.d.ts +13 -0
- package/dist/ai-guard/detectors/injection-detector.d.ts.map +1 -0
- package/dist/ai-guard/detectors/pii-detector.d.ts +11 -0
- package/dist/ai-guard/detectors/pii-detector.d.ts.map +1 -0
- package/dist/ai-guard/index.d.ts +8 -0
- package/dist/ai-guard/index.d.ts.map +1 -0
- package/dist/ai-guard/service.d.ts +21 -0
- package/dist/ai-guard/service.d.ts.map +1 -0
- package/dist/ai-guard/types.d.ts +59 -0
- package/dist/ai-guard/types.d.ts.map +1 -0
- package/dist/conversation/conversation-module.d.ts +25 -0
- package/dist/conversation/conversation-module.d.ts.map +1 -0
- package/dist/conversation/decorators.d.ts +28 -0
- package/dist/conversation/decorators.d.ts.map +1 -0
- package/dist/conversation/index.d.ts +8 -0
- package/dist/conversation/index.d.ts.map +1 -0
- package/dist/conversation/service.d.ts +43 -0
- package/dist/conversation/service.d.ts.map +1 -0
- package/dist/conversation/stores/database-store.d.ts +46 -0
- package/dist/conversation/stores/database-store.d.ts.map +1 -0
- package/dist/conversation/stores/memory-store.d.ts +17 -0
- package/dist/conversation/stores/memory-store.d.ts.map +1 -0
- package/dist/conversation/stores/redis-store.d.ts +39 -0
- package/dist/conversation/stores/redis-store.d.ts.map +1 -0
- package/dist/conversation/types.d.ts +64 -0
- package/dist/conversation/types.d.ts.map +1 -0
- package/dist/core/cluster.d.ts +42 -3
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/embedding/embedding-module.d.ts +20 -0
- package/dist/embedding/embedding-module.d.ts.map +1 -0
- package/dist/embedding/index.d.ts +6 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/providers/ollama-embedding-provider.d.ts +18 -0
- package/dist/embedding/providers/ollama-embedding-provider.d.ts.map +1 -0
- package/dist/embedding/providers/openai-embedding-provider.d.ts +18 -0
- package/dist/embedding/providers/openai-embedding-provider.d.ts.map +1 -0
- package/dist/embedding/service.d.ts +27 -0
- package/dist/embedding/service.d.ts.map +1 -0
- package/dist/embedding/types.d.ts +25 -0
- package/dist/embedding/types.d.ts.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2870 -88
- package/dist/mcp/decorators.d.ts +42 -0
- package/dist/mcp/decorators.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +6 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/mcp-module.d.ts +22 -0
- package/dist/mcp/mcp-module.d.ts.map +1 -0
- package/dist/mcp/registry.d.ts +23 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/server.d.ts +29 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/types.d.ts +60 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/prompt/index.d.ts +6 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/prompt-module.d.ts +23 -0
- package/dist/prompt/prompt-module.d.ts.map +1 -0
- package/dist/prompt/service.d.ts +47 -0
- package/dist/prompt/service.d.ts.map +1 -0
- package/dist/prompt/stores/file-store.d.ts +36 -0
- package/dist/prompt/stores/file-store.d.ts.map +1 -0
- package/dist/prompt/stores/memory-store.d.ts +17 -0
- package/dist/prompt/stores/memory-store.d.ts.map +1 -0
- package/dist/prompt/types.d.ts +68 -0
- package/dist/prompt/types.d.ts.map +1 -0
- package/dist/rag/chunkers/markdown-chunker.d.ts +11 -0
- package/dist/rag/chunkers/markdown-chunker.d.ts.map +1 -0
- package/dist/rag/chunkers/text-chunker.d.ts +11 -0
- package/dist/rag/chunkers/text-chunker.d.ts.map +1 -0
- package/dist/rag/decorators.d.ts +24 -0
- package/dist/rag/decorators.d.ts.map +1 -0
- package/dist/rag/index.d.ts +7 -0
- package/dist/rag/index.d.ts.map +1 -0
- package/dist/rag/rag-module.d.ts +23 -0
- package/dist/rag/rag-module.d.ts.map +1 -0
- package/dist/rag/service.d.ts +36 -0
- package/dist/rag/service.d.ts.map +1 -0
- package/dist/rag/types.d.ts +56 -0
- package/dist/rag/types.d.ts.map +1 -0
- package/dist/vector-store/index.d.ts +6 -0
- package/dist/vector-store/index.d.ts.map +1 -0
- package/dist/vector-store/stores/memory-store.d.ts +17 -0
- package/dist/vector-store/stores/memory-store.d.ts.map +1 -0
- package/dist/vector-store/stores/pinecone-store.d.ts +27 -0
- package/dist/vector-store/stores/pinecone-store.d.ts.map +1 -0
- package/dist/vector-store/stores/qdrant-store.d.ts +29 -0
- package/dist/vector-store/stores/qdrant-store.d.ts.map +1 -0
- package/dist/vector-store/types.d.ts +60 -0
- package/dist/vector-store/types.d.ts.map +1 -0
- package/dist/vector-store/vector-store-module.d.ts +20 -0
- package/dist/vector-store/vector-store-module.d.ts.map +1 -0
- package/docs/ai.md +500 -0
- package/docs/best-practices.md +83 -8
- package/docs/database.md +23 -0
- package/docs/guide.md +90 -27
- package/docs/migration.md +81 -7
- package/docs/security.md +23 -0
- package/docs/zh/ai.md +441 -0
- package/docs/zh/best-practices.md +43 -0
- package/docs/zh/database.md +23 -0
- package/docs/zh/guide.md +40 -1
- package/docs/zh/migration.md +39 -0
- package/docs/zh/security.md +23 -0
- package/package.json +2 -2
- package/src/ai/ai-module.ts +62 -0
- package/src/ai/decorators.ts +30 -0
- package/src/ai/errors.ts +71 -0
- package/src/ai/index.ts +11 -0
- package/src/ai/providers/anthropic-provider.ts +190 -0
- package/src/ai/providers/google-provider.ts +179 -0
- package/src/ai/providers/ollama-provider.ts +126 -0
- package/src/ai/providers/openai-provider.ts +242 -0
- package/src/ai/service.ts +155 -0
- package/src/ai/tools/tool-executor.ts +38 -0
- package/src/ai/tools/tool-registry.ts +91 -0
- package/src/ai/types.ts +145 -0
- package/src/ai-guard/ai-guard-module.ts +50 -0
- package/src/ai-guard/decorators.ts +21 -0
- package/src/ai-guard/detectors/content-moderator.ts +80 -0
- package/src/ai-guard/detectors/injection-detector.ts +48 -0
- package/src/ai-guard/detectors/pii-detector.ts +64 -0
- package/src/ai-guard/index.ts +7 -0
- package/src/ai-guard/service.ts +100 -0
- package/src/ai-guard/types.ts +61 -0
- package/src/conversation/conversation-module.ts +63 -0
- package/src/conversation/decorators.ts +47 -0
- package/src/conversation/index.ts +7 -0
- package/src/conversation/service.ts +133 -0
- package/src/conversation/stores/database-store.ts +125 -0
- package/src/conversation/stores/memory-store.ts +57 -0
- package/src/conversation/stores/redis-store.ts +101 -0
- package/src/conversation/types.ts +68 -0
- package/src/core/cluster.ts +239 -46
- package/src/core/index.ts +1 -1
- package/src/core/server.ts +91 -78
- package/src/embedding/embedding-module.ts +52 -0
- package/src/embedding/index.ts +5 -0
- package/src/embedding/providers/ollama-embedding-provider.ts +39 -0
- package/src/embedding/providers/openai-embedding-provider.ts +47 -0
- package/src/embedding/service.ts +55 -0
- package/src/embedding/types.ts +27 -0
- package/src/index.ts +11 -1
- package/src/mcp/decorators.ts +60 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/mcp-module.ts +58 -0
- package/src/mcp/registry.ts +72 -0
- package/src/mcp/server.ts +164 -0
- package/src/mcp/types.ts +63 -0
- package/src/prompt/index.ts +5 -0
- package/src/prompt/prompt-module.ts +61 -0
- package/src/prompt/service.ts +93 -0
- package/src/prompt/stores/file-store.ts +135 -0
- package/src/prompt/stores/memory-store.ts +82 -0
- package/src/prompt/types.ts +84 -0
- package/src/rag/chunkers/markdown-chunker.ts +40 -0
- package/src/rag/chunkers/text-chunker.ts +30 -0
- package/src/rag/decorators.ts +26 -0
- package/src/rag/index.ts +6 -0
- package/src/rag/rag-module.ts +78 -0
- package/src/rag/service.ts +134 -0
- package/src/rag/types.ts +47 -0
- package/src/vector-store/index.ts +5 -0
- package/src/vector-store/stores/memory-store.ts +69 -0
- package/src/vector-store/stores/pinecone-store.ts +123 -0
- package/src/vector-store/stores/qdrant-store.ts +147 -0
- package/src/vector-store/types.ts +77 -0
- package/src/vector-store/vector-store-module.ts +50 -0
- package/tests/ai/ai-module.test.ts +46 -0
- package/tests/ai/ai-service.test.ts +91 -0
- package/tests/ai/tool-registry.test.ts +57 -0
- package/tests/ai-guard/ai-guard-module.test.ts +23 -0
- package/tests/ai-guard/content-moderator.test.ts +65 -0
- package/tests/ai-guard/pii-detector.test.ts +41 -0
- package/tests/conversation/conversation-module.test.ts +26 -0
- package/tests/conversation/conversation-service.test.ts +64 -0
- package/tests/conversation/memory-store.test.ts +68 -0
- package/tests/core/cluster.test.ts +45 -1
- package/tests/embedding/embedding-service.test.ts +55 -0
- package/tests/mcp/mcp-server.test.ts +85 -0
- package/tests/prompt/prompt-module.test.ts +30 -0
- package/tests/prompt/prompt-service.test.ts +74 -0
- package/tests/rag/chunkers.test.ts +58 -0
- package/tests/rag/rag-service.test.ts +66 -0
- package/tests/vector-store/memory-vector-store.test.ts +84 -0
- package/tests/interceptor/perf/interceptor-performance.test.ts +0 -340
- package/tests/perf/optimization.test.ts +0 -182
- package/tests/perf/regression.test.ts +0 -120
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vector-store/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { VectorStore, VectorDocument, VectorSearchResult, VectorSearchOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* High-performance in-memory vector store using cosine similarity.
|
|
4
|
+
* Suitable for development and small to medium datasets (up to ~100K documents).
|
|
5
|
+
*/
|
|
6
|
+
export declare class MemoryVectorStore implements VectorStore {
|
|
7
|
+
private readonly documents;
|
|
8
|
+
upsert(document: VectorDocument): Promise<void>;
|
|
9
|
+
upsertBatch(documents: VectorDocument[]): Promise<void>;
|
|
10
|
+
get(id: string, collection?: string): Promise<VectorDocument | null>;
|
|
11
|
+
search(query: number[], options?: VectorSearchOptions): Promise<VectorSearchResult[]>;
|
|
12
|
+
delete(id: string, collection?: string): Promise<boolean>;
|
|
13
|
+
deleteCollection(collection: string): Promise<void>;
|
|
14
|
+
count(collection?: string): Promise<number>;
|
|
15
|
+
private key;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../../src/vector-store/stores/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGrG;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqC;IAElD,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvD,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAIpE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAoBzF,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIzD,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASxD,OAAO,CAAC,GAAG;CAGZ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { VectorStore, VectorDocument, VectorSearchResult, VectorSearchOptions } from '../types';
|
|
2
|
+
export interface PineconeStoreConfig {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
/** Pinecone host URL (e.g., https://my-index-xxxx.svc.aped-xxxx.pinecone.io) */
|
|
5
|
+
host: string;
|
|
6
|
+
/** Namespace (optional) */
|
|
7
|
+
namespace?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Pinecone vector store adapter.
|
|
11
|
+
* Uses the Pinecone REST API directly — no SDK dependency.
|
|
12
|
+
*/
|
|
13
|
+
export declare class PineconeVectorStore implements VectorStore {
|
|
14
|
+
private readonly apiKey;
|
|
15
|
+
private readonly host;
|
|
16
|
+
private readonly namespace;
|
|
17
|
+
constructor(config: PineconeStoreConfig);
|
|
18
|
+
upsert(document: VectorDocument): Promise<void>;
|
|
19
|
+
upsertBatch(documents: VectorDocument[]): Promise<void>;
|
|
20
|
+
get(id: string): Promise<VectorDocument | null>;
|
|
21
|
+
search(query: number[], options?: VectorSearchOptions): Promise<VectorSearchResult[]>;
|
|
22
|
+
delete(id: string): Promise<boolean>;
|
|
23
|
+
deleteCollection(collection: string): Promise<void>;
|
|
24
|
+
count(): Promise<number>;
|
|
25
|
+
private request;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=pinecone-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pinecone-store.d.ts","sourceRoot":"","sources":["../../../src/vector-store/stores/pinecone-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAErG,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEhB,MAAM,EAAE,mBAAmB;IAMjC,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAiB/C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA+BzF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKpC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;YAUvB,OAAO;CAYtB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { VectorStore, VectorDocument, VectorSearchResult, VectorSearchOptions } from '../types';
|
|
2
|
+
export interface QdrantStoreConfig {
|
|
3
|
+
/** Qdrant server URL (default: http://localhost:6333) */
|
|
4
|
+
url?: string;
|
|
5
|
+
/** Collection name in Qdrant */
|
|
6
|
+
collectionName: string;
|
|
7
|
+
/** API key (optional, for Qdrant Cloud) */
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Qdrant vector store adapter.
|
|
12
|
+
* Uses the Qdrant REST API directly — no SDK dependency.
|
|
13
|
+
*/
|
|
14
|
+
export declare class QdrantVectorStore implements VectorStore {
|
|
15
|
+
private readonly url;
|
|
16
|
+
private readonly collectionName;
|
|
17
|
+
private readonly apiKey;
|
|
18
|
+
constructor(config: QdrantStoreConfig);
|
|
19
|
+
upsert(document: VectorDocument): Promise<void>;
|
|
20
|
+
upsertBatch(documents: VectorDocument[]): Promise<void>;
|
|
21
|
+
get(id: string): Promise<VectorDocument | null>;
|
|
22
|
+
search(query: number[], options?: VectorSearchOptions): Promise<VectorSearchResult[]>;
|
|
23
|
+
delete(id: string): Promise<boolean>;
|
|
24
|
+
deleteCollection(collection: string): Promise<void>;
|
|
25
|
+
count(): Promise<number>;
|
|
26
|
+
private toNumericId;
|
|
27
|
+
private request;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=qdrant-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant-store.d.ts","sourceRoot":"","sources":["../../../src/vector-store/stores/qdrant-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAErG,MAAM,WAAW,iBAAiB;IAChC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAEzB,MAAM,EAAE,iBAAiB;IAM/B,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAevD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqB/C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAmCzF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IASrC,OAAO,CAAC,WAAW;YAKL,OAAO;CAYtB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A document stored in the vector store
|
|
3
|
+
*/
|
|
4
|
+
export interface VectorDocument {
|
|
5
|
+
id: string;
|
|
6
|
+
/** The embedding vector */
|
|
7
|
+
vector: number[];
|
|
8
|
+
/** Original text content */
|
|
9
|
+
content: string;
|
|
10
|
+
/** Arbitrary metadata */
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
/** Collection / namespace */
|
|
13
|
+
collection?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Search result with similarity score
|
|
17
|
+
*/
|
|
18
|
+
export interface VectorSearchResult {
|
|
19
|
+
document: VectorDocument;
|
|
20
|
+
/** Cosine similarity score [0, 1] */
|
|
21
|
+
score: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Search options
|
|
25
|
+
*/
|
|
26
|
+
export interface VectorSearchOptions {
|
|
27
|
+
topK?: number;
|
|
28
|
+
minScore?: number;
|
|
29
|
+
collection?: string;
|
|
30
|
+
filter?: (doc: VectorDocument) => boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Abstract vector store interface
|
|
34
|
+
*/
|
|
35
|
+
export interface VectorStore {
|
|
36
|
+
/** Insert or update a document */
|
|
37
|
+
upsert(document: VectorDocument): Promise<void>;
|
|
38
|
+
/** Insert or update multiple documents */
|
|
39
|
+
upsertBatch(documents: VectorDocument[]): Promise<void>;
|
|
40
|
+
/** Retrieve a document by ID */
|
|
41
|
+
get(id: string, collection?: string): Promise<VectorDocument | null>;
|
|
42
|
+
/** Search for similar documents using cosine similarity */
|
|
43
|
+
search(query: number[], options?: VectorSearchOptions): Promise<VectorSearchResult[]>;
|
|
44
|
+
/** Delete a document by ID */
|
|
45
|
+
delete(id: string, collection?: string): Promise<boolean>;
|
|
46
|
+
/** Delete all documents in a collection */
|
|
47
|
+
deleteCollection(collection: string): Promise<void>;
|
|
48
|
+
/** Count documents */
|
|
49
|
+
count(collection?: string): Promise<number>;
|
|
50
|
+
}
|
|
51
|
+
export interface VectorStoreModuleOptions {
|
|
52
|
+
store?: VectorStore;
|
|
53
|
+
}
|
|
54
|
+
export declare const VECTOR_STORE_TOKEN: unique symbol;
|
|
55
|
+
export declare const VECTOR_STORE_OPTIONS_TOKEN: unique symbol;
|
|
56
|
+
/**
|
|
57
|
+
* Compute cosine similarity between two vectors
|
|
58
|
+
*/
|
|
59
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vector-store/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,cAAc,CAAC;IACzB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,0CAA0C;IAC1C,WAAW,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,gCAAgC;IAChC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACrE,2DAA2D;IAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACtF,8BAA8B;IAC9B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,2CAA2C;IAC3C,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,sBAAsB;IACtB,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,eAAkD,CAAC;AAClF,eAAO,MAAM,0BAA0B,eAAoD,CAAC;AAE5F;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAYjE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type VectorStoreModuleOptions } from './types';
|
|
2
|
+
export declare class VectorStoreModule {
|
|
3
|
+
/**
|
|
4
|
+
* Configure the vector store module.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // Built-in memory store (default):
|
|
9
|
+
* VectorStoreModule.forRoot({});
|
|
10
|
+
*
|
|
11
|
+
* // Pinecone:
|
|
12
|
+
* VectorStoreModule.forRoot({
|
|
13
|
+
* store: new PineconeVectorStore({ apiKey: '...', host: '...' }),
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
static forRoot(options?: VectorStoreModuleOptions): typeof VectorStoreModule;
|
|
18
|
+
static reset(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=vector-store-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-module.d.ts","sourceRoot":"","sources":["../../src/vector-store/vector-store-module.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,SAAS,CAAC;AAGjB,qBACa,iBAAiB;IAC5B;;;;;;;;;;;;;OAaG;WACW,OAAO,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,iBAAiB;WAqBzE,KAAK,IAAI,IAAI;CAG5B"}
|
package/docs/ai.md
ADDED
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# AI Modules
|
|
2
|
+
|
|
3
|
+
**English** | [中文](./zh/ai.md)
|
|
4
|
+
|
|
5
|
+
`@dangao/bun-server` v2.0.0 introduces **9 official AI modules** providing production-ready infrastructure for building LLM-powered applications.
|
|
6
|
+
|
|
7
|
+
All providers communicate via Bun's native `fetch()` — no third-party AI SDK dependencies are added to the framework package.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Start — 5-Minute Chat API
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ollama pull llama3.2 # Free local model
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import {
|
|
19
|
+
Application, Controller, Module, Injectable, Inject,
|
|
20
|
+
POST, Body, AiModule, AiService, OllamaProvider, AI_SERVICE_TOKEN,
|
|
21
|
+
} from '@dangao/bun-server';
|
|
22
|
+
|
|
23
|
+
AiModule.forRoot({
|
|
24
|
+
providers: [{ name: 'ollama', provider: OllamaProvider, config: {}, default: true }],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
@Injectable()
|
|
28
|
+
class ChatService {
|
|
29
|
+
constructor(@Inject(AI_SERVICE_TOKEN) private ai: AiService) {}
|
|
30
|
+
async chat(msg: string) {
|
|
31
|
+
return this.ai.complete({ messages: [{ role: 'user', content: msg }] });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Controller('/chat')
|
|
36
|
+
class ChatController {
|
|
37
|
+
constructor(private svc: ChatService) {}
|
|
38
|
+
@POST('/') async post(@Body() b: { message: string }) { return this.svc.chat(b.message); }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Module({ imports: [AiModule], controllers: [ChatController], providers: [ChatService] })
|
|
42
|
+
class AppModule {}
|
|
43
|
+
|
|
44
|
+
const app = new Application({ port: 3000 });
|
|
45
|
+
app.registerModule(AppModule);
|
|
46
|
+
app.listen();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Module Overview
|
|
52
|
+
|
|
53
|
+
| Module | Token | Purpose |
|
|
54
|
+
|--------|-------|---------|
|
|
55
|
+
| `AiModule` | `AI_SERVICE_TOKEN` | LLM providers + Tool Calling + streaming |
|
|
56
|
+
| `ConversationModule` | `CONVERSATION_SERVICE_TOKEN` | Multi-turn conversation history |
|
|
57
|
+
| `PromptModule` | `PROMPT_SERVICE_TOKEN` | Prompt templates + versioning |
|
|
58
|
+
| `EmbeddingModule` | `EMBEDDING_SERVICE_TOKEN` | Text embedding generation |
|
|
59
|
+
| `VectorStoreModule` | `VECTOR_STORE_TOKEN` | Vector similarity search |
|
|
60
|
+
| `RagModule` | `RAG_SERVICE_TOKEN` | RAG ingest + retrieve pipeline |
|
|
61
|
+
| `McpModule` | `MCP_SERVER_TOKEN` | MCP protocol server |
|
|
62
|
+
| `AiGuardModule` | `AI_GUARD_SERVICE_TOKEN` | Content safety |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## AiModule — LLM Unified Access
|
|
67
|
+
|
|
68
|
+
### Configuration
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { AiModule, OpenAIProvider, AnthropicProvider, OllamaProvider, GoogleProvider } from '@dangao/bun-server';
|
|
72
|
+
|
|
73
|
+
AiModule.forRoot({
|
|
74
|
+
providers: [
|
|
75
|
+
{ name: 'openai', provider: OpenAIProvider, config: { apiKey: process.env.OPENAI_API_KEY! }, default: true },
|
|
76
|
+
{ name: 'claude', provider: AnthropicProvider, config: { apiKey: process.env.ANTHROPIC_API_KEY! } },
|
|
77
|
+
{ name: 'ollama', provider: OllamaProvider, config: { baseUrl: 'http://localhost:11434' } },
|
|
78
|
+
{ name: 'gemini', provider: GoogleProvider, config: { apiKey: process.env.GOOGLE_API_KEY! } },
|
|
79
|
+
],
|
|
80
|
+
fallback: true, // Try next provider on failure
|
|
81
|
+
timeout: 30000, // Request timeout in ms
|
|
82
|
+
tools: {
|
|
83
|
+
autoDiscover: true, // Auto-register @AiTool() decorated methods
|
|
84
|
+
maxIterations: 10, // Max Tool Calling iterations
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Usage
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
@Injectable()
|
|
93
|
+
class ChatService {
|
|
94
|
+
constructor(@Inject(AI_SERVICE_TOKEN) private ai: AiService) {}
|
|
95
|
+
|
|
96
|
+
// Non-streaming
|
|
97
|
+
async complete(messages: AiMessage[]) {
|
|
98
|
+
return this.ai.complete({ messages, provider: 'openai' });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Streaming (SSE)
|
|
102
|
+
stream(messages: AiMessage[]): ReadableStream<Uint8Array> {
|
|
103
|
+
return this.ai.stream({ messages });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Switch provider
|
|
107
|
+
async withClaude(messages: AiMessage[]) {
|
|
108
|
+
return this.ai.complete({ messages, provider: 'claude' });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Streaming Responses
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
@GET('/stream')
|
|
117
|
+
public streamChat(@Query('message') message: string): Response {
|
|
118
|
+
const stream = this.aiService.stream({
|
|
119
|
+
messages: [{ role: 'user', content: message }],
|
|
120
|
+
});
|
|
121
|
+
return new Response(stream, {
|
|
122
|
+
headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Each SSE chunk has the format: `data: {"content":"...","done":false}\n\n`
|
|
128
|
+
|
|
129
|
+
### Tool Calling with @AiTool()
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
@Injectable()
|
|
133
|
+
class MyTools {
|
|
134
|
+
@AiTool({
|
|
135
|
+
name: 'get_weather',
|
|
136
|
+
description: 'Get current weather for a city',
|
|
137
|
+
parameters: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: { city: { type: 'string' } },
|
|
140
|
+
required: ['city'],
|
|
141
|
+
},
|
|
142
|
+
})
|
|
143
|
+
async getWeather({ city }: { city: string }): Promise<string> {
|
|
144
|
+
return `Weather in ${city}: 22°C, sunny`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Register tools:
|
|
149
|
+
const registry = container.resolve<ToolRegistry>(AI_TOOL_REGISTRY_TOKEN);
|
|
150
|
+
registry.scanAndRegister(new MyTools());
|
|
151
|
+
|
|
152
|
+
// Complete with tools (auto-loop):
|
|
153
|
+
const response = await aiService.complete({
|
|
154
|
+
messages: [{ role: 'user', content: 'What is the weather in Tokyo?' }],
|
|
155
|
+
tools: registry.getDefinitions(),
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## ConversationModule — Multi-Turn Memory
|
|
162
|
+
|
|
163
|
+
### Configuration
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { ConversationModule, MemoryConversationStore } from '@dangao/bun-server';
|
|
167
|
+
|
|
168
|
+
ConversationModule.forRoot({
|
|
169
|
+
store: new MemoryConversationStore(), // or RedisConversationStore / DatabaseConversationStore
|
|
170
|
+
maxMessages: 50,
|
|
171
|
+
autoTrim: true,
|
|
172
|
+
summaryThreshold: 40, // Trigger summarization when > 40 messages
|
|
173
|
+
summarizer: async (messages) => {
|
|
174
|
+
// Inject AiService to summarize — avoids circular dependency
|
|
175
|
+
return await aiService.complete({ messages: [...messages, summaryPrompt] }).then(r => r.content);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Usage
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
@POST('/chat')
|
|
184
|
+
async chat(@Body() body: { message: string; conversationId?: string }) {
|
|
185
|
+
let convId = body.conversationId;
|
|
186
|
+
if (!convId) {
|
|
187
|
+
const conv = await this.conversations.create();
|
|
188
|
+
convId = conv.id;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const history = await this.conversations.getHistory(convId);
|
|
192
|
+
const response = await this.ai.complete({ messages: [...history, { role: 'user', content: body.message }] });
|
|
193
|
+
|
|
194
|
+
await this.conversations.appendMessage(convId, { role: 'user', content: body.message });
|
|
195
|
+
await this.conversations.appendMessage(convId, { role: 'assistant', content: response.content });
|
|
196
|
+
|
|
197
|
+
return { conversationId: convId, reply: response.content };
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Stores
|
|
202
|
+
|
|
203
|
+
| Store | Use case |
|
|
204
|
+
|-------|----------|
|
|
205
|
+
| `MemoryConversationStore` | Development, single-instance (default) |
|
|
206
|
+
| `RedisConversationStore` | Production, multi-instance |
|
|
207
|
+
| `DatabaseConversationStore` | Durable storage, full history queries |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## PromptModule — Prompt Templates
|
|
212
|
+
|
|
213
|
+
### Configuration
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { PromptModule, InMemoryPromptStore, FilePromptStore } from '@dangao/bun-server';
|
|
217
|
+
|
|
218
|
+
// In-memory (default):
|
|
219
|
+
PromptModule.forRoot({});
|
|
220
|
+
|
|
221
|
+
// File-based (loads from .prompts/*.json):
|
|
222
|
+
PromptModule.forRoot({
|
|
223
|
+
store: new FilePromptStore({ promptsDir: './.prompts' }),
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Usage
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// Create template
|
|
231
|
+
await promptService.create({
|
|
232
|
+
id: 'system-assistant',
|
|
233
|
+
name: 'System: Assistant',
|
|
234
|
+
content: 'You are {{role}}, a helpful assistant for {{company}}.',
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Render with variables
|
|
238
|
+
const prompt = await promptService.render('system-assistant', {
|
|
239
|
+
role: 'data analyst',
|
|
240
|
+
company: 'Acme Corp',
|
|
241
|
+
});
|
|
242
|
+
// "You are data analyst, a helpful assistant for Acme Corp."
|
|
243
|
+
|
|
244
|
+
// Update creates a new version
|
|
245
|
+
await promptService.update('system-assistant', { content: 'You are {{role}} at {{company}}.' });
|
|
246
|
+
|
|
247
|
+
// Retrieve specific version
|
|
248
|
+
const v1 = await promptService.getVersion('system-assistant', 1);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## EmbeddingModule + VectorStoreModule
|
|
254
|
+
|
|
255
|
+
### Configuration
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import {
|
|
259
|
+
EmbeddingModule, OpenAIEmbeddingProvider,
|
|
260
|
+
VectorStoreModule, MemoryVectorStore,
|
|
261
|
+
} from '@dangao/bun-server';
|
|
262
|
+
|
|
263
|
+
EmbeddingModule.forRoot({
|
|
264
|
+
provider: { name: 'openai', provider: OpenAIEmbeddingProvider, config: { apiKey: '...' } },
|
|
265
|
+
batchSize: 100,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
VectorStoreModule.forRoot({
|
|
269
|
+
store: new MemoryVectorStore(), // or PineconeVectorStore / QdrantVectorStore
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Usage
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// Generate embeddings
|
|
277
|
+
const vector = await embeddingService.embed('Hello world');
|
|
278
|
+
const vectors = await embeddingService.embedBatch(['text 1', 'text 2']);
|
|
279
|
+
|
|
280
|
+
// Vector store operations
|
|
281
|
+
await vectorStore.upsert({ id: 'doc1', vector, content: 'Hello world', collection: 'docs' });
|
|
282
|
+
const results = await vectorStore.search(queryVector, { topK: 5, collection: 'docs', minScore: 0.7 });
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## RagModule — RAG Pipeline
|
|
288
|
+
|
|
289
|
+
### Configuration
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { RagModule } from '@dangao/bun-server';
|
|
293
|
+
|
|
294
|
+
// Requires EmbeddingModule and VectorStoreModule to be imported first
|
|
295
|
+
RagModule.forRoot({
|
|
296
|
+
collection: 'my-kb',
|
|
297
|
+
chunkSize: 512,
|
|
298
|
+
chunkOverlap: 50,
|
|
299
|
+
topK: 5,
|
|
300
|
+
minScore: 0.5,
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Usage
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
@Injectable()
|
|
308
|
+
class KnowledgeService {
|
|
309
|
+
constructor(@Inject(RAG_SERVICE_TOKEN) private rag: RagService) {}
|
|
310
|
+
|
|
311
|
+
// Ingest documents
|
|
312
|
+
async ingest() {
|
|
313
|
+
await this.rag.ingest({ type: 'text', content: 'Bun is a fast JS runtime.' });
|
|
314
|
+
await this.rag.ingest({ type: 'file', path: './docs/manual.md' });
|
|
315
|
+
await this.rag.ingest({ type: 'url', url: 'https://bun.sh/docs' });
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Retrieve context for a query
|
|
319
|
+
async answer(question: string) {
|
|
320
|
+
const context = await this.rag.retrieve(question);
|
|
321
|
+
// context.formatted = "[1] Bun is...\n\n[2] ..."
|
|
322
|
+
return context;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## McpModule — Model Context Protocol Server
|
|
330
|
+
|
|
331
|
+
MCP (Model Context Protocol) enables AI clients (Cursor, Claude Desktop, VS Code Copilot) to call your API methods as tools.
|
|
332
|
+
|
|
333
|
+
### Configuration
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { McpModule } from '@dangao/bun-server';
|
|
337
|
+
|
|
338
|
+
McpModule.forRoot({
|
|
339
|
+
transport: 'sse',
|
|
340
|
+
path: '/mcp',
|
|
341
|
+
serverInfo: { name: 'my-api', version: '1.0.0' },
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Define MCP Tools
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
@Injectable()
|
|
349
|
+
class MyTools {
|
|
350
|
+
@McpTool({
|
|
351
|
+
name: 'search_products',
|
|
352
|
+
description: 'Search for products by keyword',
|
|
353
|
+
inputSchema: {
|
|
354
|
+
type: 'object',
|
|
355
|
+
properties: { query: { type: 'string' } },
|
|
356
|
+
required: ['query'],
|
|
357
|
+
},
|
|
358
|
+
})
|
|
359
|
+
async searchProducts({ query }: { query: string }) {
|
|
360
|
+
return this.productService.search(query);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Register in a controller:
|
|
365
|
+
@Controller('/mcp')
|
|
366
|
+
class McpController {
|
|
367
|
+
constructor(
|
|
368
|
+
@Inject(MCP_SERVER_TOKEN) private server: McpServer,
|
|
369
|
+
private registry: McpRegistry,
|
|
370
|
+
private tools: MyTools,
|
|
371
|
+
) {
|
|
372
|
+
this.registry.scan(this.tools);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@GET('/') sse(): Response { return this.server.createSseResponse(); }
|
|
376
|
+
@POST('/') async handle(): Promise<Response> { ... }
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## AiGuardModule — Content Safety
|
|
383
|
+
|
|
384
|
+
### Configuration
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
import { AiGuardModule } from '@dangao/bun-server';
|
|
388
|
+
|
|
389
|
+
AiGuardModule.forRoot({
|
|
390
|
+
piiDetection: { redact: true },
|
|
391
|
+
promptInjection: { sensitivity: 'medium' }, // 'low' | 'medium' | 'high'
|
|
392
|
+
moderation: {
|
|
393
|
+
openaiApiKey: process.env.OPENAI_API_KEY, // Uses OpenAI Moderation API
|
|
394
|
+
blockCategories: ['hate', 'violence', 'sexual'],
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Usage
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
// Manual check
|
|
403
|
+
const result = await guardService.check(userInput);
|
|
404
|
+
if (!result.allowed) throw new HttpException(400, 'Content not allowed');
|
|
405
|
+
const safeInput = result.sanitizedInput; // PII-redacted version
|
|
406
|
+
|
|
407
|
+
// Or throw automatically:
|
|
408
|
+
const safeInput = await guardService.checkOrThrow(userInput);
|
|
409
|
+
|
|
410
|
+
// Decorator (marks method-level checking):
|
|
411
|
+
@POST('/chat')
|
|
412
|
+
@AiGuard({ piiDetection: true, promptInjection: true })
|
|
413
|
+
async chat(@Body() body: { message: string }) { ... }
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Building AI Applications — Best Practices
|
|
419
|
+
|
|
420
|
+
### 1. Use Ollama for Local Development
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Development: free, no API costs
|
|
424
|
+
AiModule.forRoot({
|
|
425
|
+
providers: [
|
|
426
|
+
{ name: 'ollama', provider: OllamaProvider, config: {}, default: true },
|
|
427
|
+
{ name: 'openai', provider: OpenAIProvider, config: { apiKey: env.OPENAI_API_KEY! } },
|
|
428
|
+
],
|
|
429
|
+
fallback: true,
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 2. Cache AI Responses
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
// Combine with CacheModule to avoid redundant LLM calls
|
|
437
|
+
const cached = await cacheService.getOrSet(
|
|
438
|
+
`ai:${hash(messages)}`,
|
|
439
|
+
() => aiService.complete({ messages }),
|
|
440
|
+
60_000, // 60s TTL
|
|
441
|
+
);
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 3. Track Token Usage and Costs
|
|
445
|
+
|
|
446
|
+
Every `AiResponse` includes `usage`:
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
const response = await aiService.complete({ messages });
|
|
450
|
+
console.log(response.usage);
|
|
451
|
+
// { promptTokens: 120, completionTokens: 50, totalTokens: 170, estimatedCostUsd: 0.00043 }
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### 4. Streaming Best Practices
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
// Always set proper SSE headers
|
|
458
|
+
return new Response(aiService.stream({ messages }), {
|
|
459
|
+
headers: {
|
|
460
|
+
'Content-Type': 'text/event-stream',
|
|
461
|
+
'Cache-Control': 'no-cache',
|
|
462
|
+
'Connection': 'keep-alive',
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### 5. Always Guard User Input
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
// Apply AiGuard before processing in production:
|
|
471
|
+
const safeMessage = await guardService.checkOrThrow(userInput);
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## AI Capability Coverage
|
|
477
|
+
|
|
478
|
+
| Capability | Official Module |
|
|
479
|
+
|---|---|
|
|
480
|
+
| Multi-LLM providers | `AiModule` |
|
|
481
|
+
| Text embeddings | `EmbeddingModule` |
|
|
482
|
+
| Knowledge base / vector search | `VectorStoreModule` |
|
|
483
|
+
| RAG retrieval pipeline | `RagModule` |
|
|
484
|
+
| Conversation memory | `ConversationModule` |
|
|
485
|
+
| Prompt template management | `PromptModule` |
|
|
486
|
+
| Tool / Function Calling | `AiModule` (ToolRegistry + @AiTool()) |
|
|
487
|
+
| Content safety | `AiGuardModule` |
|
|
488
|
+
| MCP protocol server | `McpModule` |
|
|
489
|
+
| AI workflow orchestration | Demo layer (ai-platform-mvp example) |
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Related Resources
|
|
494
|
+
|
|
495
|
+
- [AI Modules Examples](../examples/05-ai/README.md)
|
|
496
|
+
- [AI Platform MVP Demo](../examples/05-ai/ai-platform-mvp/README.md)
|
|
497
|
+
- [Ollama Documentation](https://ollama.ai)
|
|
498
|
+
- [OpenAI API Reference](https://platform.openai.com/docs)
|
|
499
|
+
- [Anthropic API Reference](https://docs.anthropic.com)
|
|
500
|
+
- [MCP Specification](https://modelcontextprotocol.io)
|