@denizsvnc/ai-rag-engine 0.0.0-stage → 2.2.1
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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +167 -2
- package/dist/adapters/cache/index.d.ts +1 -0
- package/dist/adapters/cache/redis-cache.adapter.d.ts +49 -0
- package/dist/adapters/faq/local-faq.adapter.d.ts +29 -0
- package/dist/adapters/faq/url-faq.adapter.d.ts +14 -0
- package/dist/adapters/llm/custom.adapter.d.ts +42 -0
- package/dist/adapters/llm/fallback.adapter.d.ts +10 -0
- package/dist/adapters/llm/gemini.adapter.d.ts +9 -0
- package/dist/adapters/llm/ollama.adapter.d.ts +30 -0
- package/dist/adapters/llm/openai.adapter.d.ts +10 -0
- package/dist/adapters/llm/openrouter.adapter.d.ts +6 -0
- package/dist/adapters/llm/tiered.adapter.d.ts +22 -0
- package/dist/adapters/rules/static-rules.adapter.d.ts +6 -0
- package/dist/adapters/vector/memory-vector.adapter.d.ts +33 -0
- package/dist/adapters/vector/postgres-vector.adapter.d.ts +51 -0
- package/dist/api/auth.d.ts +47 -0
- package/dist/api/middleware.d.ts +3 -0
- package/dist/api/rate-limit.d.ts +8 -0
- package/dist/api/routes.d.ts +9 -0
- package/dist/api/server.d.ts +1 -0
- package/dist/api/server.js +4433 -0
- package/dist/config/default.d.ts +22 -0
- package/dist/config/ingestion-runtime.d.ts +11 -0
- package/dist/core/cache-manager.d.ts +29 -0
- package/dist/core/engine.d.ts +75 -0
- package/dist/core/ingestion/ingestion-worker.d.ts +19 -0
- package/dist/core/ingestion/postgres-ingestion-store.d.ts +56 -0
- package/dist/core/ingestion/queued-ingestion.service.d.ts +35 -0
- package/dist/core/metrics/prometheus-exporter.d.ts +12 -0
- package/dist/core/metrics/rag-evaluator.d.ts +63 -0
- package/dist/core/metrics/token-tracker.d.ts +69 -0
- package/dist/core/prompt-builder.d.ts +20 -0
- package/dist/core/queue/bullmq-queue.d.ts +39 -0
- package/dist/core/queue/in-memory-queue.d.ts +24 -0
- package/dist/core/queue/job-queue.interface.d.ts +22 -0
- package/dist/core/queue/queue-factory.d.ts +12 -0
- package/dist/core/security/confirmation.d.ts +64 -0
- package/dist/core/security/injection-detector.d.ts +25 -0
- package/dist/core/security/nonce-store.d.ts +21 -0
- package/dist/core/security/pii-guard.d.ts +38 -0
- package/dist/core/security/sanitizer.d.ts +23 -0
- package/dist/core/security/secrets.d.ts +2 -0
- package/dist/core/security/security-guard.d.ts +18 -0
- package/dist/core/security/security.types.d.ts +38 -0
- package/dist/core/sml-engine.d.ts +65 -0
- package/dist/core/tool-registry.d.ts +17 -0
- package/dist/core/vector/bm25.d.ts +44 -0
- package/dist/core/vector/hybrid-search.d.ts +15 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +4509 -0
- package/dist/interfaces/cache.interface.d.ts +8 -0
- package/dist/interfaces/engine-config.interface.d.ts +73 -0
- package/dist/interfaces/faq.interface.d.ts +17 -0
- package/dist/interfaces/ingestion.interface.d.ts +14 -0
- package/dist/interfaces/llm.interface.d.ts +22 -0
- package/dist/interfaces/query-context.interface.d.ts +33 -0
- package/dist/interfaces/rules.interface.d.ts +3 -0
- package/dist/interfaces/tool.interface.d.ts +50 -0
- package/dist/interfaces/vector.interface.d.ts +15 -0
- package/dist/scripts/migrate-vector.d.ts +1 -0
- package/dist/scripts/migrate-vector.js +627 -0
- package/dist/services/document-ingestion.service.d.ts +116 -0
- package/dist/utils/http.d.ts +2 -0
- package/dist/utils/math.d.ts +3 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +1787 -0
- package/docs/RELEASING.md +55 -0
- package/docs/USAGE.md +154 -0
- package/package.json +95 -4
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const ENGINE_DEFAULTS: {
|
|
2
|
+
SERVER: {
|
|
3
|
+
PORT: number;
|
|
4
|
+
HOST: string;
|
|
5
|
+
};
|
|
6
|
+
SML: {
|
|
7
|
+
DEFAULT_MODEL: string;
|
|
8
|
+
MATCH_THRESHOLD: number;
|
|
9
|
+
};
|
|
10
|
+
VECTOR_SEARCH: {
|
|
11
|
+
TOP_K: number;
|
|
12
|
+
};
|
|
13
|
+
CACHE: {
|
|
14
|
+
MIN_HITS_TO_PERSIST: number;
|
|
15
|
+
MAX_ITEMS_IN_RAM: number;
|
|
16
|
+
TTL_MS: number;
|
|
17
|
+
};
|
|
18
|
+
PATHS: {
|
|
19
|
+
CACHE_FILE: string;
|
|
20
|
+
TOOLS_REGISTRY: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { PostgresVectorAdapter } from '../adapters/vector/postgres-vector.adapter.js';
|
|
2
|
+
import { QueuedIngestionService } from '../core/ingestion/queued-ingestion.service.js';
|
|
3
|
+
import { IngestionWorker } from '../core/ingestion/ingestion-worker.js';
|
|
4
|
+
export declare function positiveEnv(name: string, fallback: number): number;
|
|
5
|
+
/** API and worker share configuration, never a process-local model/vector store. */
|
|
6
|
+
export declare function createIngestionRuntime(vectors: PostgresVectorAdapter): Promise<{
|
|
7
|
+
backend: QueuedIngestionService;
|
|
8
|
+
worker: IngestionWorker;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function persistentVectorsFromEnv(): PostgresVectorAdapter;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ICacheAdapter } from '../interfaces/cache.interface.js';
|
|
2
|
+
export declare class CacheManager implements ICacheAdapter {
|
|
3
|
+
private filePath;
|
|
4
|
+
private minHitsToPersist;
|
|
5
|
+
private memoryCache;
|
|
6
|
+
private hitCounters;
|
|
7
|
+
private isPersisting;
|
|
8
|
+
private defaultTtlMs;
|
|
9
|
+
constructor(filePath?: string, minHitsToPersist?: number, maxItemsInRAM?: number, defaultTtlMs?: number);
|
|
10
|
+
init(): Promise<void>;
|
|
11
|
+
get(query: string): Promise<any | null>;
|
|
12
|
+
set(query: string, value: any, ttlMs?: number): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Delete a single entry by query key and synchronize disk storage
|
|
15
|
+
*/
|
|
16
|
+
delete(query: string): Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* Invalidate cache entries by exact key or regular expression.
|
|
19
|
+
* Useful for webhook cache eviction when product prices or warehouse inventory change.
|
|
20
|
+
*/
|
|
21
|
+
invalidate(patternOrKey: string | RegExp): Promise<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Evict all cached queries from memory and reset persistent disk storage
|
|
24
|
+
*/
|
|
25
|
+
clear(): Promise<void>;
|
|
26
|
+
has(query: string): boolean;
|
|
27
|
+
size(): number;
|
|
28
|
+
private persistToDisk;
|
|
29
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { EngineConfig, RAGResponse } from '../interfaces/engine-config.interface.js';
|
|
2
|
+
import { TokenTracker, type EngineMetricsSummary } from './metrics/token-tracker.js';
|
|
3
|
+
import { DocumentIngestionService, type DocumentUploadPayload } from '../services/document-ingestion.service.js';
|
|
4
|
+
import type { Job } from './queue/job-queue.interface.js';
|
|
5
|
+
import type { QueryContext } from '../interfaces/query-context.interface.js';
|
|
6
|
+
import type { ToolAuditLog } from '../interfaces/tool.interface.js';
|
|
7
|
+
import type { ICacheAdapter } from '../interfaces/cache.interface.js';
|
|
8
|
+
export declare class RAGEngine {
|
|
9
|
+
private config;
|
|
10
|
+
private confirmationService;
|
|
11
|
+
private cacheManager;
|
|
12
|
+
private smlEngine;
|
|
13
|
+
private toolRegistry;
|
|
14
|
+
private tokenTracker;
|
|
15
|
+
private ingestionService;
|
|
16
|
+
private isInitialized;
|
|
17
|
+
private initPromise;
|
|
18
|
+
private auditLogs;
|
|
19
|
+
private readonly maxAuditLogs;
|
|
20
|
+
constructor(config: EngineConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Records a tool audit log entry into a bounded ring buffer (max 1000 items)
|
|
23
|
+
* and redacts sensitive field values.
|
|
24
|
+
*/
|
|
25
|
+
recordAuditLog(entry: ToolAuditLog): void;
|
|
26
|
+
/**
|
|
27
|
+
* Initializes the engine, loads models into memory, and hydrates persistent caches.
|
|
28
|
+
* Thread-safe: Parallel concurrent invocations await the exact same mutex Promise.
|
|
29
|
+
* Resilient: Resets initPromise on failure so subsequent retries can succeed.
|
|
30
|
+
*/
|
|
31
|
+
init(): Promise<void>;
|
|
32
|
+
registerTool(tool: any): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Executes the query lifecycle:
|
|
35
|
+
* Security Guardrail -> Cache -> SML Routing -> Retrieval -> Untrusted Boundary Framing -> LLM Generation.
|
|
36
|
+
*/
|
|
37
|
+
query(userPrompt: string, context?: QueryContext): Promise<RAGResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* Retrieve structured audit logs for tool executions (supports tenant-level filtering).
|
|
40
|
+
*/
|
|
41
|
+
getAuditLogs(tenantId?: string): ToolAuditLog[];
|
|
42
|
+
/**
|
|
43
|
+
* Clear recorded audit logs.
|
|
44
|
+
*/
|
|
45
|
+
clearAuditLogs(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Invalidate cached queries matching a specific key or regular expression.
|
|
48
|
+
* Call this when catalog prices, warehouse stock, or corporate policies change.
|
|
49
|
+
*/
|
|
50
|
+
invalidateCache(patternOrQuery: string | RegExp): Promise<number>;
|
|
51
|
+
/**
|
|
52
|
+
* Clear all cached queries from RAM and persistent disk storage.
|
|
53
|
+
*/
|
|
54
|
+
clearCache(): Promise<void>;
|
|
55
|
+
getCacheManager(): ICacheAdapter;
|
|
56
|
+
/**
|
|
57
|
+
* Returns cumulative FinOps token usage, cost savings, and latency metrics.
|
|
58
|
+
*/
|
|
59
|
+
getMetrics(): EngineMetricsSummary;
|
|
60
|
+
getTokenTracker(): TokenTracker;
|
|
61
|
+
/**
|
|
62
|
+
* Submits a document (PDF, TXT, MD, CSV, JSON) for background ingestion.
|
|
63
|
+
* Enforces magic byte security and enqueues heavy chunking and PII masking.
|
|
64
|
+
*/
|
|
65
|
+
ingestDocument(payload: DocumentUploadPayload): Promise<{
|
|
66
|
+
jobId: string;
|
|
67
|
+
status: string;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves the status of an ongoing or completed document ingestion job.
|
|
71
|
+
*/
|
|
72
|
+
getIngestionStatus(jobId: string, tenantId?: string): Promise<Job | null>;
|
|
73
|
+
retryIngestion(jobId: string, tenantId: string): Promise<void>;
|
|
74
|
+
getIngestionService(): DocumentIngestionService;
|
|
75
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PostgresVectorAdapter } from '../../adapters/vector/postgres-vector.adapter.js';
|
|
2
|
+
import { QueuedIngestionService } from './queued-ingestion.service.js';
|
|
3
|
+
/** Runs in a separate Node process. No HTTP server or LLM provider is needed here. */
|
|
4
|
+
export declare class IngestionWorker {
|
|
5
|
+
private readonly service;
|
|
6
|
+
private readonly vectors;
|
|
7
|
+
private readonly options;
|
|
8
|
+
private timer;
|
|
9
|
+
private pump;
|
|
10
|
+
private stopped;
|
|
11
|
+
constructor(service: QueuedIngestionService, vectors: Pick<PostgresVectorAdapter, 'replaceDocument'>, options?: {
|
|
12
|
+
pollMs?: number;
|
|
13
|
+
onError?: (error: unknown) => void;
|
|
14
|
+
});
|
|
15
|
+
start(): Promise<void>;
|
|
16
|
+
private tick;
|
|
17
|
+
private process;
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
2
|
+
import type { JobStatus } from '../queue/job-queue.interface.js';
|
|
3
|
+
import type { IngestionSettings } from '../../interfaces/ingestion.interface.js';
|
|
4
|
+
export interface StoredUpload {
|
|
5
|
+
id: string;
|
|
6
|
+
tenantId: string;
|
|
7
|
+
userId: string;
|
|
8
|
+
documentId: string;
|
|
9
|
+
filename: string;
|
|
10
|
+
version: number;
|
|
11
|
+
digest: string;
|
|
12
|
+
settings: IngestionSettings;
|
|
13
|
+
content: Buffer | null;
|
|
14
|
+
status: JobStatus;
|
|
15
|
+
result: Record<string, unknown> | null;
|
|
16
|
+
error: string | null;
|
|
17
|
+
createdAt: number;
|
|
18
|
+
updatedAt: number;
|
|
19
|
+
}
|
|
20
|
+
export declare class IngestionQuotaError extends Error {
|
|
21
|
+
}
|
|
22
|
+
export declare class IngestionConflictError extends Error {
|
|
23
|
+
}
|
|
24
|
+
/** Shared blobs, document revisions and a durable outbox. No process-local file references. */
|
|
25
|
+
export declare class PostgresIngestionStore {
|
|
26
|
+
readonly pool: Pool;
|
|
27
|
+
private readonly table;
|
|
28
|
+
private readonly heads;
|
|
29
|
+
private readonly tableName;
|
|
30
|
+
constructor(pool: Pool, tableName?: string);
|
|
31
|
+
migrate(): Promise<void>;
|
|
32
|
+
ready(): Promise<void>;
|
|
33
|
+
put(input: {
|
|
34
|
+
tenantId: string;
|
|
35
|
+
userId: string;
|
|
36
|
+
documentId: string;
|
|
37
|
+
filename: string;
|
|
38
|
+
content: Buffer;
|
|
39
|
+
settings: IngestionSettings;
|
|
40
|
+
idempotencyKey?: string | undefined;
|
|
41
|
+
}, limits: {
|
|
42
|
+
maxPending: number;
|
|
43
|
+
maxStoredBytes: number;
|
|
44
|
+
}): Promise<StoredUpload>;
|
|
45
|
+
get(id: string, tenantId?: string): Promise<StoredUpload | null>;
|
|
46
|
+
dispatchable(limit?: number): Promise<Array<{
|
|
47
|
+
id: string;
|
|
48
|
+
tenantId: string;
|
|
49
|
+
}>>;
|
|
50
|
+
mark(id: string, status: 'queued' | 'processing' | 'failed', error?: string): Promise<void>;
|
|
51
|
+
complete(id: string, result: Record<string, unknown>): Promise<void>;
|
|
52
|
+
resetFailed(id: string, tenantId: string): Promise<void>;
|
|
53
|
+
expireFailedBlobs(retentionDays?: number): Promise<void>;
|
|
54
|
+
private row;
|
|
55
|
+
private transaction;
|
|
56
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { DocumentUploadPayload } from '../../services/document-ingestion.service.js';
|
|
2
|
+
import type { IIngestionBackend } from '../../interfaces/ingestion.interface.js';
|
|
3
|
+
import type { Job, JobStatus } from '../queue/job-queue.interface.js';
|
|
4
|
+
import type { BullMQJobQueue } from '../queue/bullmq-queue.js';
|
|
5
|
+
import { PostgresIngestionStore } from './postgres-ingestion-store.js';
|
|
6
|
+
export type IngestionQueue = Pick<BullMQJobQueue<IngestionReference>, 'add' | 'getJob' | 'ready' | 'process' | 'retry' | 'close'>;
|
|
7
|
+
export interface IngestionReference {
|
|
8
|
+
id: string;
|
|
9
|
+
tenantId: string;
|
|
10
|
+
}
|
|
11
|
+
export interface QueuedIngestionOptions {
|
|
12
|
+
maxUploadBytes?: number | undefined;
|
|
13
|
+
maxPendingPerTenant?: number | undefined;
|
|
14
|
+
maxStoredBytesPerTenant?: number | undefined;
|
|
15
|
+
chunkSize?: number | undefined;
|
|
16
|
+
chunkOverlap?: number | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** API-side producer. PostgreSQL commits the upload before Redis dispatch; a worker reconciles the outbox. */
|
|
19
|
+
export declare class QueuedIngestionService implements IIngestionBackend {
|
|
20
|
+
readonly store: PostgresIngestionStore;
|
|
21
|
+
readonly queue: IngestionQueue;
|
|
22
|
+
private readonly options;
|
|
23
|
+
private readonly settings;
|
|
24
|
+
private readonly maxBytes;
|
|
25
|
+
constructor(store: PostgresIngestionStore, queue: IngestionQueue, options?: QueuedIngestionOptions);
|
|
26
|
+
submitDocument(payload: DocumentUploadPayload): Promise<{
|
|
27
|
+
jobId: string;
|
|
28
|
+
status: JobStatus;
|
|
29
|
+
}>;
|
|
30
|
+
flushOutbox(): Promise<void>;
|
|
31
|
+
private dispatch;
|
|
32
|
+
getJobStatus(id: string, tenantId?: string): Promise<Job | null>;
|
|
33
|
+
retryJob(id: string, tenantId: string): Promise<void>;
|
|
34
|
+
private bytes;
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EngineMetricsSummary } from './token-tracker.js';
|
|
2
|
+
export interface PrometheusMetricOptions {
|
|
3
|
+
circuitBreakerState?: 'CLOSED' | 'OPEN' | 'HALF_OPEN' | undefined;
|
|
4
|
+
activeCacheSize?: number | undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Formats engine FinOps and runtime telemetry into OpenMetrics / Prometheus exposition format.
|
|
8
|
+
* Can be scraped directly by Prometheus or Datadog agents via GET /api/metrics?format=prometheus.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PrometheusExporter {
|
|
11
|
+
static exportMetrics(summary: EngineMetricsSummary, options?: PrometheusMetricOptions): string;
|
|
12
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface RetrievalEvalResult {
|
|
2
|
+
k: number;
|
|
3
|
+
precisionAtK: number;
|
|
4
|
+
recallAtK: number;
|
|
5
|
+
hitRate: number;
|
|
6
|
+
reciprocalRank: number;
|
|
7
|
+
}
|
|
8
|
+
export interface FaithfulnessEvalResult {
|
|
9
|
+
score: number;
|
|
10
|
+
lexicalGroundingScore: number;
|
|
11
|
+
totalSentences: number;
|
|
12
|
+
groundedSentences: number;
|
|
13
|
+
contradictionsDetected: string[];
|
|
14
|
+
ungroundedClaims: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface FullRAGEvaluationReport {
|
|
17
|
+
retrieval: RetrievalEvalResult;
|
|
18
|
+
faithfulness: FaithfulnessEvalResult;
|
|
19
|
+
overallPass: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Pure TypeScript RAG Evaluation Engine.
|
|
23
|
+
* Evaluates retrieval quality (Precision@K, Recall@K, MRR) and generation faithfulness
|
|
24
|
+
* (hallucination detection) without calling external paid LLMs.
|
|
25
|
+
*/
|
|
26
|
+
export declare class RAGEvaluator {
|
|
27
|
+
/**
|
|
28
|
+
* Measures Retrieval Precision@K:
|
|
29
|
+
* Proportion of retrieved documents in the top-K that are genuinely relevant.
|
|
30
|
+
*/
|
|
31
|
+
static precisionAtK(retrievedIds: string[], relevantIds: string[], k?: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Measures Retrieval Recall@K:
|
|
34
|
+
* Proportion of all existing relevant documents that were captured in the top-K.
|
|
35
|
+
*/
|
|
36
|
+
static recallAtK(retrievedIds: string[], relevantIds: string[], k?: number): number;
|
|
37
|
+
/**
|
|
38
|
+
* Measures Mean Reciprocal Rank (MRR):
|
|
39
|
+
* 1 / rank of the first relevant document retrieved.
|
|
40
|
+
*/
|
|
41
|
+
static reciprocalRank(retrievedIds: string[], relevantIds: string[]): number;
|
|
42
|
+
/**
|
|
43
|
+
* Evaluates Answer Faithfulness / Hallucination Rate:
|
|
44
|
+
* Deconstructs the generated response into discrete sentences/claims,
|
|
45
|
+
* and checks whether the salient terms in each sentence are grounded
|
|
46
|
+
* in the retrieved context documents.
|
|
47
|
+
*/
|
|
48
|
+
static evaluateGrounding(answer: string, context: string | string[]): FaithfulnessEvalResult & {
|
|
49
|
+
grounded: boolean;
|
|
50
|
+
groundingScore: number;
|
|
51
|
+
};
|
|
52
|
+
static evaluateFaithfulness(answer: string, contextTexts: string[]): FaithfulnessEvalResult;
|
|
53
|
+
/**
|
|
54
|
+
* Conducts a full RAG evaluation given a query, generated answer, retrieved docs, and ground truth IDs.
|
|
55
|
+
*/
|
|
56
|
+
static evaluate(options: {
|
|
57
|
+
retrievedIds: string[];
|
|
58
|
+
relevantIds: string[];
|
|
59
|
+
answer: string;
|
|
60
|
+
contextTexts: string[];
|
|
61
|
+
k?: number;
|
|
62
|
+
}): FullRAGEvaluationReport;
|
|
63
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface ResponseMetrics {
|
|
2
|
+
tokensConsumed: number;
|
|
3
|
+
tokensSaved: number;
|
|
4
|
+
estimatedCostSavedUsd: number;
|
|
5
|
+
latencyMs: number;
|
|
6
|
+
source: 'CACHE' | 'FAQ' | 'TOOL_EXECUTION' | 'LLM_RAG' | 'SECURITY_BLOCKED';
|
|
7
|
+
}
|
|
8
|
+
export interface EngineMetricsSummary {
|
|
9
|
+
totalQueries: number;
|
|
10
|
+
cacheHits: number;
|
|
11
|
+
faqHits: number;
|
|
12
|
+
smlToolHits: number;
|
|
13
|
+
llmCalls: number;
|
|
14
|
+
securityBlocked: number;
|
|
15
|
+
zeroTokenRate: string;
|
|
16
|
+
tokensConsumed: number;
|
|
17
|
+
tokensSaved: number;
|
|
18
|
+
estimatedCostUsd: number;
|
|
19
|
+
estimatedCostSavedUsd: number;
|
|
20
|
+
latency: {
|
|
21
|
+
avgMs: number;
|
|
22
|
+
minMs: number;
|
|
23
|
+
maxMs: number;
|
|
24
|
+
p50Ms: number;
|
|
25
|
+
p95Ms: number;
|
|
26
|
+
p99Ms: number;
|
|
27
|
+
sumMs: number;
|
|
28
|
+
count: number;
|
|
29
|
+
buckets: Array<{
|
|
30
|
+
leMs: number;
|
|
31
|
+
count: number;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface TokenTrackerOptions {
|
|
36
|
+
costPerThousandTokensUsd?: number;
|
|
37
|
+
baselineTokensPerQuery?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare class TokenTracker {
|
|
40
|
+
private readonly costPerThousand;
|
|
41
|
+
private readonly baselineTokensPerQuery;
|
|
42
|
+
private totalQueries;
|
|
43
|
+
private cacheHits;
|
|
44
|
+
private faqHits;
|
|
45
|
+
private smlToolHits;
|
|
46
|
+
private llmCalls;
|
|
47
|
+
private securityBlocked;
|
|
48
|
+
private totalTokensConsumed;
|
|
49
|
+
private totalTokensSaved;
|
|
50
|
+
private latencies;
|
|
51
|
+
private latencySumMs;
|
|
52
|
+
private readonly latencyBoundsMs;
|
|
53
|
+
private latencyBucketCounts;
|
|
54
|
+
constructor(options?: TokenTrackerOptions);
|
|
55
|
+
estimateTokens(text: string): number;
|
|
56
|
+
trackQuery(event: {
|
|
57
|
+
source: ResponseMetrics['source'];
|
|
58
|
+
userPrompt: string;
|
|
59
|
+
answer?: string | undefined;
|
|
60
|
+
usage?: {
|
|
61
|
+
promptTokens: number;
|
|
62
|
+
completionTokens: number;
|
|
63
|
+
} | undefined;
|
|
64
|
+
latencyMs: number;
|
|
65
|
+
}): ResponseMetrics;
|
|
66
|
+
recordFullQuery(promptTokens: number, completionTokens: number, latencyMs: number): void;
|
|
67
|
+
getSummary(): EngineMetricsSummary;
|
|
68
|
+
reset(): void;
|
|
69
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { VectorDocument } from '../interfaces/vector.interface.js';
|
|
2
|
+
export interface PromptContext {
|
|
3
|
+
basePrompt?: string | undefined;
|
|
4
|
+
rules?: string[] | undefined;
|
|
5
|
+
documents?: VectorDocument[] | undefined;
|
|
6
|
+
toolResults?: Array<{
|
|
7
|
+
toolName: string;
|
|
8
|
+
result: any;
|
|
9
|
+
}> | undefined;
|
|
10
|
+
caller?: {
|
|
11
|
+
tenantId?: string | undefined;
|
|
12
|
+
userId?: string | undefined;
|
|
13
|
+
roles?: string[] | undefined;
|
|
14
|
+
} | undefined;
|
|
15
|
+
}
|
|
16
|
+
export declare class PromptBuilder {
|
|
17
|
+
static buildSystemPrompt(context: PromptContext): string;
|
|
18
|
+
private static escapeData;
|
|
19
|
+
static formatVisitorPrompt(sanitizedInput: string): string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IJobQueue, Job, JobHandler } from './job-queue.interface.js';
|
|
2
|
+
export interface BullMQQueueOptions {
|
|
3
|
+
queueName?: string | undefined;
|
|
4
|
+
redisUrl?: string | undefined;
|
|
5
|
+
connection?: {
|
|
6
|
+
host?: string | undefined;
|
|
7
|
+
port?: number | undefined;
|
|
8
|
+
password?: string | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
concurrency?: number | undefined;
|
|
11
|
+
globalConcurrency?: number | undefined;
|
|
12
|
+
attempts?: number | undefined;
|
|
13
|
+
backoffMs?: number | undefined;
|
|
14
|
+
lockDurationMs?: number | undefined;
|
|
15
|
+
stalledIntervalMs?: number | undefined;
|
|
16
|
+
onError?: ((error: Error) => void) | undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Redis-backed producer; a consumer starts only when process() is explicitly called. */
|
|
19
|
+
export declare class BullMQJobQueue<TData = any, TResult = any> implements IJobQueue<TData, TResult> {
|
|
20
|
+
private readonly options;
|
|
21
|
+
private readonly queue;
|
|
22
|
+
private readonly producer;
|
|
23
|
+
private consumer;
|
|
24
|
+
private worker;
|
|
25
|
+
private processingType;
|
|
26
|
+
private closed;
|
|
27
|
+
private readonly name;
|
|
28
|
+
private readonly attempts;
|
|
29
|
+
constructor(options?: BullMQQueueOptions);
|
|
30
|
+
private connection;
|
|
31
|
+
private report;
|
|
32
|
+
ready(): Promise<void>;
|
|
33
|
+
add(type: string, data: TData, jobId?: string): Promise<Job<TData, TResult>>;
|
|
34
|
+
getJob(id: string): Promise<Job<TData, TResult> | null>;
|
|
35
|
+
process(type: string, handler: JobHandler<TData, TResult>): Promise<void>;
|
|
36
|
+
retry(id: string): Promise<void>;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
private map;
|
|
39
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IJobQueue, Job, JobHandler } from './job-queue.interface.js';
|
|
2
|
+
export interface InMemoryQueueOptions {
|
|
3
|
+
concurrency?: number | undefined;
|
|
4
|
+
maxPendingJobs?: number | undefined;
|
|
5
|
+
maxRetainedJobs?: number | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare class InMemoryJobQueue<TData = any, TResult = any> implements IJobQueue<TData, TResult> {
|
|
8
|
+
private jobs;
|
|
9
|
+
private handlers;
|
|
10
|
+
private pendingQueue;
|
|
11
|
+
private activeJobsCount;
|
|
12
|
+
private isClosed;
|
|
13
|
+
private readonly maxPendingJobs;
|
|
14
|
+
private drainWaiters;
|
|
15
|
+
private readonly concurrency;
|
|
16
|
+
private readonly maxRetainedJobs;
|
|
17
|
+
constructor(options?: InMemoryQueueOptions);
|
|
18
|
+
add(type: string, data: TData, customJobId?: string): Promise<Job<TData, TResult>>;
|
|
19
|
+
getJob(id: string): Promise<Job<TData, TResult> | null>;
|
|
20
|
+
process(type: string, handler: JobHandler<TData, TResult>): void;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
private dispatch;
|
|
23
|
+
private pruneOldJobs;
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type JobStatus = 'pending' | 'queued' | 'processing' | 'completed' | 'failed';
|
|
2
|
+
export interface Job<TData = any, TResult = any> {
|
|
3
|
+
attemptsMade?: number | undefined;
|
|
4
|
+
maxAttempts?: number | undefined;
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
data: TData;
|
|
8
|
+
status: JobStatus;
|
|
9
|
+
progress: number;
|
|
10
|
+
result?: TResult | undefined;
|
|
11
|
+
error?: string | undefined;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
updatedAt: number;
|
|
14
|
+
completedAt?: number | undefined;
|
|
15
|
+
}
|
|
16
|
+
export type JobHandler<TData = any, TResult = any> = (job: Job<TData, TResult>, updateProgress: (progress: number) => Promise<void> | void) => Promise<TResult>;
|
|
17
|
+
export interface IJobQueue<TData = any, TResult = any> {
|
|
18
|
+
add(type: string, data: TData, jobId?: string): Promise<Job<TData, TResult>>;
|
|
19
|
+
getJob(id: string): Promise<Job<TData, TResult> | null>;
|
|
20
|
+
process(type: string, handler: JobHandler<TData, TResult>): void | Promise<void>;
|
|
21
|
+
close(): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IJobQueue } from './job-queue.interface.js';
|
|
2
|
+
export interface QueueConfig {
|
|
3
|
+
driver?: 'memory' | 'bullmq' | undefined;
|
|
4
|
+
redisUrl?: string | undefined;
|
|
5
|
+
concurrency?: number | undefined;
|
|
6
|
+
queueName?: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates the appropriate job queue based on configuration.
|
|
10
|
+
* Uses zero-dependency InMemoryJobQueue by default, or BullMQJobQueue when Redis is configured.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createJobQueue<TData = any, TResult = any>(config?: QueueConfig): IJobQueue<TData, TResult>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type ConfirmationNonceStore } from './nonce-store.js';
|
|
2
|
+
import type { QueryContext } from '../../interfaces/query-context.interface.js';
|
|
3
|
+
export interface ConfirmationTicketPayload {
|
|
4
|
+
toolName: string;
|
|
5
|
+
argsHash: string;
|
|
6
|
+
tenantId?: string | undefined;
|
|
7
|
+
userId?: string | undefined;
|
|
8
|
+
nonce: string;
|
|
9
|
+
expiresAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface TicketTargetOptions {
|
|
12
|
+
toolName: string;
|
|
13
|
+
args: any;
|
|
14
|
+
tenantId?: string | undefined;
|
|
15
|
+
userId?: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare class ConfirmationService {
|
|
18
|
+
private secret;
|
|
19
|
+
private ttlMs;
|
|
20
|
+
private nonceStore;
|
|
21
|
+
private static readonly memoryStore;
|
|
22
|
+
private static readonly DEFAULT_TTL_MS;
|
|
23
|
+
constructor(secret?: string, ttlMs?: number, nonceStore?: ConfirmationNonceStore);
|
|
24
|
+
/**
|
|
25
|
+
* Instance method to issue a ticket using the configured secret and TTL.
|
|
26
|
+
*/
|
|
27
|
+
issueTicket(options: TicketTargetOptions): string;
|
|
28
|
+
issueTicket(toolName: string, args: any, context?: QueryContext): string;
|
|
29
|
+
/**
|
|
30
|
+
* Instance method to verify a ticket. Throws an Error on verification failure.
|
|
31
|
+
*/
|
|
32
|
+
verifyTicket(ticket: string, options: TicketTargetOptions): Promise<{
|
|
33
|
+
valid: boolean;
|
|
34
|
+
payload?: ConfirmationTicketPayload;
|
|
35
|
+
}>;
|
|
36
|
+
verifyTicket(ticket: string, toolName: string, args: any, context?: QueryContext): Promise<{
|
|
37
|
+
valid: boolean;
|
|
38
|
+
payload?: ConfirmationTicketPayload;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Produces a deterministic canonical JSON string for arguments regardless of key order.
|
|
42
|
+
*/
|
|
43
|
+
static canonicalize(data: any): string;
|
|
44
|
+
/**
|
|
45
|
+
* Computes SHA-256 hash of canonicalized tool arguments.
|
|
46
|
+
*/
|
|
47
|
+
static hashArgs(args: any): string;
|
|
48
|
+
/**
|
|
49
|
+
* Issues a cryptographically signed, short-lived, single-use ticket for a proposed mutating tool invocation.
|
|
50
|
+
*/
|
|
51
|
+
static issueTicket(toolName: string, args: any, context?: QueryContext, ttlMs?: number, secret?: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Validates that the provided confirmation ticket:
|
|
54
|
+
* 1. Possesses a valid HMAC signature.
|
|
55
|
+
* 2. Has not expired.
|
|
56
|
+
* 3. Has not been replayed (single-use enforcement).
|
|
57
|
+
* 4. Matches the exact tool name and SHA-256 hash of the submitted arguments.
|
|
58
|
+
* 5. Matches the caller tenantId/userId if specified.
|
|
59
|
+
*/
|
|
60
|
+
static verifyTicket(ticket: string, toolName: string, args: any, context?: QueryContext, secret?: string, nonceStore?: ConfirmationNonceStore): Promise<{
|
|
61
|
+
valid: boolean;
|
|
62
|
+
error?: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RiskLevel } from './security.types.js';
|
|
2
|
+
export interface DetectionResult {
|
|
3
|
+
isRisk: boolean;
|
|
4
|
+
riskLevel: RiskLevel;
|
|
5
|
+
matchedPatterns: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Scans user inputs for heuristic patterns and known signatures of prompt injection,
|
|
9
|
+
* jailbreaks, role hijacking, and prompt extraction attempts.
|
|
10
|
+
*/
|
|
11
|
+
export declare class InjectionDetector {
|
|
12
|
+
/**
|
|
13
|
+
* High-confidence, critical injection patterns (bilingual: Turkish & English).
|
|
14
|
+
* Any match here immediately triggers HIGH risk classification.
|
|
15
|
+
*/
|
|
16
|
+
private static readonly HIGH_RISK_PATTERNS;
|
|
17
|
+
/**
|
|
18
|
+
* Medium-confidence suspicious patterns.
|
|
19
|
+
*/
|
|
20
|
+
private static readonly MEDIUM_RISK_PATTERNS;
|
|
21
|
+
/**
|
|
22
|
+
* Analyzes input text and classifies prompt injection risk.
|
|
23
|
+
*/
|
|
24
|
+
static detect(input: string, customPatterns?: RegExp[]): DetectionResult;
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Implementations must atomically reserve a nonce until expiry, with no fallback on errors. */
|
|
2
|
+
export interface ConfirmationNonceStore {
|
|
3
|
+
readonly distributed: boolean;
|
|
4
|
+
consume(nonce: string, expiresAt: number): Promise<boolean>;
|
|
5
|
+
}
|
|
6
|
+
export declare class MemoryConfirmationNonceStore implements ConfirmationNonceStore {
|
|
7
|
+
readonly distributed = false;
|
|
8
|
+
private used;
|
|
9
|
+
consume(nonce: string, expiresAt: number): Promise<boolean>;
|
|
10
|
+
}
|
|
11
|
+
export interface ConfirmationRedisClient {
|
|
12
|
+
set(key: string, value: string, px: 'PX', ttl: number, nx: 'NX'): Promise<unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** All instances must use the same Redis database and prefix; nonce keys must not be evicted. */
|
|
15
|
+
export declare class RedisConfirmationNonceStore implements ConfirmationNonceStore {
|
|
16
|
+
private client;
|
|
17
|
+
private prefix;
|
|
18
|
+
readonly distributed = true;
|
|
19
|
+
constructor(client: ConfirmationRedisClient, prefix?: string);
|
|
20
|
+
consume(nonce: string, expiresAt: number): Promise<boolean>;
|
|
21
|
+
}
|