@revealui/ai 0.1.3 → 0.2.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 +3 -0
- package/dist/ingestion/pipeline.d.ts +2 -1
- package/dist/ingestion/pipeline.d.ts.map +1 -1
- package/dist/ingestion/pipeline.js +10 -5
- package/dist/llm/client.d.ts +12 -2
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +35 -6
- package/dist/llm/providers/bitnet.d.ts +28 -0
- package/dist/llm/providers/bitnet.d.ts.map +1 -0
- package/dist/llm/providers/bitnet.js +36 -0
- package/dist/llm/semantic-cache.d.ts.map +1 -1
- package/dist/llm/semantic-cache.js +4 -4
- package/dist/llm/server.d.ts +1 -0
- package/dist/llm/server.d.ts.map +1 -1
- package/dist/llm/server.js +1 -0
- package/dist/memory/persistence/crdt-persistence.d.ts.map +1 -1
- package/dist/memory/persistence/crdt-persistence.js +2 -1
- package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -1
- package/dist/memory/preferences/user-preferences-manager.js +10 -9
- package/dist/memory/stores/episodic-memory.d.ts.map +1 -1
- package/dist/memory/stores/episodic-memory.js +2 -1
- package/dist/memory/utils/index.d.ts +0 -1
- package/dist/memory/utils/index.d.ts.map +1 -1
- package/dist/memory/utils/index.js +0 -1
- package/dist/memory/vector/vector-memory-service.d.ts +3 -0
- package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
- package/dist/memory/vector/vector-memory-service.js +18 -5
- package/dist/skills/loader/github-loader.d.ts.map +1 -1
- package/dist/skills/loader/github-loader.js +27 -16
- package/dist/skills/loader/vercel-loader.d.ts.map +1 -1
- package/dist/skills/loader/vercel-loader.js +26 -16
- package/package.json +16 -9
- package/dist/memory/utils/logger.d.ts +0 -21
- package/dist/memory/utils/logger.d.ts.map +0 -1
- package/dist/memory/utils/logger.js +0 -62
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# @revealui/ai
|
|
2
2
|
|
|
3
|
+
> **Commercial package** — requires a [RevealUI Pro license](https://revealui.com/pro). Free to install and evaluate; a license key is required for production use.
|
|
4
|
+
|
|
5
|
+
|
|
3
6
|
AI system for RevealUI - memory, LLM, orchestration, and tools.
|
|
4
7
|
|
|
5
8
|
## Features
|
|
@@ -24,9 +24,10 @@ export interface IngestResult {
|
|
|
24
24
|
}
|
|
25
25
|
export declare class IngestionPipeline {
|
|
26
26
|
private db;
|
|
27
|
+
private restDb;
|
|
27
28
|
private embeddingFn;
|
|
28
29
|
private splitter;
|
|
29
|
-
constructor(db: Database, embeddingFn: (text: string) => Promise<number[]>);
|
|
30
|
+
constructor(db: Database, restDb: Database, embeddingFn: (text: string) => Promise<number[]>);
|
|
30
31
|
ingest(req: IngestRequest): Promise<IngestResult>;
|
|
31
32
|
ingestBatch(docs: IngestRequest[]): Promise<IngestResult[]>;
|
|
32
33
|
deleteDocument(documentId: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/ingestion/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/ingestion/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAOnD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;IAOtF,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA6EjD,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAa3D,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CAiBjB"}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Orchestrates: parse → split → embed → store.
|
|
5
5
|
* One document produces N chunks, each with a 768-dim embedding.
|
|
6
6
|
*/
|
|
7
|
+
import { safeVectorInsert } from '@revealui/db/validation';
|
|
7
8
|
import { ragChunks, ragDocuments } from '@revealui/db/schema/rag';
|
|
8
9
|
import { and, eq } from 'drizzle-orm';
|
|
9
10
|
import { createParser } from './file-parsers.js';
|
|
10
11
|
import { RecursiveCharacterSplitter } from './text-splitter.js';
|
|
11
12
|
function generateId(prefix) {
|
|
12
|
-
return `${prefix}-${
|
|
13
|
+
return `${prefix}-${crypto.randomUUID()}`;
|
|
13
14
|
}
|
|
14
15
|
function estimateWordCount(text) {
|
|
15
16
|
return text.split(/\s+/).filter((w) => w.length > 0).length;
|
|
@@ -19,18 +20,22 @@ function estimateTokens(text) {
|
|
|
19
20
|
}
|
|
20
21
|
export class IngestionPipeline {
|
|
21
22
|
db;
|
|
23
|
+
restDb;
|
|
22
24
|
embeddingFn;
|
|
23
25
|
splitter;
|
|
24
|
-
constructor(db, embeddingFn) {
|
|
26
|
+
constructor(db, restDb, embeddingFn) {
|
|
25
27
|
this.db = db;
|
|
28
|
+
this.restDb = restDb;
|
|
26
29
|
this.embeddingFn = embeddingFn;
|
|
27
30
|
this.splitter = new RecursiveCharacterSplitter();
|
|
28
31
|
}
|
|
29
32
|
async ingest(req) {
|
|
30
33
|
const docId = generateId('rdoc');
|
|
31
34
|
const now = new Date();
|
|
32
|
-
// 1. Insert document row with status='processing'
|
|
33
|
-
|
|
35
|
+
// 1. Insert document row with status='processing', guarded by cross-DB ref check.
|
|
36
|
+
// safeVectorInsert validates that workspaceId (= site ID) exists in NeonDB before
|
|
37
|
+
// writing to the Supabase vector store, preventing orphaned RAG documents.
|
|
38
|
+
await safeVectorInsert(this.restDb, async () => this.db.insert(ragDocuments).values({
|
|
34
39
|
id: docId,
|
|
35
40
|
workspaceId: req.workspaceId,
|
|
36
41
|
sourceType: req.sourceType,
|
|
@@ -44,7 +49,7 @@ export class IngestionPipeline {
|
|
|
44
49
|
status: 'processing',
|
|
45
50
|
createdAt: now,
|
|
46
51
|
updatedAt: now,
|
|
47
|
-
});
|
|
52
|
+
}), { siteId: req.workspaceId });
|
|
48
53
|
try {
|
|
49
54
|
// 2. Parse
|
|
50
55
|
const parser = createParser(req.mimeType ?? 'text/plain');
|
package/dist/llm/client.d.ts
CHANGED
|
@@ -12,10 +12,10 @@ export declare function redactSensitiveFields(obj: Record<string, unknown>): Rec
|
|
|
12
12
|
import type { Database } from '@revealui/db/client';
|
|
13
13
|
import type { AuditStore } from '../audit/store.js';
|
|
14
14
|
import type { ProviderHealthMonitor } from './provider-health.js';
|
|
15
|
-
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
|
|
15
|
+
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
|
|
16
16
|
import { type CacheStats, type ResponseCacheOptions } from './response-cache.js';
|
|
17
17
|
import { type SemanticCacheOptions, type SemanticCacheStats } from './semantic-cache.js';
|
|
18
|
-
export type LLMProviderType = 'openai' | 'anthropic' | 'vultr' | 'groq' | 'ollama' | 'huggingface' | 'inference-snaps';
|
|
18
|
+
export type LLMProviderType = 'openai' | 'anthropic' | 'vultr' | 'groq' | 'ollama' | 'bitnet' | 'huggingface' | 'inference-snaps';
|
|
19
19
|
export interface LLMClientConfig {
|
|
20
20
|
provider: LLMProviderType;
|
|
21
21
|
apiKey: string;
|
|
@@ -27,6 +27,15 @@ export interface LLMClientConfig {
|
|
|
27
27
|
apiKeyFn?: () => Promise<string>;
|
|
28
28
|
baseURL?: string;
|
|
29
29
|
model?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Dedicated embedding provider. When set, all embed() calls are routed here
|
|
32
|
+
* instead of the primary provider. Required when the primary provider does not
|
|
33
|
+
* support embeddings (e.g. BitNet).
|
|
34
|
+
*
|
|
35
|
+
* Auto-wired by createLLMClientFromEnv() when BITNET_BASE_URL + OLLAMA_BASE_URL
|
|
36
|
+
* are both set.
|
|
37
|
+
*/
|
|
38
|
+
embedProvider?: LLMProvider;
|
|
30
39
|
temperature?: number;
|
|
31
40
|
maxTokens?: number;
|
|
32
41
|
fallbackProvider?: LLMProviderType;
|
|
@@ -50,6 +59,7 @@ export interface LLMClientConfig {
|
|
|
50
59
|
export declare class LLMClient {
|
|
51
60
|
private provider;
|
|
52
61
|
private fallbackProvider?;
|
|
62
|
+
private embedProviderOverride?;
|
|
53
63
|
private config;
|
|
54
64
|
private rateLimitState;
|
|
55
65
|
private responseCache?;
|
package/dist/llm/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAY3F;AAID,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAInD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAY3F;AAID,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAInD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAGjE,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,OAAO,EACR,MAAM,qBAAqB,CAAA;AAS5B,OAAO,EAAE,KAAK,UAAU,EAAiB,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/F,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAA;AAG5B,MAAM,MAAM,eAAe,GACvB,QAAQ,GACR,WAAW,GACX,OAAO,GACP,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,aAAa,GACb,iBAAiB,CAAA;AAErB,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,eAAe,CAAA;IACzB,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,WAAW,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,eAAe,CAAA;IAClC,SAAS,CAAC,EAAE;QACV,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;KACxB,CAAA;IACD,oFAAoF;IACpF,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,wEAAwE;IACxE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,6BAA6B;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,6BAA6B;IAC7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,0EAA0E;IAC1E,aAAa,CAAC,EAAE,qBAAqB,CAAA;CACtC;AAQD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,gBAAgB,CAAC,CAAa;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAAa;IAC3C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,aAAa,CAAC,CAAe;IACrC,OAAO,CAAC,aAAa,CAAC,CAAe;IACrC,OAAO,CAAC,aAAa,CAAC,CAAuB;IAC7C,wFAAwF;IACxF,OAAO,CAAC,aAAa,CAAQ;gBAEjB,MAAM,EAAE,eAAe;IA8CnC,OAAO,CAAC,cAAc;IAkCtB;;;OAGG;YACW,uBAAuB;IAmBrC,OAAO,CAAC,cAAc;IAoCtB,OAAO,CAAC,aAAa;IAMf,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAmHzE,KAAK,CACT,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;IA2B5B,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAAC;IA0BvF;;;OAGG;IACH,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE;IAIlF;;OAEG;IACH,gBAAgB,IAAI,qBAAqB,GAAG,SAAS;IAIrD;;;;OAIG;IACH,qBAAqB,IAAI,UAAU,GAAG,SAAS;IAI/C;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;;;OAIG;IACH,qBAAqB,IAAI,kBAAkB,GAAG,SAAS;IAIvD;;OAEG;IACH,kBAAkB,IAAI,IAAI;CAG3B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,IAAI,SAAS,CAgGlD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,QAAQ,EACZ,UAAU,CAAC,EAAE,UAAU,GACtB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAiD3B"}
|
package/dist/llm/client.js
CHANGED
|
@@ -43,6 +43,7 @@ import { decryptApiKey } from '@revealui/db/crypto';
|
|
|
43
43
|
import { tenantProviderConfigs, userApiKeys } from '@revealui/db/schema';
|
|
44
44
|
import { and, eq } from 'drizzle-orm';
|
|
45
45
|
import { AnthropicProvider } from './providers/anthropic.js';
|
|
46
|
+
import { BitnetProvider } from './providers/bitnet.js';
|
|
46
47
|
import { GroqProvider } from './providers/groq.js';
|
|
47
48
|
import { InferenceSnapsProvider, } from './providers/inference-snaps.js';
|
|
48
49
|
import { OllamaProvider } from './providers/ollama.js';
|
|
@@ -54,6 +55,7 @@ import { estimateRequest as _estimateRequestTokens } from './token-counter.js';
|
|
|
54
55
|
export class LLMClient {
|
|
55
56
|
provider;
|
|
56
57
|
fallbackProvider;
|
|
58
|
+
embedProviderOverride;
|
|
57
59
|
config;
|
|
58
60
|
rateLimitState;
|
|
59
61
|
responseCache;
|
|
@@ -79,6 +81,8 @@ export class LLMClient {
|
|
|
79
81
|
}
|
|
80
82
|
// Wire health monitor if provided
|
|
81
83
|
this.healthMonitor = config.healthMonitor;
|
|
84
|
+
// Wire dedicated embed provider if supplied (e.g. Ollama when BitNet is primary)
|
|
85
|
+
this.embedProviderOverride = config.embedProvider;
|
|
82
86
|
// Create primary provider
|
|
83
87
|
this.provider = this.createProvider(config.provider, {
|
|
84
88
|
apiKey: config.apiKey,
|
|
@@ -113,6 +117,8 @@ export class LLMClient {
|
|
|
113
117
|
return new GroqProvider(config);
|
|
114
118
|
case 'ollama':
|
|
115
119
|
return new OllamaProvider(config);
|
|
120
|
+
case 'bitnet':
|
|
121
|
+
return new BitnetProvider(config);
|
|
116
122
|
case 'inference-snaps':
|
|
117
123
|
return new InferenceSnapsProvider(config);
|
|
118
124
|
default:
|
|
@@ -276,13 +282,15 @@ export class LLMClient {
|
|
|
276
282
|
if (!this.checkRateLimit()) {
|
|
277
283
|
throw new Error('Rate limit exceeded');
|
|
278
284
|
}
|
|
285
|
+
// Use dedicated embed provider if one was configured (e.g. Ollama when BitNet is primary)
|
|
286
|
+
const embedProvider = this.embedProviderOverride ?? this.provider;
|
|
279
287
|
try {
|
|
280
288
|
this.recordRequest();
|
|
281
|
-
return await
|
|
289
|
+
return await embedProvider.embed(text, options);
|
|
282
290
|
}
|
|
283
291
|
catch (error) {
|
|
284
|
-
// Try fallback if available
|
|
285
|
-
if (this.fallbackProvider) {
|
|
292
|
+
// Try fallback if available (only when using the primary provider path)
|
|
293
|
+
if (!this.embedProviderOverride && this.fallbackProvider) {
|
|
286
294
|
try {
|
|
287
295
|
return await this.fallbackProvider.embed(text, options);
|
|
288
296
|
}
|
|
@@ -383,6 +391,9 @@ export function createLLMClientFromEnv() {
|
|
|
383
391
|
else if (process.env.INFERENCE_SNAPS_BASE_URL) {
|
|
384
392
|
provider = 'inference-snaps';
|
|
385
393
|
}
|
|
394
|
+
else if (process.env.BITNET_BASE_URL) {
|
|
395
|
+
provider = 'bitnet';
|
|
396
|
+
}
|
|
386
397
|
else if (process.env.GROQ_API_KEY) {
|
|
387
398
|
provider = 'groq';
|
|
388
399
|
}
|
|
@@ -395,9 +406,10 @@ export function createLLMClientFromEnv() {
|
|
|
395
406
|
else {
|
|
396
407
|
// No provider configured — throw a clear error. OpenAI is intentionally excluded from
|
|
397
408
|
// auto-detection (no revenue yet). Set LLM_PROVIDER=openai explicitly if needed.
|
|
398
|
-
throw new Error('No LLM provider configured. Set one of:
|
|
399
|
-
'
|
|
400
|
-
'
|
|
409
|
+
throw new Error('No LLM provider configured. Set one of: BITNET_BASE_URL (local BitNet), ' +
|
|
410
|
+
'INFERENCE_SNAPS_BASE_URL (local snap), GROQ_API_KEY (recommended cloud), ' +
|
|
411
|
+
'OLLAMA_BASE_URL (local Ollama), or ANTHROPIC_API_KEY. ' +
|
|
412
|
+
'Alternatively, set LLM_PROVIDER explicitly.');
|
|
401
413
|
}
|
|
402
414
|
let apiKey;
|
|
403
415
|
let baseURL;
|
|
@@ -428,6 +440,11 @@ export function createLLMClientFromEnv() {
|
|
|
428
440
|
baseURL = process.env.OLLAMA_BASE_URL;
|
|
429
441
|
defaultModel = 'llama3.2:3b';
|
|
430
442
|
}
|
|
443
|
+
else if (provider === 'bitnet') {
|
|
444
|
+
apiKey = 'bitnet'; // llama-server ignores the API key
|
|
445
|
+
baseURL = process.env.BITNET_BASE_URL;
|
|
446
|
+
defaultModel = 'bitnet-b1.58-2B-4T';
|
|
447
|
+
}
|
|
431
448
|
else if (provider === 'inference-snaps') {
|
|
432
449
|
apiKey = 'inference-snaps'; // inference-snaps ignores the API key
|
|
433
450
|
baseURL = process.env.INFERENCE_SNAPS_BASE_URL;
|
|
@@ -437,6 +454,17 @@ export function createLLMClientFromEnv() {
|
|
|
437
454
|
throw new Error(`API key not found for provider "${provider}". Set the corresponding env var ` +
|
|
438
455
|
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL, ANTHROPIC_API_KEY, or OPENAI_API_KEY).`);
|
|
439
456
|
}
|
|
457
|
+
// When BitNet is the chat provider, auto-wire Ollama as the embed backend.
|
|
458
|
+
// BitNet does not support /v1/embeddings; Ollama (nomic-embed-text) fills that role.
|
|
459
|
+
// If OLLAMA_BASE_URL is not set, embed() will throw with a helpful message.
|
|
460
|
+
let embedProvider;
|
|
461
|
+
if (provider === 'bitnet' && process.env.OLLAMA_BASE_URL) {
|
|
462
|
+
embedProvider = new OllamaProvider({
|
|
463
|
+
apiKey: 'ollama',
|
|
464
|
+
baseURL: process.env.OLLAMA_BASE_URL,
|
|
465
|
+
embedModel: process.env.OLLAMA_EMBED_MODEL ?? 'nomic-embed-text',
|
|
466
|
+
});
|
|
467
|
+
}
|
|
440
468
|
return new LLMClient({
|
|
441
469
|
provider,
|
|
442
470
|
apiKey,
|
|
@@ -449,6 +477,7 @@ export function createLLMClientFromEnv() {
|
|
|
449
477
|
process.env.RESPONSE_CACHE_ENABLED === 'true',
|
|
450
478
|
enableSemanticCache: process.env.LLM_ENABLE_SEMANTIC_CACHE === 'true' ||
|
|
451
479
|
process.env.SEMANTIC_CACHE_ENABLED === 'true',
|
|
480
|
+
embedProvider,
|
|
452
481
|
});
|
|
453
482
|
}
|
|
454
483
|
/**
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BitNet Provider
|
|
3
|
+
*
|
|
4
|
+
* Local inference via BitNet's OpenAI-compatible llama-server (http://localhost:8080/v1).
|
|
5
|
+
* No API key required. Runs entirely on CPU (AVX2). Zero cost, fully offline.
|
|
6
|
+
*
|
|
7
|
+
* Setup: pnpm bitnet:install (clone + compile + download model)
|
|
8
|
+
* Start: pnpm bitnet:serve (start inference server on :8080)
|
|
9
|
+
*
|
|
10
|
+
* Note: BitNet is a generative model only. It does not expose /v1/embeddings.
|
|
11
|
+
* For vector search, use Ollama (nomic-embed-text) or @xenova/transformers.
|
|
12
|
+
*/
|
|
13
|
+
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMProviderConfig, LLMResponse, LLMStreamOptions, Message } from './base.js';
|
|
14
|
+
export interface BitnetProviderConfig extends Omit<LLMProviderConfig, 'apiKey'> {
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
/** Defaults to http://localhost:8080/v1 */
|
|
17
|
+
baseURL?: string;
|
|
18
|
+
/** Chat model. Defaults to bitnet-b1.58-2B-4T — installed by pnpm bitnet:install */
|
|
19
|
+
model?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare class BitnetProvider implements LLMProvider {
|
|
22
|
+
private inner;
|
|
23
|
+
constructor(config: BitnetProviderConfig);
|
|
24
|
+
chat(messages: Message[], options?: LLMChatOptions): Promise<LLMResponse>;
|
|
25
|
+
stream(messages: Message[], options?: LLMStreamOptions): AsyncIterable<LLMChunk>;
|
|
26
|
+
embed(_text: string | string[], _options?: LLMEmbedOptions): Promise<Embedding | Embedding[]>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=bitnet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitnet.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/bitnet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,OAAO,EACR,MAAM,WAAW,CAAA;AAGlB,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,KAAK,CAAgB;gBAEjB,MAAM,EAAE,oBAAoB;IAUxC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAAC;IAIhF,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;CAO9F"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BitNet Provider
|
|
3
|
+
*
|
|
4
|
+
* Local inference via BitNet's OpenAI-compatible llama-server (http://localhost:8080/v1).
|
|
5
|
+
* No API key required. Runs entirely on CPU (AVX2). Zero cost, fully offline.
|
|
6
|
+
*
|
|
7
|
+
* Setup: pnpm bitnet:install (clone + compile + download model)
|
|
8
|
+
* Start: pnpm bitnet:serve (start inference server on :8080)
|
|
9
|
+
*
|
|
10
|
+
* Note: BitNet is a generative model only. It does not expose /v1/embeddings.
|
|
11
|
+
* For vector search, use Ollama (nomic-embed-text) or @xenova/transformers.
|
|
12
|
+
*/
|
|
13
|
+
import { OpenAIProvider } from './openai.js';
|
|
14
|
+
export class BitnetProvider {
|
|
15
|
+
inner;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.inner = new OpenAIProvider({
|
|
18
|
+
...config,
|
|
19
|
+
// llama-server ignores the API key but the OpenAI client requires a non-empty value
|
|
20
|
+
apiKey: config.apiKey ?? 'bitnet',
|
|
21
|
+
baseURL: config.baseURL ?? 'http://localhost:8080/v1',
|
|
22
|
+
model: config.model ?? 'bitnet-b1.58-2B-4T',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
chat(messages, options) {
|
|
26
|
+
return this.inner.chat(messages, options);
|
|
27
|
+
}
|
|
28
|
+
stream(messages, options) {
|
|
29
|
+
return this.inner.stream(messages, options);
|
|
30
|
+
}
|
|
31
|
+
embed(_text, _options) {
|
|
32
|
+
throw new Error('BitNet does not support embeddings. Set OLLAMA_BASE_URL to auto-wire Ollama ' +
|
|
33
|
+
'(nomic-embed-text) as the embed backend, or use @xenova/transformers for ' +
|
|
34
|
+
'fully offline embedding generation.');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-cache.d.ts","sourceRoot":"","sources":["../../src/llm/semantic-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAIZ;IACD,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"semantic-cache.d.ts","sourceRoot":"","sources":["../../src/llm/semantic-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAIZ;IACD,OAAO,CAAC,MAAM,CAA+C;gBAEjD,OAAO,GAAE,oBAAyB;IAiB9C;;;;;OAKG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAwFrE;;;;;;OAMG;IACG,GAAG,CACP,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,GACA,OAAO,CAAC,IAAI,CAAC;IAqChB;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM;IAczC;;OAEG;IACH,QAAQ,IAAI,kBAAkB;IAmB9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAMrC;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE;IACP,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;CACvB,GACA;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACtB,CAUA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAKpF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* @see https://redis.io/blog/what-is-semantic-caching/
|
|
25
25
|
*/
|
|
26
26
|
import { generateEmbedding } from '../embeddings/index.js';
|
|
27
|
-
import { createLogger } from '
|
|
27
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
28
28
|
import { VectorMemoryService } from '../memory/vector/vector-memory-service.js';
|
|
29
29
|
/**
|
|
30
30
|
* Semantic cache that uses vector similarity for intelligent caching
|
|
@@ -50,7 +50,7 @@ export class SemanticCache {
|
|
|
50
50
|
vectorService;
|
|
51
51
|
options;
|
|
52
52
|
stats;
|
|
53
|
-
logger = createLogger('
|
|
53
|
+
logger = createLogger({ component: 'SemanticCache' });
|
|
54
54
|
constructor(options = {}) {
|
|
55
55
|
this.vectorService = new VectorMemoryService();
|
|
56
56
|
this.options = {
|
|
@@ -134,7 +134,7 @@ export class SemanticCache {
|
|
|
134
134
|
}
|
|
135
135
|
catch (error) {
|
|
136
136
|
// Fail gracefully - return undefined on error
|
|
137
|
-
this.logger.error('Semantic cache error
|
|
137
|
+
this.logger.error('Semantic cache error', error instanceof Error ? error : new Error(String(error)));
|
|
138
138
|
if (this.options.enableStats) {
|
|
139
139
|
this.stats.misses++;
|
|
140
140
|
}
|
|
@@ -181,7 +181,7 @@ export class SemanticCache {
|
|
|
181
181
|
}
|
|
182
182
|
catch (error) {
|
|
183
183
|
// Fail gracefully - log error but don't throw
|
|
184
|
-
this.logger.error('Failed to store in semantic cache
|
|
184
|
+
this.logger.error('Failed to store in semantic cache', error instanceof Error ? error : new Error(String(error)));
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
/**
|
package/dist/llm/server.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
export * from './client.js';
|
|
8
8
|
export * from './providers/anthropic.js';
|
|
9
9
|
export * from './providers/base.js';
|
|
10
|
+
export * from './providers/bitnet.js';
|
|
10
11
|
export * from './providers/groq.js';
|
|
11
12
|
export * from './providers/inference-snaps.js';
|
|
12
13
|
export * from './providers/ollama.js';
|
package/dist/llm/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAA;AAG3B,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAA;AAG3B,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
|
package/dist/llm/server.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from './client.js';
|
|
|
9
9
|
// Export provider implementations
|
|
10
10
|
export * from './providers/anthropic.js';
|
|
11
11
|
export * from './providers/base.js';
|
|
12
|
+
export * from './providers/bitnet.js';
|
|
12
13
|
export * from './providers/groq.js';
|
|
13
14
|
export * from './providers/inference-snaps.js';
|
|
14
15
|
export * from './providers/ollama.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crdt-persistence.d.ts","sourceRoot":"","sources":["../../../src/memory/persistence/crdt-persistence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"crdt-persistence.d.ts","sourceRoot":"","sources":["../../../src/memory/persistence/crdt-persistence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAOjF,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,iBAAiB,CAAA;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3B,UAAU,CAAC,EAAE,aAAa,CAAA;CAC3B;AAMD;;;;;;GAMG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEhC;;;;;;;;;OASG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,EACnE,MAAM,GAAE,eAAiC,EACzC,MAAM,GAAE,MAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;IA4ChB;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,IAAI,CAAC;IAiBhF;;;;OAIG;IACG,eAAe,CAAC,SAAS,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrE;;;;;;OAMG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAiBxF;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC;IAuChB;;;;;OAKG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;CAyBvF"}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Supports both state-based (JSONB) and operation-based (operations log) storage.
|
|
6
6
|
*/
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
|
-
import {
|
|
8
|
+
import { and, eq, gte } from 'drizzle-orm';
|
|
9
|
+
import { agentContexts, crdtOperations } from '@revealui/db/schema';
|
|
9
10
|
import { findAgentContextById } from '../utils/sql-helpers.js';
|
|
10
11
|
// =============================================================================
|
|
11
12
|
// CRDT Persistence
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-preferences-manager.d.ts","sourceRoot":"","sources":["../../../src/memory/preferences/user-preferences-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"user-preferences-manager.d.ts","sourceRoot":"","sources":["../../../src/memory/preferences/user-preferences-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAgB3E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,MAAM,CAAiD;IAE/D;;;;;;OAMG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IAcxD;;;;OAIG;IACH,cAAc,IAAI,eAAe;IAIjC;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAsB1D;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,IAAI;IAUlD;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAgBnC;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAiChD;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB;IAM5D;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoF3B;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgF3B;;;;OAIG;IACH,MAAM,IAAI,eAAe,CAAC,eAAe,CAAC;IAI1C;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,eAAe,CAAC,eAAe,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,QAAQ,GACX,sBAAsB;IAMzB;;;;OAIG;IACH,KAAK,IAAI,sBAAsB;IAI/B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* from multiple devices. Uses LWWRegister for last-writer-wins semantics.
|
|
6
6
|
*/
|
|
7
7
|
import { UserPreferencesSchema } from '@revealui/contracts/entities';
|
|
8
|
-
import { eq
|
|
8
|
+
import { eq } from 'drizzle-orm';
|
|
9
|
+
import { users } from '@revealui/db/schema';
|
|
9
10
|
import { LWWRegister } from '../crdt/lww-register.js';
|
|
10
11
|
import { DatabaseConnectionError, DatabaseConstraintError, DatabaseOperationError, NotFoundError, ValidationError, } from '../errors/index.js';
|
|
11
12
|
import { deepClone } from '../utils/deep-clone.js';
|
|
12
|
-
import { createLogger } from '
|
|
13
|
+
import { createLogger } from '@revealui/core/observability/logger';
|
|
13
14
|
import { findUserById } from '../utils/sql-helpers.js';
|
|
14
15
|
// =============================================================================
|
|
15
16
|
// User Preferences Manager
|
|
@@ -36,7 +37,7 @@ export class UserPreferencesManager {
|
|
|
36
37
|
userId;
|
|
37
38
|
nodeId;
|
|
38
39
|
db;
|
|
39
|
-
logger = createLogger('
|
|
40
|
+
logger = createLogger({ component: 'UserPreferences' });
|
|
40
41
|
/**
|
|
41
42
|
* Creates a new UserPreferencesManager.
|
|
42
43
|
*
|
|
@@ -217,18 +218,18 @@ export class UserPreferencesManager {
|
|
|
217
218
|
errorMessage.includes('timeout') ||
|
|
218
219
|
errorMessage.includes('econnrefused') ||
|
|
219
220
|
errorMessage.includes('connect econnrefused')) {
|
|
220
|
-
this.logger.error(`Database connection error loading preferences for user ${this.userId}
|
|
221
|
+
this.logger.error(`Database connection error loading preferences for user ${this.userId}`, error);
|
|
221
222
|
throw new DatabaseConnectionError('Failed to load user preferences', error);
|
|
222
223
|
}
|
|
223
224
|
if (errorMessage.includes('violates') ||
|
|
224
225
|
errorMessage.includes('constraint') ||
|
|
225
226
|
errorMessage.includes('foreign key')) {
|
|
226
|
-
this.logger.error(`Database constraint error loading preferences for user ${this.userId}
|
|
227
|
+
this.logger.error(`Database constraint error loading preferences for user ${this.userId}`, error);
|
|
227
228
|
throw new DatabaseConstraintError('Failed to load user preferences', error);
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
// Generic database operation error
|
|
231
|
-
this.logger.error(`Failed to load preferences for user ${this.userId}
|
|
232
|
+
this.logger.error(`Failed to load preferences for user ${this.userId}`, error instanceof Error ? error : new Error(String(error)));
|
|
232
233
|
throw new DatabaseOperationError('Failed to load user preferences', error instanceof Error ? error : new Error(String(error)));
|
|
233
234
|
}
|
|
234
235
|
}
|
|
@@ -281,19 +282,19 @@ export class UserPreferencesManager {
|
|
|
281
282
|
errorMessage.includes('timeout') ||
|
|
282
283
|
errorMessage.includes('econnrefused') ||
|
|
283
284
|
errorMessage.includes('connect econnrefused')) {
|
|
284
|
-
this.logger.error(`Database connection error saving preferences for user ${this.userId}
|
|
285
|
+
this.logger.error(`Database connection error saving preferences for user ${this.userId}`, error);
|
|
285
286
|
throw new DatabaseConnectionError('Failed to save user preferences', error);
|
|
286
287
|
}
|
|
287
288
|
if (errorMessage.includes('violates') ||
|
|
288
289
|
errorMessage.includes('constraint') ||
|
|
289
290
|
errorMessage.includes('foreign key') ||
|
|
290
291
|
errorMessage.includes('duplicate')) {
|
|
291
|
-
this.logger.error(`Database constraint error saving preferences for user ${this.userId}
|
|
292
|
+
this.logger.error(`Database constraint error saving preferences for user ${this.userId}`, error);
|
|
292
293
|
throw new DatabaseConstraintError('Failed to save user preferences', error);
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
296
|
// Generic database operation error
|
|
296
|
-
this.logger.error(`Failed to save preferences for user ${this.userId}
|
|
297
|
+
this.logger.error(`Failed to save preferences for user ${this.userId}`, error instanceof Error ? error : new Error(String(error)));
|
|
297
298
|
throw new DatabaseOperationError('Failed to save user preferences', error instanceof Error ? error : new Error(String(error)));
|
|
298
299
|
}
|
|
299
300
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"episodic-memory.d.ts","sourceRoot":"","sources":["../../../src/memory/stores/episodic-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAMlG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,EAAE,aAAa,CAAA;CAC7B;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqB;IAE1C;;;;;;;OAOG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,eAAe;IAYvF;;;;;;OAMG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B/C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU5B;;;;;;OAMG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBnD;;;;OAIG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAuBxD;;;;;;;;;;OAUG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBhF;;;;OAIG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAM,GAChD,OAAO,CAAC,WAAW,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"episodic-memory.d.ts","sourceRoot":"","sources":["../../../src/memory/stores/episodic-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAMlG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,EAAE,aAAa,CAAA;CAC7B;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqB;IAE1C;;;;;;;OAOG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,eAAe;IAYvF;;;;;;OAMG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B/C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU5B;;;;;;OAMG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBnD;;;;OAIG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAuBxD;;;;;;;;;;OAUG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBhF;;;;OAIG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAM,GAChD,OAAO,CAAC,WAAW,EAAE,CAAC;IAuBzB;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc;IAO5C;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;;OAIG;IACH,MAAM,IAAI,kBAAkB;IAS5B;;;;;;;OAOG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,kBAAkB,EACxB,EAAE,EAAE,QAAQ,EACZ,WAAW,CAAC,EAAE,eAAe,GAC5B,cAAc;IAOjB;;;;OAIG;IACH,KAAK,IAAI,cAAc;IAIvB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
|
|
@@ -266,10 +266,11 @@ export class EpisodicMemory {
|
|
|
266
266
|
// Return memories sorted by similarity
|
|
267
267
|
return results.map((r) => r.memory);
|
|
268
268
|
}
|
|
269
|
-
catch (
|
|
269
|
+
catch (error) {
|
|
270
270
|
// Embedding generation failed (e.g. embedding service unavailable).
|
|
271
271
|
// Return empty results — do NOT fall back to getAll(), which would dump the
|
|
272
272
|
// entire memory store into agent context regardless of relevance.
|
|
273
|
+
void (error instanceof Error ? error.message : String(error)); // Semantic search failed — return empty results
|
|
273
274
|
return [];
|
|
274
275
|
}
|
|
275
276
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Utility functions
|
|
3
3
|
*/
|
|
4
4
|
export { deepClone } from './deep-clone.js';
|
|
5
|
-
export { createLogger, defaultLogger, type Logger } from './logger.js';
|
|
6
5
|
export { findAgentContextById, findAgentMemoriesByUserId, findAgentMemoryById, findNodeIdMappingByEntity, findNodeIdMappingByHash, findUserById, } from './sql-helpers.js';
|
|
7
6
|
export { estimateObjectSize, hasCircularReference, validateContext, validateContextKey, validateContextSize, validateContextValue, validateObjectDepth, } from './validation.js';
|
|
8
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,YAAY,GACb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAA"}
|
|
@@ -2,6 +2,5 @@
|
|
|
2
2
|
* Utility functions
|
|
3
3
|
*/
|
|
4
4
|
export { deepClone } from './deep-clone.js';
|
|
5
|
-
export { createLogger, defaultLogger } from './logger.js';
|
|
6
5
|
export { findAgentContextById, findAgentMemoriesByUserId, findAgentMemoryById, findNodeIdMappingByEntity, findNodeIdMappingByHash, findUserById, } from './sql-helpers.js';
|
|
7
6
|
export { estimateObjectSize, hasCircularReference, validateContext, validateContextKey, validateContextSize, validateContextValue, validateObjectDepth, } from './validation.js';
|
|
@@ -30,11 +30,14 @@ export interface VectorSearchResult {
|
|
|
30
30
|
*/
|
|
31
31
|
export declare class VectorMemoryService {
|
|
32
32
|
private _db;
|
|
33
|
+
private _restDb;
|
|
33
34
|
/**
|
|
34
35
|
* Lazy-load database client to avoid connection initialization at module import time.
|
|
35
36
|
* This allows the module to be imported in test environments without triggering database connections.
|
|
36
37
|
*/
|
|
37
38
|
private get db();
|
|
39
|
+
/** Lazy-load REST client for cross-DB reference validation. */
|
|
40
|
+
private get restDb();
|
|
38
41
|
/**
|
|
39
42
|
* Search for similar memories using vector similarity.
|
|
40
43
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAM7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAkD;IAC7D,OAAO,CAAC,OAAO,CAAgD;IAE/D;;;OAGG;IACH,OAAO,KAAK,EAAE,GAKb;IAED,+DAA+D;IAC/D,OAAO,KAAK,MAAM,GAKjB;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA2GhC;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG;QAC7D,EAAE,CAAC,EAAE,MAAM,CAAA;KACZ,GACA,OAAO,CAAC,WAAW,CAAC;IA4EvB;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC;IAyEvB;;;;;OAKG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C;;;;;OAKG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CA8CvD"}
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* const memories = await service.searchSimilar(embedding, { siteId: 'site-123', limit: 10 })
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
import { getVectorClient } from '@revealui/db/client';
|
|
15
|
+
import { getRestClient, getVectorClient } from '@revealui/db/client';
|
|
16
|
+
import { safeVectorInsert } from '@revealui/db/validation';
|
|
16
17
|
import { agentMemories } from '@revealui/db/schema/vector';
|
|
17
18
|
import { and, eq, sql } from 'drizzle-orm';
|
|
18
19
|
/**
|
|
@@ -20,6 +21,7 @@ import { and, eq, sql } from 'drizzle-orm';
|
|
|
20
21
|
*/
|
|
21
22
|
export class VectorMemoryService {
|
|
22
23
|
_db = null;
|
|
24
|
+
_restDb = null;
|
|
23
25
|
/**
|
|
24
26
|
* Lazy-load database client to avoid connection initialization at module import time.
|
|
25
27
|
* This allows the module to be imported in test environments without triggering database connections.
|
|
@@ -30,6 +32,13 @@ export class VectorMemoryService {
|
|
|
30
32
|
}
|
|
31
33
|
return this._db;
|
|
32
34
|
}
|
|
35
|
+
/** Lazy-load REST client for cross-DB reference validation. */
|
|
36
|
+
get restDb() {
|
|
37
|
+
if (!this._restDb) {
|
|
38
|
+
this._restDb = getRestClient();
|
|
39
|
+
}
|
|
40
|
+
return this._restDb;
|
|
41
|
+
}
|
|
33
42
|
/**
|
|
34
43
|
* Search for similar memories using vector similarity.
|
|
35
44
|
*
|
|
@@ -146,12 +155,16 @@ export class VectorMemoryService {
|
|
|
146
155
|
* @returns Created memory with generated id and timestamps
|
|
147
156
|
*/
|
|
148
157
|
async create(memory) {
|
|
149
|
-
const id = memory.id ||
|
|
158
|
+
const id = memory.id || crypto.randomUUID();
|
|
150
159
|
const now = new Date();
|
|
151
160
|
// Pass embedding vector directly - Drizzle's vector type will handle conversion
|
|
152
161
|
// The vector custom type has toDriver() that converts number[] to string format
|
|
153
162
|
const embeddingVector = memory.embedding?.vector || null;
|
|
154
|
-
const
|
|
163
|
+
const siteId = memory.metadata?.siteId;
|
|
164
|
+
if (!siteId) {
|
|
165
|
+
throw new Error('siteId is required to create an agent memory');
|
|
166
|
+
}
|
|
167
|
+
const result = await safeVectorInsert(this.restDb, async () => this.db
|
|
155
168
|
.insert(agentMemories)
|
|
156
169
|
.values({
|
|
157
170
|
id,
|
|
@@ -167,12 +180,12 @@ export class VectorMemoryService {
|
|
|
167
180
|
verified: memory.verified,
|
|
168
181
|
verifiedBy: null, // Can be set via update
|
|
169
182
|
verifiedAt: null,
|
|
170
|
-
siteId
|
|
183
|
+
siteId,
|
|
171
184
|
agentId: memory.metadata?.custom?.agentId || null,
|
|
172
185
|
createdAt: now,
|
|
173
186
|
expiresAt: memory.metadata?.expiresAt ? new Date(memory.metadata.expiresAt) : null,
|
|
174
187
|
})
|
|
175
|
-
.returning();
|
|
188
|
+
.returning(), { siteId: siteId ?? undefined });
|
|
176
189
|
const row = result[0];
|
|
177
190
|
if (!row) {
|
|
178
191
|
throw new Error('Failed to create memory');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/github-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"github-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/github-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAaxC;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CA+B9D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,CA8D/F;AA2DD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAS5B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAY3E"}
|
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Install skills from GitHub repositories.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
7
|
import * as fs from 'node:fs';
|
|
8
8
|
import * as path from 'node:path';
|
|
9
9
|
import { promisify } from 'node:util';
|
|
10
10
|
import { parseSkillMd } from '../parser/index.js';
|
|
11
|
-
const
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
/** Validate shell-unsafe characters in git arguments (R4-C1 fix) */
|
|
13
|
+
const SAFE_GIT_ARG = /^[a-zA-Z0-9._\-/]+$/;
|
|
14
|
+
function validateGitArg(value, name) {
|
|
15
|
+
if (!SAFE_GIT_ARG.test(value)) {
|
|
16
|
+
throw new Error(`Invalid ${name}: "${value}". Only alphanumeric, dots, hyphens, underscores, and slashes allowed.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
12
19
|
/**
|
|
13
20
|
* Parse a GitHub source string into components.
|
|
14
21
|
*
|
|
@@ -109,19 +116,17 @@ export async function loadFromGitHub(source, options) {
|
|
|
109
116
|
* Perform a sparse checkout for a specific path.
|
|
110
117
|
*/
|
|
111
118
|
async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
112
|
-
|
|
119
|
+
validateGitArg(subPath, 'subPath');
|
|
120
|
+
if (ref)
|
|
121
|
+
validateGitArg(ref, 'ref');
|
|
113
122
|
const tempDir = `${targetPath}.tmp`;
|
|
114
123
|
try {
|
|
115
|
-
|
|
116
|
-
await
|
|
117
|
-
// Configure sparse checkout
|
|
118
|
-
await execAsync(`git -C ${tempDir} sparse-checkout set ${subPath}`);
|
|
119
|
-
// Checkout specific ref if provided
|
|
124
|
+
await execFileAsync('git', ['clone', '--depth', '1', '--filter=blob:none', '--sparse', repoUrl, tempDir]);
|
|
125
|
+
await execFileAsync('git', ['-C', tempDir, 'sparse-checkout', 'set', subPath]);
|
|
120
126
|
if (ref) {
|
|
121
|
-
await
|
|
122
|
-
await
|
|
127
|
+
await execFileAsync('git', ['-C', tempDir, 'fetch', '--depth', '1', 'origin', ref]);
|
|
128
|
+
await execFileAsync('git', ['-C', tempDir, 'checkout', ref]);
|
|
123
129
|
}
|
|
124
|
-
// Move the skill directory to target
|
|
125
130
|
const sourcePath = path.join(tempDir, subPath);
|
|
126
131
|
if (!fs.existsSync(sourcePath)) {
|
|
127
132
|
throw new Error(`Path "${subPath}" not found in repository`);
|
|
@@ -129,7 +134,6 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
|
129
134
|
fs.renameSync(sourcePath, targetPath);
|
|
130
135
|
}
|
|
131
136
|
finally {
|
|
132
|
-
// Clean up temp directory
|
|
133
137
|
if (fs.existsSync(tempDir)) {
|
|
134
138
|
fs.rmSync(tempDir, { recursive: true });
|
|
135
139
|
}
|
|
@@ -139,8 +143,14 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
|
139
143
|
* Perform a full shallow clone.
|
|
140
144
|
*/
|
|
141
145
|
async function fullClone(repoUrl, targetPath, ref) {
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
if (ref)
|
|
147
|
+
validateGitArg(ref, 'ref');
|
|
148
|
+
const args = ['clone', '--depth', '1'];
|
|
149
|
+
if (ref) {
|
|
150
|
+
args.push('--branch', ref);
|
|
151
|
+
}
|
|
152
|
+
args.push(repoUrl, targetPath);
|
|
153
|
+
await execFileAsync('git', args);
|
|
144
154
|
// Remove .git directory to save space
|
|
145
155
|
const gitDir = path.join(targetPath, '.git');
|
|
146
156
|
if (fs.existsSync(gitDir)) {
|
|
@@ -165,9 +175,10 @@ export async function updateFromGitHub(skillName, registry) {
|
|
|
165
175
|
export async function validateGitHubSource(source) {
|
|
166
176
|
try {
|
|
167
177
|
const parsed = parseGitHubSource(source);
|
|
178
|
+
validateGitArg(parsed.owner, 'owner');
|
|
179
|
+
validateGitArg(parsed.repo, 'repo');
|
|
168
180
|
const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
169
|
-
|
|
170
|
-
await execAsync(`git ls-remote --exit-code ${repoUrl} HEAD`);
|
|
181
|
+
await execFileAsync('git', ['ls-remote', '--exit-code', repoUrl, 'HEAD']);
|
|
171
182
|
return true;
|
|
172
183
|
}
|
|
173
184
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/vercel-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"vercel-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/vercel-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,mBAAmB,CAAA;AAc1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,KAAK,CAAC,CA8EhB;AAwKD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,CAAC,CAwBhB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D"}
|
|
@@ -4,14 +4,21 @@
|
|
|
4
4
|
* Bridge layer to load skills from the Vercel Skills ecosystem (skills.sh)
|
|
5
5
|
* and convert them to RevealUI's format.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
8
|
import * as fs from 'node:fs';
|
|
9
9
|
import * as path from 'node:path';
|
|
10
10
|
import { promisify } from 'node:util';
|
|
11
11
|
import { logger } from '@revealui/core/observability/logger';
|
|
12
12
|
import { parseSkillMd } from '../parser/index.js';
|
|
13
13
|
import { parseVercelSource } from './vercel-types.js';
|
|
14
|
-
const
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
/** Validate shell-unsafe characters in git arguments (R4-C1 fix) */
|
|
16
|
+
const SAFE_GIT_ARG = /^[a-zA-Z0-9._\-/]+$/;
|
|
17
|
+
function validateGitArg(value, name) {
|
|
18
|
+
if (!SAFE_GIT_ARG.test(value)) {
|
|
19
|
+
throw new Error(`Invalid ${name}: "${value}". Only alphanumeric, dots, hyphens, underscores, and slashes allowed.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
15
22
|
/**
|
|
16
23
|
* Load a skill from the Vercel Skills ecosystem.
|
|
17
24
|
*
|
|
@@ -115,9 +122,8 @@ async function installViaVercelCli(source, options) {
|
|
|
115
122
|
if (options.ref) {
|
|
116
123
|
args.push('--ref', options.ref);
|
|
117
124
|
}
|
|
118
|
-
const command = `npx ${args.join(' ')}`;
|
|
119
125
|
try {
|
|
120
|
-
const { stdout, stderr } = await
|
|
126
|
+
const { stdout, stderr } = await execFileAsync('npx', args, {
|
|
121
127
|
cwd: options.dir,
|
|
122
128
|
timeout: 60000, // 60 second timeout
|
|
123
129
|
});
|
|
@@ -191,18 +197,17 @@ async function fallbackGitClone(source, targetPath) {
|
|
|
191
197
|
* Perform a sparse checkout for a specific path.
|
|
192
198
|
*/
|
|
193
199
|
async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
200
|
+
validateGitArg(subPath, 'subPath');
|
|
201
|
+
if (ref)
|
|
202
|
+
validateGitArg(ref, 'ref');
|
|
194
203
|
const tempDir = `${targetPath}.tmp`;
|
|
195
204
|
try {
|
|
196
|
-
|
|
197
|
-
await
|
|
198
|
-
// Configure sparse checkout
|
|
199
|
-
await execAsync(`git -C ${tempDir} sparse-checkout set ${subPath}`);
|
|
200
|
-
// Checkout specific ref if provided
|
|
205
|
+
await execFileAsync('git', ['clone', '--depth', '1', '--filter=blob:none', '--sparse', repoUrl, tempDir]);
|
|
206
|
+
await execFileAsync('git', ['-C', tempDir, 'sparse-checkout', 'set', subPath]);
|
|
201
207
|
if (ref) {
|
|
202
|
-
await
|
|
203
|
-
await
|
|
208
|
+
await execFileAsync('git', ['-C', tempDir, 'fetch', '--depth', '1', 'origin', ref]);
|
|
209
|
+
await execFileAsync('git', ['-C', tempDir, 'checkout', ref]);
|
|
204
210
|
}
|
|
205
|
-
// Move the skill directory to target
|
|
206
211
|
const sourcePath = path.join(tempDir, subPath);
|
|
207
212
|
if (!fs.existsSync(sourcePath)) {
|
|
208
213
|
throw new Error(`Path "${subPath}" not found in repository`);
|
|
@@ -210,7 +215,6 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
|
210
215
|
fs.renameSync(sourcePath, targetPath);
|
|
211
216
|
}
|
|
212
217
|
finally {
|
|
213
|
-
// Clean up temp directory
|
|
214
218
|
if (fs.existsSync(tempDir)) {
|
|
215
219
|
fs.rmSync(tempDir, { recursive: true });
|
|
216
220
|
}
|
|
@@ -220,8 +224,14 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
|
|
|
220
224
|
* Perform a full shallow clone.
|
|
221
225
|
*/
|
|
222
226
|
async function fullClone(repoUrl, targetPath, ref) {
|
|
223
|
-
|
|
224
|
-
|
|
227
|
+
if (ref)
|
|
228
|
+
validateGitArg(ref, 'ref');
|
|
229
|
+
const args = ['clone', '--depth', '1'];
|
|
230
|
+
if (ref) {
|
|
231
|
+
args.push('--branch', ref);
|
|
232
|
+
}
|
|
233
|
+
args.push(repoUrl, targetPath);
|
|
234
|
+
await execFileAsync('git', args);
|
|
225
235
|
// Remove .git directory to save space
|
|
226
236
|
const gitDir = path.join(targetPath, '.git');
|
|
227
237
|
if (fs.existsSync(gitDir)) {
|
|
@@ -304,7 +314,7 @@ export async function updateVercelSkill(skillName, registry) {
|
|
|
304
314
|
*/
|
|
305
315
|
export async function isVercelCliAvailable() {
|
|
306
316
|
try {
|
|
307
|
-
await
|
|
317
|
+
await execFileAsync('npx', ['skills', '--version'], { timeout: 5000 });
|
|
308
318
|
return true;
|
|
309
319
|
}
|
|
310
320
|
catch {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/ai",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AI system for RevealUI - memory, LLM, orchestration, and tools",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "[Pro] AI system for RevealUI - memory, LLM, orchestration, and tools",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
7
7
|
"ai",
|
|
@@ -16,13 +16,18 @@
|
|
|
16
16
|
"tools",
|
|
17
17
|
"vector-search"
|
|
18
18
|
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/RevealUIStudio/revealui.git",
|
|
22
|
+
"directory": "packages/ai"
|
|
23
|
+
},
|
|
19
24
|
"license": "SEE LICENSE IN ../../LICENSE.commercial",
|
|
20
25
|
"dependencies": {
|
|
21
26
|
"lru-cache": "^11.2.5",
|
|
22
27
|
"zod": "^4.3.5",
|
|
23
|
-
"@revealui/db": "
|
|
24
|
-
"@revealui/core": "0.
|
|
25
|
-
"@revealui/contracts": "1.
|
|
28
|
+
"@revealui/db": "0.3.0",
|
|
29
|
+
"@revealui/core": "0.3.0",
|
|
30
|
+
"@revealui/contracts": "1.3.0"
|
|
26
31
|
},
|
|
27
32
|
"devDependencies": {
|
|
28
33
|
"@testing-library/react": "^16.3.2",
|
|
@@ -116,24 +121,26 @@
|
|
|
116
121
|
"files": [
|
|
117
122
|
"dist"
|
|
118
123
|
],
|
|
124
|
+
"funding": {
|
|
125
|
+
"type": "commercial",
|
|
126
|
+
"url": "https://revealui.com/pro"
|
|
127
|
+
},
|
|
119
128
|
"main": "./dist/index.js",
|
|
120
129
|
"module": "./dist/index.js",
|
|
121
130
|
"peerDependencies": {
|
|
122
131
|
"drizzle-orm": "^0.45.1",
|
|
123
132
|
"react": "^18.0.0 || ^19.0.0"
|
|
124
133
|
},
|
|
125
|
-
"type": "module",
|
|
126
|
-
"types": "./dist/index.d.ts",
|
|
127
134
|
"publishConfig": {
|
|
128
|
-
"registry": "https://registry.npmjs.org",
|
|
129
135
|
"access": "public"
|
|
130
136
|
},
|
|
137
|
+
"type": "module",
|
|
138
|
+
"types": "./dist/index.d.ts",
|
|
131
139
|
"scripts": {
|
|
132
140
|
"build": "tsc",
|
|
133
141
|
"clean": "rm -rf dist",
|
|
134
142
|
"dev": "tsc --watch",
|
|
135
143
|
"lint": "biome check .",
|
|
136
|
-
"lint:eslint": "eslint .",
|
|
137
144
|
"test": "vitest run",
|
|
138
145
|
"test:coverage": "vitest run --coverage",
|
|
139
146
|
"test:integration": "vitest run --root . --config vitest.integration.config.ts",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple Logger Utility
|
|
3
|
-
*
|
|
4
|
-
* Provides a minimal logging interface that can be easily replaced
|
|
5
|
-
* with a proper logging service later. Respects environment and log levels.
|
|
6
|
-
*/
|
|
7
|
-
export interface Logger {
|
|
8
|
-
info: (...args: unknown[]) => void;
|
|
9
|
-
warn: (...args: unknown[]) => void;
|
|
10
|
-
error: (...args: unknown[]) => void;
|
|
11
|
-
debug: (...args: unknown[]) => void;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Creates a logger instance with optional prefix
|
|
15
|
-
*/
|
|
16
|
-
export declare function createLogger(prefix?: string): Logger;
|
|
17
|
-
/**
|
|
18
|
-
* Default logger instance
|
|
19
|
-
*/
|
|
20
|
-
export declare const defaultLogger: Logger;
|
|
21
|
-
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AA0DD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAqC,CAAA"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple Logger Utility
|
|
3
|
-
*
|
|
4
|
-
* Provides a minimal logging interface that can be easily replaced
|
|
5
|
-
* with a proper logging service later. Respects environment and log levels.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Environment-aware logger implementation
|
|
9
|
-
* Only logs when appropriate for the environment and log level
|
|
10
|
-
*/
|
|
11
|
-
class SimpleLogger {
|
|
12
|
-
prefix;
|
|
13
|
-
minLevel;
|
|
14
|
-
isProduction;
|
|
15
|
-
constructor(prefix = '[Memory]') {
|
|
16
|
-
this.prefix = prefix;
|
|
17
|
-
this.isProduction = process.env.NODE_ENV === 'production';
|
|
18
|
-
this.minLevel = process.env.LOG_LEVEL || (this.isProduction ? 'warn' : 'debug');
|
|
19
|
-
}
|
|
20
|
-
shouldLog(level) {
|
|
21
|
-
// Never log debug or info in production
|
|
22
|
-
if (this.isProduction && (level === 'debug' || level === 'info')) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
const levels = ['debug', 'info', 'warn', 'error'];
|
|
26
|
-
return levels.indexOf(level) >= levels.indexOf(this.minLevel);
|
|
27
|
-
}
|
|
28
|
-
info(...args) {
|
|
29
|
-
// Info logs are never shown in production
|
|
30
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
31
|
-
console.log(this.prefix, ...args);
|
|
32
|
-
}
|
|
33
|
-
// In production: complete no-op
|
|
34
|
-
}
|
|
35
|
-
warn(...args) {
|
|
36
|
-
// Warning logs are never shown in production
|
|
37
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
38
|
-
console.warn(this.prefix, ...args);
|
|
39
|
-
}
|
|
40
|
-
// In production: complete no-op
|
|
41
|
-
}
|
|
42
|
-
error(...args) {
|
|
43
|
-
if (this.shouldLog('error')) {
|
|
44
|
-
console.error(this.prefix, ...args);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
debug(...args) {
|
|
48
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
49
|
-
console.debug(this.prefix, ...args);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Creates a logger instance with optional prefix
|
|
55
|
-
*/
|
|
56
|
-
export function createLogger(prefix) {
|
|
57
|
-
return new SimpleLogger(prefix);
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Default logger instance
|
|
61
|
-
*/
|
|
62
|
-
export const defaultLogger = new SimpleLogger('[Memory]');
|