@revealui/ai 0.2.9 → 0.4.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 +200 -26
- package/dist/a2a/handler.d.ts +3 -1
- package/dist/a2a/handler.d.ts.map +1 -1
- package/dist/a2a/handler.js +24 -7
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +5 -1
- package/dist/client/hooks/useAgentStream.d.ts +84 -1
- package/dist/client/hooks/useAgentStream.d.ts.map +1 -1
- package/dist/client/hooks/useAgentStream.js +106 -10
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -15
- package/dist/ingestion/admin-indexer.js +1 -1
- package/dist/ingestion/pipeline.d.ts +1 -1
- package/dist/ingestion/pipeline.d.ts.map +1 -1
- package/dist/llm/client.d.ts +33 -10
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +70 -57
- package/dist/llm/key-validator.d.ts.map +1 -1
- package/dist/llm/key-validator.js +0 -27
- package/dist/llm/providers/inference-snaps.d.ts +7 -5
- package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
- package/dist/llm/providers/inference-snaps.js +7 -5
- package/dist/llm/providers/openai-compat.d.ts +1 -1
- package/dist/llm/providers/openai-compat.js +1 -1
- package/dist/llm/response-cache.d.ts +1 -2
- package/dist/llm/response-cache.d.ts.map +1 -1
- package/dist/llm/response-cache.js +1 -2
- package/dist/llm/server.d.ts +1 -1
- package/dist/llm/server.d.ts.map +1 -1
- package/dist/llm/server.js +3 -1
- package/dist/memory/crdt/lww-register.js +1 -1
- package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -1
- package/dist/memory/preferences/user-preferences-manager.js +1 -1
- package/dist/memory/services/index.d.ts +2 -0
- package/dist/memory/services/index.d.ts.map +1 -1
- package/dist/memory/services/index.js +1 -0
- package/dist/memory/services/reconciliation-service.d.ts +64 -0
- package/dist/memory/services/reconciliation-service.d.ts.map +1 -0
- package/dist/memory/services/reconciliation-service.js +127 -0
- package/dist/memory/stores/working-memory.d.ts.map +1 -1
- package/dist/memory/stores/working-memory.js +1 -1
- package/dist/memory/utils/index.d.ts +1 -2
- package/dist/memory/utils/index.d.ts.map +1 -1
- package/dist/memory/utils/index.js +1 -2
- package/dist/memory/utils/sql-helpers.d.ts +21 -66
- package/dist/memory/utils/sql-helpers.d.ts.map +1 -1
- package/dist/memory/utils/sql-helpers.js +34 -169
- package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
- package/dist/memory/vector/vector-memory-service.js +6 -1
- package/dist/orchestration/runtime.d.ts +30 -1
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +20 -3
- package/dist/orchestration/streaming-runtime.d.ts +48 -1
- package/dist/orchestration/streaming-runtime.d.ts.map +1 -1
- package/dist/orchestration/ticket-agent.d.ts +10 -1
- package/dist/orchestration/ticket-agent.d.ts.map +1 -1
- package/dist/orchestration/ticket-agent.js +11 -2
- package/dist/skills/catalog/vercel-catalog.d.ts.map +1 -1
- package/dist/skills/catalog/vercel-catalog.js +13 -7
- package/dist/tools/mcp-adapter.d.ts +192 -1
- package/dist/tools/mcp-adapter.d.ts.map +1 -1
- package/dist/tools/mcp-adapter.js +434 -1
- package/dist/tools/mcp-elicitation.d.ts +128 -0
- package/dist/tools/mcp-elicitation.d.ts.map +1 -0
- package/dist/tools/mcp-elicitation.js +121 -0
- package/dist/tools/mcp-events.d.ts +270 -0
- package/dist/tools/mcp-events.d.ts.map +1 -0
- package/dist/tools/mcp-events.js +165 -0
- package/dist/tools/mcp-sampling.d.ts +155 -0
- package/dist/tools/mcp-sampling.d.ts.map +1 -0
- package/dist/tools/mcp-sampling.js +171 -0
- package/dist/tools/ticket-tools.d.ts +35 -2
- package/dist/tools/ticket-tools.d.ts.map +1 -1
- package/dist/tools/ticket-tools.js +32 -2
- package/package.json +38 -12
- package/dist/llm/providers/vultr.d.ts +0 -18
- package/dist/llm/providers/vultr.d.ts.map +0 -1
- package/dist/llm/providers/vultr.js +0 -169
- package/dist/memory/utils/deep-clone.d.ts +0 -10
- package/dist/memory/utils/deep-clone.d.ts.map +0 -1
- package/dist/memory/utils/deep-clone.js +0 -9
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAGH,cAAc,gBAAgB,CAAC;AAE/B,cAAc,kBAAkB,CAAC;AAIjC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,sBAAsB,CAAC;AAErC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,oCAAoC,CAAC;AAEnD,cAAc,mBAAmB,CAAC;AAElC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,mBAAmB,CAAC;AAElC,cAAc,sBAAsB,CAAC;AAErC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -45,21 +45,6 @@
|
|
|
45
45
|
*
|
|
46
46
|
* @packageDocumentation
|
|
47
47
|
*/
|
|
48
|
-
import { isFeatureEnabled } from '@revealui/core/features';
|
|
49
|
-
import { logger } from '@revealui/core/observability/logger';
|
|
50
|
-
/**
|
|
51
|
-
* Check if the AI package is licensed for use.
|
|
52
|
-
* Returns false with a warning log if no Pro/Enterprise license is active.
|
|
53
|
-
* Call at application startup to verify licensing.
|
|
54
|
-
*/
|
|
55
|
-
export function checkAiLicense() {
|
|
56
|
-
if (!isFeatureEnabled('ai')) {
|
|
57
|
-
logger.warn('[@revealui/ai] AI features require a Pro or Enterprise license. ' +
|
|
58
|
-
'Visit https://revealui.com/pricing for details.');
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
48
|
// Re-export A2A protocol
|
|
64
49
|
export * from './a2a/index.js';
|
|
65
50
|
// Re-export audit trail
|
|
@@ -74,6 +59,7 @@ export * from './ingestion/index.js';
|
|
|
74
59
|
export * from './llm/client.js';
|
|
75
60
|
export * from './llm/provider-health.js';
|
|
76
61
|
export * from './llm/providers/base.js';
|
|
62
|
+
export * from './llm/providers/inference-snaps.js';
|
|
77
63
|
export * from './llm/providers/openai-compat.js';
|
|
78
64
|
export * from './llm/token-counter.js';
|
|
79
65
|
export * from './llm/workspace-provider-config.js';
|
|
@@ -96,6 +82,9 @@ export * from './tools/base.js';
|
|
|
96
82
|
export * from './tools/deduplicator.js';
|
|
97
83
|
export * from './tools/document-summarizer.js';
|
|
98
84
|
export * from './tools/mcp-adapter.js';
|
|
85
|
+
export * from './tools/mcp-elicitation.js';
|
|
86
|
+
export * from './tools/mcp-events.js';
|
|
87
|
+
export * from './tools/mcp-sampling.js';
|
|
99
88
|
export * from './tools/memory/index.js';
|
|
100
89
|
export * from './tools/registry.js';
|
|
101
90
|
export * from './tools/ticket-tools.js';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { Database } from '@revealui/db/client';
|
|
8
8
|
export interface IngestRequest {
|
|
9
9
|
workspaceId: string;
|
|
10
|
-
sourceType: '
|
|
10
|
+
sourceType: 'admin_collection' | 'url' | 'file' | 'text';
|
|
11
11
|
sourceId?: string;
|
|
12
12
|
sourceCollection?: string;
|
|
13
13
|
title?: string;
|
|
@@ -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,CAAC;AAOpD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,
|
|
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,CAAC;AAOpD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,QAAQ,CAA6B;gBAEjC,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"}
|
package/dist/llm/client.d.ts
CHANGED
|
@@ -3,19 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Single interface for all LLM providers with fallback and rate limiting
|
|
5
5
|
*/
|
|
6
|
-
/**
|
|
7
|
-
* Redact sensitive fields before passing an object to a logger.
|
|
8
|
-
* Replaces API keys, tokens, and authorization headers with `[REDACTED]`.
|
|
9
|
-
* Recurses into nested plain objects; leaves arrays and primitives as-is.
|
|
10
|
-
*/
|
|
11
|
-
export declare function redactSensitiveFields(obj: Record<string, unknown>): Record<string, unknown>;
|
|
12
6
|
import type { Database } from '@revealui/db/client';
|
|
7
|
+
import { CircuitBreaker } from '@revealui/resilience';
|
|
13
8
|
import type { AuditStore } from '../audit/store.js';
|
|
14
9
|
import type { ProviderHealthMonitor } from './provider-health.js';
|
|
15
10
|
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
|
|
16
11
|
import { type CacheStats, type ResponseCacheOptions } from './response-cache.js';
|
|
17
12
|
import { type SemanticCacheOptions, type SemanticCacheStats } from './semantic-cache.js';
|
|
18
|
-
export type LLMProviderType = '
|
|
13
|
+
export type LLMProviderType = 'groq' | 'ollama' | 'huggingface' | 'inference-snaps';
|
|
19
14
|
export interface LLMClientConfig {
|
|
20
15
|
provider: LLMProviderType;
|
|
21
16
|
apiKey: string;
|
|
@@ -52,6 +47,10 @@ export interface LLMClientConfig {
|
|
|
52
47
|
semanticCacheOptions?: SemanticCacheOptions;
|
|
53
48
|
/** Optional health monitor - records latency + error rate per provider */
|
|
54
49
|
healthMonitor?: ProviderHealthMonitor;
|
|
50
|
+
/** Circuit breaker failure threshold before tripping (default: 5) */
|
|
51
|
+
circuitBreakerFailureThreshold?: number;
|
|
52
|
+
/** Circuit breaker reset timeout in ms before half-open probe (default: 30000) */
|
|
53
|
+
circuitBreakerResetTimeout?: number;
|
|
55
54
|
}
|
|
56
55
|
export declare class LLMClient {
|
|
57
56
|
private provider;
|
|
@@ -62,6 +61,8 @@ export declare class LLMClient {
|
|
|
62
61
|
private responseCache?;
|
|
63
62
|
private semanticCache?;
|
|
64
63
|
private healthMonitor?;
|
|
64
|
+
private circuitBreaker;
|
|
65
|
+
private fallbackCircuitBreaker?;
|
|
65
66
|
/** Tracks the last resolved API key so we only recreate the provider when it changes */
|
|
66
67
|
private currentApiKey;
|
|
67
68
|
constructor(config: LLMClientConfig);
|
|
@@ -84,6 +85,21 @@ export declare class LLMClient {
|
|
|
84
85
|
tokens: number;
|
|
85
86
|
estimatedCostUsd: number;
|
|
86
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* Get circuit breaker stats for the primary and fallback providers.
|
|
90
|
+
*/
|
|
91
|
+
getCircuitBreakerStats(): {
|
|
92
|
+
primary: {
|
|
93
|
+
name: string;
|
|
94
|
+
state: string;
|
|
95
|
+
stats: ReturnType<CircuitBreaker['getStats']>;
|
|
96
|
+
};
|
|
97
|
+
fallback?: {
|
|
98
|
+
name: string;
|
|
99
|
+
state: string;
|
|
100
|
+
stats: ReturnType<CircuitBreaker['getStats']>;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
87
103
|
/**
|
|
88
104
|
* Get the provider health monitor if one was configured.
|
|
89
105
|
*/
|
|
@@ -113,13 +129,20 @@ export declare class LLMClient {
|
|
|
113
129
|
* Create an LLM client from environment variables.
|
|
114
130
|
*
|
|
115
131
|
* When LLM_PROVIDER is not set, auto-detects the provider by checking env vars
|
|
116
|
-
* in priority order: INFERENCE_SNAPS → GROQ → OLLAMA.
|
|
132
|
+
* in priority order: INFERENCE_SNAPS → GROQ → OLLAMA. If none are set, defaults
|
|
133
|
+
* to Inference Snaps at http://localhost:9090/v1 (Ubuntu local) and emits a
|
|
134
|
+
* one-line stderr warning so the implicit default is discoverable in logs.
|
|
117
135
|
*
|
|
118
136
|
* All providers use OpenAI-compatible APIs. No proprietary provider SDKs.
|
|
119
137
|
*
|
|
138
|
+
* Canonical Inference Snaps is the reference local provider on Ubuntu — offline,
|
|
139
|
+
* silicon-optimized, no API key required. See `providers/inference-snaps.ts` for
|
|
140
|
+
* install docs (`sudo snap install gemma3`, etc.).
|
|
141
|
+
*
|
|
120
142
|
* Provider defaults:
|
|
121
|
-
*
|
|
122
|
-
*
|
|
143
|
+
* inference-snaps → gemma3 (base URL defaults to http://localhost:9090/v1)
|
|
144
|
+
* groq → qwen/qwen3-32b
|
|
145
|
+
* ollama → gemma4:e2b (base URL defaults to http://localhost:11434)
|
|
123
146
|
*/
|
|
124
147
|
export declare function createLLMClientFromEnv(): LLMClient;
|
|
125
148
|
/**
|
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;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"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"}
|
package/dist/llm/client.js
CHANGED
|
@@ -3,49 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Single interface for all LLM providers with fallback and rate limiting
|
|
5
5
|
*/
|
|
6
|
-
// =============================================================================
|
|
7
|
-
// Log redaction
|
|
8
|
-
// =============================================================================
|
|
9
|
-
const SENSITIVE_KEYS = new Set([
|
|
10
|
-
'apiKey',
|
|
11
|
-
'api_key',
|
|
12
|
-
'authorization',
|
|
13
|
-
'Authorization',
|
|
14
|
-
'x-ai-api-key',
|
|
15
|
-
'X-AI-Api-Key',
|
|
16
|
-
'token',
|
|
17
|
-
'secret',
|
|
18
|
-
'password',
|
|
19
|
-
'encryptedKey',
|
|
20
|
-
'encrypted_key',
|
|
21
|
-
]);
|
|
22
|
-
/**
|
|
23
|
-
* Redact sensitive fields before passing an object to a logger.
|
|
24
|
-
* Replaces API keys, tokens, and authorization headers with `[REDACTED]`.
|
|
25
|
-
* Recurses into nested plain objects; leaves arrays and primitives as-is.
|
|
26
|
-
*/
|
|
27
|
-
export function redactSensitiveFields(obj) {
|
|
28
|
-
const result = {};
|
|
29
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
30
|
-
if (SENSITIVE_KEYS.has(key)) {
|
|
31
|
-
result[key] = '[REDACTED]';
|
|
32
|
-
}
|
|
33
|
-
else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
34
|
-
result[key] = redactSensitiveFields(value);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
result[key] = value;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
6
|
import { decryptApiKey } from '@revealui/db/crypto';
|
|
43
7
|
import { tenantProviderConfigs, userApiKeys } from '@revealui/db/schema';
|
|
8
|
+
import { CircuitBreaker, CircuitBreakerOpenError, } from '@revealui/resilience';
|
|
44
9
|
import { and, eq } from 'drizzle-orm';
|
|
45
10
|
import { GroqProvider } from './providers/groq.js';
|
|
46
11
|
import { InferenceSnapsProvider, } from './providers/inference-snaps.js';
|
|
47
12
|
import { OllamaProvider } from './providers/ollama.js';
|
|
48
|
-
import { VultrProvider } from './providers/vultr.js';
|
|
49
13
|
import { ResponseCache } from './response-cache.js';
|
|
50
14
|
import { SemanticCache, } from './semantic-cache.js';
|
|
51
15
|
import { estimateRequest as _estimateRequestTokens } from './token-counter.js';
|
|
@@ -58,6 +22,8 @@ export class LLMClient {
|
|
|
58
22
|
responseCache;
|
|
59
23
|
semanticCache;
|
|
60
24
|
healthMonitor;
|
|
25
|
+
circuitBreaker;
|
|
26
|
+
fallbackCircuitBreaker;
|
|
61
27
|
/** Tracks the last resolved API key so we only recreate the provider when it changes */
|
|
62
28
|
currentApiKey;
|
|
63
29
|
constructor(config) {
|
|
@@ -78,6 +44,17 @@ export class LLMClient {
|
|
|
78
44
|
}
|
|
79
45
|
// Wire health monitor if provided
|
|
80
46
|
this.healthMonitor = config.healthMonitor;
|
|
47
|
+
// Per-provider circuit breakers — isolate outages so one provider's failure
|
|
48
|
+
// doesn't block calls to a different provider
|
|
49
|
+
const cbConfig = {
|
|
50
|
+
failureThreshold: config.circuitBreakerFailureThreshold ?? 5,
|
|
51
|
+
resetTimeout: config.circuitBreakerResetTimeout ?? 30_000,
|
|
52
|
+
successThreshold: 2,
|
|
53
|
+
};
|
|
54
|
+
this.circuitBreaker = new CircuitBreaker(cbConfig);
|
|
55
|
+
if (config.fallbackProvider) {
|
|
56
|
+
this.fallbackCircuitBreaker = new CircuitBreaker(cbConfig);
|
|
57
|
+
}
|
|
81
58
|
// Wire dedicated embed provider if supplied
|
|
82
59
|
this.embedProviderOverride = config.embedProvider;
|
|
83
60
|
// Create primary provider
|
|
@@ -101,8 +78,6 @@ export class LLMClient {
|
|
|
101
78
|
}
|
|
102
79
|
createProvider(type, config) {
|
|
103
80
|
switch (type) {
|
|
104
|
-
case 'vultr':
|
|
105
|
-
return new VultrProvider(config);
|
|
106
81
|
case 'groq':
|
|
107
82
|
return new GroqProvider(config);
|
|
108
83
|
case 'ollama':
|
|
@@ -221,7 +196,7 @@ export class LLMClient {
|
|
|
221
196
|
const callStart = Date.now();
|
|
222
197
|
try {
|
|
223
198
|
this.recordRequest();
|
|
224
|
-
const response = await this.provider.chat(messages, options);
|
|
199
|
+
const response = await this.circuitBreaker.execute(() => this.provider.chat(messages, options));
|
|
225
200
|
this.healthMonitor?.recordCall(this.config.provider, Date.now() - callStart);
|
|
226
201
|
// Store in semantic cache (if enabled)
|
|
227
202
|
if (this.semanticCache) {
|
|
@@ -251,11 +226,14 @@ export class LLMClient {
|
|
|
251
226
|
this.healthMonitor?.recordCall(this.config.provider, Date.now() - callStart, error instanceof Error ? error : new Error(String(error)));
|
|
252
227
|
// Try fallback if available
|
|
253
228
|
if (this.fallbackProvider && this.config.fallbackProvider) {
|
|
229
|
+
const fp = this.fallbackProvider;
|
|
254
230
|
const fallbackStart = Date.now();
|
|
255
231
|
try {
|
|
256
|
-
const
|
|
232
|
+
const fb = this.fallbackCircuitBreaker
|
|
233
|
+
? await this.fallbackCircuitBreaker.execute(() => fp.chat(messages, options))
|
|
234
|
+
: await fp.chat(messages, options);
|
|
257
235
|
this.healthMonitor?.recordCall(this.config.fallbackProvider, Date.now() - fallbackStart);
|
|
258
|
-
return
|
|
236
|
+
return fb;
|
|
259
237
|
}
|
|
260
238
|
catch (fallbackError) {
|
|
261
239
|
this.healthMonitor?.recordCall(this.config.fallbackProvider, Date.now() - fallbackStart, fallbackError instanceof Error ? fallbackError : new Error(String(fallbackError)));
|
|
@@ -274,13 +252,16 @@ export class LLMClient {
|
|
|
274
252
|
const embedProvider = this.embedProviderOverride ?? this.provider;
|
|
275
253
|
try {
|
|
276
254
|
this.recordRequest();
|
|
277
|
-
return await embedProvider.embed(text, options);
|
|
255
|
+
return await this.circuitBreaker.execute(() => embedProvider.embed(text, options));
|
|
278
256
|
}
|
|
279
257
|
catch (error) {
|
|
280
258
|
// Try fallback if available (only when using the primary provider path)
|
|
281
259
|
if (!this.embedProviderOverride && this.fallbackProvider) {
|
|
260
|
+
const fp = this.fallbackProvider;
|
|
282
261
|
try {
|
|
283
|
-
return
|
|
262
|
+
return this.fallbackCircuitBreaker
|
|
263
|
+
? await this.fallbackCircuitBreaker.execute(() => fp.embed(text, options))
|
|
264
|
+
: await fp.embed(text, options);
|
|
284
265
|
}
|
|
285
266
|
catch {
|
|
286
267
|
throw new Error(`Both primary and fallback providers failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -296,6 +277,11 @@ export class LLMClient {
|
|
|
296
277
|
throw new Error('Rate limit exceeded');
|
|
297
278
|
}
|
|
298
279
|
try {
|
|
280
|
+
// Circuit breaker check — streaming can't use execute() wrapper
|
|
281
|
+
// so we check state and record outcomes manually
|
|
282
|
+
if (this.circuitBreaker.isOpen()) {
|
|
283
|
+
throw new CircuitBreakerOpenError(`llm-${this.config.provider}`);
|
|
284
|
+
}
|
|
299
285
|
this.recordRequest();
|
|
300
286
|
yield* this.provider.stream(messages, options);
|
|
301
287
|
}
|
|
@@ -303,6 +289,9 @@ export class LLMClient {
|
|
|
303
289
|
// Try fallback if available
|
|
304
290
|
if (this.fallbackProvider) {
|
|
305
291
|
try {
|
|
292
|
+
if (this.fallbackCircuitBreaker?.isOpen()) {
|
|
293
|
+
throw new CircuitBreakerOpenError(`llm-${this.config.fallbackProvider}`);
|
|
294
|
+
}
|
|
306
295
|
yield* this.fallbackProvider.stream(messages, options);
|
|
307
296
|
}
|
|
308
297
|
catch {
|
|
@@ -321,6 +310,25 @@ export class LLMClient {
|
|
|
321
310
|
estimateRequest(messages) {
|
|
322
311
|
return _estimateRequestTokens(messages, this.config.model ?? '');
|
|
323
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Get circuit breaker stats for the primary and fallback providers.
|
|
315
|
+
*/
|
|
316
|
+
getCircuitBreakerStats() {
|
|
317
|
+
return {
|
|
318
|
+
primary: {
|
|
319
|
+
name: `llm-${this.config.provider}`,
|
|
320
|
+
state: this.circuitBreaker.getState(),
|
|
321
|
+
stats: this.circuitBreaker.getStats(),
|
|
322
|
+
},
|
|
323
|
+
fallback: this.fallbackCircuitBreaker && this.config.fallbackProvider
|
|
324
|
+
? {
|
|
325
|
+
name: `llm-${this.config.fallbackProvider}`,
|
|
326
|
+
state: this.fallbackCircuitBreaker.getState(),
|
|
327
|
+
stats: this.fallbackCircuitBreaker.getStats(),
|
|
328
|
+
}
|
|
329
|
+
: undefined,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
324
332
|
/**
|
|
325
333
|
* Get the provider health monitor if one was configured.
|
|
326
334
|
*/
|
|
@@ -360,13 +368,20 @@ export class LLMClient {
|
|
|
360
368
|
* Create an LLM client from environment variables.
|
|
361
369
|
*
|
|
362
370
|
* When LLM_PROVIDER is not set, auto-detects the provider by checking env vars
|
|
363
|
-
* in priority order: INFERENCE_SNAPS → GROQ → OLLAMA.
|
|
371
|
+
* in priority order: INFERENCE_SNAPS → GROQ → OLLAMA. If none are set, defaults
|
|
372
|
+
* to Inference Snaps at http://localhost:9090/v1 (Ubuntu local) and emits a
|
|
373
|
+
* one-line stderr warning so the implicit default is discoverable in logs.
|
|
364
374
|
*
|
|
365
375
|
* All providers use OpenAI-compatible APIs. No proprietary provider SDKs.
|
|
366
376
|
*
|
|
377
|
+
* Canonical Inference Snaps is the reference local provider on Ubuntu — offline,
|
|
378
|
+
* silicon-optimized, no API key required. See `providers/inference-snaps.ts` for
|
|
379
|
+
* install docs (`sudo snap install gemma3`, etc.).
|
|
380
|
+
*
|
|
367
381
|
* Provider defaults:
|
|
368
|
-
*
|
|
369
|
-
*
|
|
382
|
+
* inference-snaps → gemma3 (base URL defaults to http://localhost:9090/v1)
|
|
383
|
+
* groq → qwen/qwen3-32b
|
|
384
|
+
* ollama → gemma4:e2b (base URL defaults to http://localhost:11434)
|
|
370
385
|
*/
|
|
371
386
|
export function createLLMClientFromEnv() {
|
|
372
387
|
// Auto-detect provider when LLM_PROVIDER is not explicitly set
|
|
@@ -384,18 +399,14 @@ export function createLLMClientFromEnv() {
|
|
|
384
399
|
provider = 'ollama';
|
|
385
400
|
}
|
|
386
401
|
else {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
402
|
+
// Zero-config Ubuntu default: assume Inference Snaps on the standard
|
|
403
|
+
// local port. Operator sees the warning once at boot.
|
|
404
|
+
provider = 'inference-snaps';
|
|
390
405
|
}
|
|
391
406
|
let apiKey;
|
|
392
407
|
let baseURL;
|
|
393
408
|
let defaultModel;
|
|
394
|
-
if (provider === '
|
|
395
|
-
apiKey = process.env.VULTR_API_KEY;
|
|
396
|
-
baseURL = process.env.VULTR_BASE_URL;
|
|
397
|
-
}
|
|
398
|
-
else if (provider === 'huggingface') {
|
|
409
|
+
if (provider === 'huggingface') {
|
|
399
410
|
apiKey = process.env.HF_TOKEN;
|
|
400
411
|
baseURL = process.env.HF_MODEL_URL;
|
|
401
412
|
}
|
|
@@ -413,12 +424,14 @@ export function createLLMClientFromEnv() {
|
|
|
413
424
|
}
|
|
414
425
|
else if (provider === 'inference-snaps') {
|
|
415
426
|
apiKey = 'inference-snaps'; // inference-snaps ignores the API key
|
|
416
|
-
|
|
427
|
+
// Defaults to Canonical's Inference Snap local service on port 9090; override
|
|
428
|
+
// via INFERENCE_SNAPS_BASE_URL when the snap listens on a non-default port.
|
|
429
|
+
baseURL = process.env.INFERENCE_SNAPS_BASE_URL ?? 'http://localhost:9090/v1';
|
|
417
430
|
defaultModel = 'gemma3';
|
|
418
431
|
}
|
|
419
432
|
if (!apiKey) {
|
|
420
433
|
throw new Error(`API key not found for provider "${provider}". Set the corresponding env var ` +
|
|
421
|
-
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL,
|
|
434
|
+
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL, or HF_TOKEN).`);
|
|
422
435
|
}
|
|
423
436
|
return new LLMClient({
|
|
424
437
|
provider,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-validator.d.ts","sourceRoot":"","sources":["../../src/llm/key-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,wBAAwB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAezF;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,
|
|
1
|
+
{"version":3,"file":"key-validator.d.ts","sourceRoot":"","sources":["../../src/llm/key-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,wBAAwB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAezF;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,CA2CnC"}
|
|
@@ -41,22 +41,6 @@ export async function validateProviderKey(provider, apiKey) {
|
|
|
41
41
|
// Any other non-OK status (429, 500 etc.) - treat as reachable but unknown
|
|
42
42
|
return { valid: false, error: `Groq validation failed: HTTP ${res.status}` };
|
|
43
43
|
}
|
|
44
|
-
case 'anthropic': {
|
|
45
|
-
// Anthropic has no free read endpoint. Validate by key format only.
|
|
46
|
-
// Valid Anthropic keys start with "sk-ant-api".
|
|
47
|
-
if (!apiKey.startsWith('sk-ant-api')) {
|
|
48
|
-
return { valid: false, error: 'Anthropic API key must start with "sk-ant-api"' };
|
|
49
|
-
}
|
|
50
|
-
return { valid: true };
|
|
51
|
-
}
|
|
52
|
-
case 'openai': {
|
|
53
|
-
// Validate by format - keys start with "sk-"
|
|
54
|
-
// (Per LLM policy, OpenAI API calls are blocked until we have revenue.)
|
|
55
|
-
if (!apiKey.startsWith('sk-')) {
|
|
56
|
-
return { valid: false, error: 'OpenAI API key must start with "sk-"' };
|
|
57
|
-
}
|
|
58
|
-
return { valid: true };
|
|
59
|
-
}
|
|
60
44
|
case 'huggingface': {
|
|
61
45
|
const res = await probeFetch('https://huggingface.co/api/whoami-v2', {
|
|
62
46
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
@@ -68,17 +52,6 @@ export async function validateProviderKey(provider, apiKey) {
|
|
|
68
52
|
}
|
|
69
53
|
return { valid: false, error: `HuggingFace validation failed: HTTP ${res.status}` };
|
|
70
54
|
}
|
|
71
|
-
case 'vultr': {
|
|
72
|
-
// Vultr Serverless Inference API (OpenAI-compatible)
|
|
73
|
-
const res = await probeFetch('https://api.vultrinference.com/v1/models', {
|
|
74
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
75
|
-
});
|
|
76
|
-
if (res.ok)
|
|
77
|
-
return { valid: true };
|
|
78
|
-
if (res.status === 401)
|
|
79
|
-
return { valid: false, error: 'Invalid Vultr API key' };
|
|
80
|
-
return { valid: false, error: `Vultr validation failed: HTTP ${res.status}` };
|
|
81
|
-
}
|
|
82
55
|
case 'ollama': {
|
|
83
56
|
// Ollama is local - we cannot reliably probe it from the server.
|
|
84
57
|
// Accept the key as-is (Ollama doesn't use API keys anyway).
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* Local inference via Canonical's inference-snaps OpenAI-compatible API.
|
|
5
5
|
* No API key required. Zero cost, fully offline, hardware-optimized.
|
|
6
6
|
*
|
|
7
|
-
* Supported models (snaps)
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* Supported models (snaps), per Canonical's official catalog at
|
|
8
|
+
* https://documentation.ubuntu.com/inference-snaps/reference/snaps/ :
|
|
9
|
+
* gemma3 - general LLM + vision (text/image in, text out)
|
|
10
|
+
* deepseek-r1 - reasoning LLM (chat completions)
|
|
11
|
+
* qwen-vl - vision-language model (image + text)
|
|
12
|
+
* nemotron-3-nano - general LLM (reasoning + non-reasoning, text only)
|
|
13
|
+
* nemotron-3-nano-omni - multimodal (text/image/video/audio in, text out)
|
|
12
14
|
*
|
|
13
15
|
* Install a model:
|
|
14
16
|
* sudo snap install gemma3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inference-snaps.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/inference-snaps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"inference-snaps.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/inference-snaps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,OAAO,EACR,MAAM,WAAW,CAAC;AAGnB,MAAM,WAAW,4BAA6B,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,sBAAuB,YAAW,WAAW;IACxD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,EAAE,4BAA4B;IAahD,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;IAI1E,KAAK,CACT,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EACvB,QAAQ,CAAC,EAAE,eAAe,GACzB,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;CAsBpC"}
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
* Local inference via Canonical's inference-snaps OpenAI-compatible API.
|
|
5
5
|
* No API key required. Zero cost, fully offline, hardware-optimized.
|
|
6
6
|
*
|
|
7
|
-
* Supported models (snaps)
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* Supported models (snaps), per Canonical's official catalog at
|
|
8
|
+
* https://documentation.ubuntu.com/inference-snaps/reference/snaps/ :
|
|
9
|
+
* gemma3 - general LLM + vision (text/image in, text out)
|
|
10
|
+
* deepseek-r1 - reasoning LLM (chat completions)
|
|
11
|
+
* qwen-vl - vision-language model (image + text)
|
|
12
|
+
* nemotron-3-nano - general LLM (reasoning + non-reasoning, text only)
|
|
13
|
+
* nemotron-3-nano-omni - multimodal (text/image/video/audio in, text out)
|
|
12
14
|
*
|
|
13
15
|
* Install a model:
|
|
14
16
|
* sudo snap install gemma3
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* OpenAI-Compatible Provider
|
|
3
3
|
*
|
|
4
4
|
* Base implementation for any LLM API that follows the OpenAI chat/completions
|
|
5
|
-
* format. Used by: Ollama, Groq, Inference Snaps
|
|
5
|
+
* format. Used by: Ollama, Groq, Inference Snaps.
|
|
6
6
|
* NOT for direct OpenAI usage - RevealUI uses open-source models only.
|
|
7
7
|
*/
|
|
8
8
|
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMProviderConfig, LLMResponse, LLMStreamOptions, Message } from './base.js';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* OpenAI-Compatible Provider
|
|
3
3
|
*
|
|
4
4
|
* Base implementation for any LLM API that follows the OpenAI chat/completions
|
|
5
|
-
* format. Used by: Ollama, Groq, Inference Snaps
|
|
5
|
+
* format. Used by: Ollama, Groq, Inference Snaps.
|
|
6
6
|
* NOT for direct OpenAI usage - RevealUI uses open-source models only.
|
|
7
7
|
*/
|
|
8
8
|
const authorizationHeader = 'Authorization';
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* Provides 100% cost savings on cache hits vs Anthropic's 90% token-level savings.
|
|
6
6
|
*
|
|
7
7
|
* Use cases:
|
|
8
|
-
* -
|
|
9
|
-
* - OpenAI (doesn't have prompt caching)
|
|
8
|
+
* - Groq (doesn't have prompt caching)
|
|
10
9
|
* - Any provider without built-in caching
|
|
11
10
|
* - Supplement to Anthropic prompt caching for exact duplicates
|
|
12
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/llm/response-cache.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/llm/response-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE7E,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,CAAC;IACnE,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,KAAK,CAAsD;IACnE,OAAO,CAAC,WAAW,CAAU;gBAEjB,OAAO,GAAE,oBAAyB;IAqB9C;;;;;;;OAOG;IACH,WAAW,CACT,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GACA,MAAM;IAqBT;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAiB5C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAShD;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAatB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;CACF;AAQD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAKpF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE;IACP,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,GACA;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB,CAcA"}
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* Provides 100% cost savings on cache hits vs Anthropic's 90% token-level savings.
|
|
6
6
|
*
|
|
7
7
|
* Use cases:
|
|
8
|
-
* -
|
|
9
|
-
* - OpenAI (doesn't have prompt caching)
|
|
8
|
+
* - Groq (doesn't have prompt caching)
|
|
10
9
|
* - Any provider without built-in caching
|
|
11
10
|
* - Supplement to Anthropic prompt caching for exact duplicates
|
|
12
11
|
*
|
package/dist/llm/server.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export * from './providers/groq.js';
|
|
|
10
10
|
export * from './providers/inference-snaps.js';
|
|
11
11
|
export * from './providers/ollama.js';
|
|
12
12
|
export * from './providers/openai-compat.js';
|
|
13
|
-
export * from './
|
|
13
|
+
export * from './workspace-provider-config.js';
|
|
14
14
|
//# sourceMappingURL=server.d.ts.map
|
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,CAAC;AAG5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAC;AAG5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAI7C,cAAc,gCAAgC,CAAC"}
|
package/dist/llm/server.js
CHANGED
|
@@ -12,4 +12,6 @@ export * from './providers/groq.js';
|
|
|
12
12
|
export * from './providers/inference-snaps.js';
|
|
13
13
|
export * from './providers/ollama.js';
|
|
14
14
|
export * from './providers/openai-compat.js';
|
|
15
|
-
|
|
15
|
+
// Export per-workspace provider registry (used by admin inference-config route
|
|
16
|
+
// to hydrate per-site config at boot + apply changes immediately on PUT)
|
|
17
|
+
export * from './workspace-provider-config.js';
|
|
@@ -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,CAAC;
|
|
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,CAAC;AAIpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAc5E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,MAAM,CAAkD;IAEhE;;;;;;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;IAkBnC;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAyChD;;;;;;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;IA+E3B;;;;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"}
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { UserPreferencesSchema } from '@revealui/contracts/entities';
|
|
8
8
|
import { createLogger } from '@revealui/core/observability/logger';
|
|
9
|
+
import { deepClone } from '@revealui/core/utils/deep-clone';
|
|
9
10
|
import { users } from '@revealui/db/schema';
|
|
10
11
|
import { eq } from 'drizzle-orm';
|
|
11
12
|
import { LWWRegister } from '../crdt/lww-register.js';
|
|
12
13
|
import { DatabaseConnectionError, DatabaseConstraintError, DatabaseOperationError, NotFoundError, ValidationError, } from '../errors/index.js';
|
|
13
|
-
import { deepClone } from '../utils/deep-clone.js';
|
|
14
14
|
import { findUserById } from '../utils/sql-helpers.js';
|
|
15
15
|
// =============================================================================
|
|
16
16
|
// User Preferences Manager
|
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export type { EntityType } from './node-id-service.js';
|
|
7
7
|
export { NodeIdService } from './node-id-service.js';
|
|
8
|
+
export type { Contradiction, ReconciledMemory, ReconciliationResult, SharedFactInput, } from './reconciliation-service.js';
|
|
9
|
+
export { buildReconciliationPrompt, parseReconciliationResponse, reconcileHeuristic, } from './reconciliation-service.js';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|