@revealui/ai 0.3.0 → 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/llm/client.d.ts +33 -4
- package/dist/llm/client.d.ts.map +1 -1
- package/dist/llm/client.js +70 -21
- 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/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/utils/sql-helpers.d.ts +19 -25
- package/dist/memory/utils/sql-helpers.d.ts.map +1 -1
- package/dist/memory/utils/sql-helpers.js +34 -81
- 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/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 +13 -11
- 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';
|
package/dist/llm/client.d.ts
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* Single interface for all LLM providers with fallback and rate limiting
|
|
5
5
|
*/
|
|
6
6
|
import type { Database } from '@revealui/db/client';
|
|
7
|
+
import { CircuitBreaker } from '@revealui/resilience';
|
|
7
8
|
import type { AuditStore } from '../audit/store.js';
|
|
8
9
|
import type { ProviderHealthMonitor } from './provider-health.js';
|
|
9
10
|
import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
|
|
10
11
|
import { type CacheStats, type ResponseCacheOptions } from './response-cache.js';
|
|
11
12
|
import { type SemanticCacheOptions, type SemanticCacheStats } from './semantic-cache.js';
|
|
12
|
-
export type LLMProviderType = '
|
|
13
|
+
export type LLMProviderType = 'groq' | 'ollama' | 'huggingface' | 'inference-snaps';
|
|
13
14
|
export interface LLMClientConfig {
|
|
14
15
|
provider: LLMProviderType;
|
|
15
16
|
apiKey: string;
|
|
@@ -46,6 +47,10 @@ export interface LLMClientConfig {
|
|
|
46
47
|
semanticCacheOptions?: SemanticCacheOptions;
|
|
47
48
|
/** Optional health monitor - records latency + error rate per provider */
|
|
48
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;
|
|
49
54
|
}
|
|
50
55
|
export declare class LLMClient {
|
|
51
56
|
private provider;
|
|
@@ -56,6 +61,8 @@ export declare class LLMClient {
|
|
|
56
61
|
private responseCache?;
|
|
57
62
|
private semanticCache?;
|
|
58
63
|
private healthMonitor?;
|
|
64
|
+
private circuitBreaker;
|
|
65
|
+
private fallbackCircuitBreaker?;
|
|
59
66
|
/** Tracks the last resolved API key so we only recreate the provider when it changes */
|
|
60
67
|
private currentApiKey;
|
|
61
68
|
constructor(config: LLMClientConfig);
|
|
@@ -78,6 +85,21 @@ export declare class LLMClient {
|
|
|
78
85
|
tokens: number;
|
|
79
86
|
estimatedCostUsd: number;
|
|
80
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
|
+
};
|
|
81
103
|
/**
|
|
82
104
|
* Get the provider health monitor if one was configured.
|
|
83
105
|
*/
|
|
@@ -107,13 +129,20 @@ export declare class LLMClient {
|
|
|
107
129
|
* Create an LLM client from environment variables.
|
|
108
130
|
*
|
|
109
131
|
* When LLM_PROVIDER is not set, auto-detects the provider by checking env vars
|
|
110
|
-
* 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.
|
|
111
135
|
*
|
|
112
136
|
* All providers use OpenAI-compatible APIs. No proprietary provider SDKs.
|
|
113
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
|
+
*
|
|
114
142
|
* Provider defaults:
|
|
115
|
-
*
|
|
116
|
-
*
|
|
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)
|
|
117
146
|
*/
|
|
118
147
|
export declare function createLLMClientFromEnv(): LLMClient;
|
|
119
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;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
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
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { decryptApiKey } from '@revealui/db/crypto';
|
|
7
7
|
import { tenantProviderConfigs, userApiKeys } from '@revealui/db/schema';
|
|
8
|
+
import { CircuitBreaker, CircuitBreakerOpenError, } from '@revealui/resilience';
|
|
8
9
|
import { and, eq } from 'drizzle-orm';
|
|
9
10
|
import { GroqProvider } from './providers/groq.js';
|
|
10
11
|
import { InferenceSnapsProvider, } from './providers/inference-snaps.js';
|
|
11
12
|
import { OllamaProvider } from './providers/ollama.js';
|
|
12
|
-
import { VultrProvider } from './providers/vultr.js';
|
|
13
13
|
import { ResponseCache } from './response-cache.js';
|
|
14
14
|
import { SemanticCache, } from './semantic-cache.js';
|
|
15
15
|
import { estimateRequest as _estimateRequestTokens } from './token-counter.js';
|
|
@@ -22,6 +22,8 @@ export class LLMClient {
|
|
|
22
22
|
responseCache;
|
|
23
23
|
semanticCache;
|
|
24
24
|
healthMonitor;
|
|
25
|
+
circuitBreaker;
|
|
26
|
+
fallbackCircuitBreaker;
|
|
25
27
|
/** Tracks the last resolved API key so we only recreate the provider when it changes */
|
|
26
28
|
currentApiKey;
|
|
27
29
|
constructor(config) {
|
|
@@ -42,6 +44,17 @@ export class LLMClient {
|
|
|
42
44
|
}
|
|
43
45
|
// Wire health monitor if provided
|
|
44
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
|
+
}
|
|
45
58
|
// Wire dedicated embed provider if supplied
|
|
46
59
|
this.embedProviderOverride = config.embedProvider;
|
|
47
60
|
// Create primary provider
|
|
@@ -65,8 +78,6 @@ export class LLMClient {
|
|
|
65
78
|
}
|
|
66
79
|
createProvider(type, config) {
|
|
67
80
|
switch (type) {
|
|
68
|
-
case 'vultr':
|
|
69
|
-
return new VultrProvider(config);
|
|
70
81
|
case 'groq':
|
|
71
82
|
return new GroqProvider(config);
|
|
72
83
|
case 'ollama':
|
|
@@ -185,7 +196,7 @@ export class LLMClient {
|
|
|
185
196
|
const callStart = Date.now();
|
|
186
197
|
try {
|
|
187
198
|
this.recordRequest();
|
|
188
|
-
const response = await this.provider.chat(messages, options);
|
|
199
|
+
const response = await this.circuitBreaker.execute(() => this.provider.chat(messages, options));
|
|
189
200
|
this.healthMonitor?.recordCall(this.config.provider, Date.now() - callStart);
|
|
190
201
|
// Store in semantic cache (if enabled)
|
|
191
202
|
if (this.semanticCache) {
|
|
@@ -215,11 +226,14 @@ export class LLMClient {
|
|
|
215
226
|
this.healthMonitor?.recordCall(this.config.provider, Date.now() - callStart, error instanceof Error ? error : new Error(String(error)));
|
|
216
227
|
// Try fallback if available
|
|
217
228
|
if (this.fallbackProvider && this.config.fallbackProvider) {
|
|
229
|
+
const fp = this.fallbackProvider;
|
|
218
230
|
const fallbackStart = Date.now();
|
|
219
231
|
try {
|
|
220
|
-
const
|
|
232
|
+
const fb = this.fallbackCircuitBreaker
|
|
233
|
+
? await this.fallbackCircuitBreaker.execute(() => fp.chat(messages, options))
|
|
234
|
+
: await fp.chat(messages, options);
|
|
221
235
|
this.healthMonitor?.recordCall(this.config.fallbackProvider, Date.now() - fallbackStart);
|
|
222
|
-
return
|
|
236
|
+
return fb;
|
|
223
237
|
}
|
|
224
238
|
catch (fallbackError) {
|
|
225
239
|
this.healthMonitor?.recordCall(this.config.fallbackProvider, Date.now() - fallbackStart, fallbackError instanceof Error ? fallbackError : new Error(String(fallbackError)));
|
|
@@ -238,13 +252,16 @@ export class LLMClient {
|
|
|
238
252
|
const embedProvider = this.embedProviderOverride ?? this.provider;
|
|
239
253
|
try {
|
|
240
254
|
this.recordRequest();
|
|
241
|
-
return await embedProvider.embed(text, options);
|
|
255
|
+
return await this.circuitBreaker.execute(() => embedProvider.embed(text, options));
|
|
242
256
|
}
|
|
243
257
|
catch (error) {
|
|
244
258
|
// Try fallback if available (only when using the primary provider path)
|
|
245
259
|
if (!this.embedProviderOverride && this.fallbackProvider) {
|
|
260
|
+
const fp = this.fallbackProvider;
|
|
246
261
|
try {
|
|
247
|
-
return
|
|
262
|
+
return this.fallbackCircuitBreaker
|
|
263
|
+
? await this.fallbackCircuitBreaker.execute(() => fp.embed(text, options))
|
|
264
|
+
: await fp.embed(text, options);
|
|
248
265
|
}
|
|
249
266
|
catch {
|
|
250
267
|
throw new Error(`Both primary and fallback providers failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -260,6 +277,11 @@ export class LLMClient {
|
|
|
260
277
|
throw new Error('Rate limit exceeded');
|
|
261
278
|
}
|
|
262
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
|
+
}
|
|
263
285
|
this.recordRequest();
|
|
264
286
|
yield* this.provider.stream(messages, options);
|
|
265
287
|
}
|
|
@@ -267,6 +289,9 @@ export class LLMClient {
|
|
|
267
289
|
// Try fallback if available
|
|
268
290
|
if (this.fallbackProvider) {
|
|
269
291
|
try {
|
|
292
|
+
if (this.fallbackCircuitBreaker?.isOpen()) {
|
|
293
|
+
throw new CircuitBreakerOpenError(`llm-${this.config.fallbackProvider}`);
|
|
294
|
+
}
|
|
270
295
|
yield* this.fallbackProvider.stream(messages, options);
|
|
271
296
|
}
|
|
272
297
|
catch {
|
|
@@ -285,6 +310,25 @@ export class LLMClient {
|
|
|
285
310
|
estimateRequest(messages) {
|
|
286
311
|
return _estimateRequestTokens(messages, this.config.model ?? '');
|
|
287
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
|
+
}
|
|
288
332
|
/**
|
|
289
333
|
* Get the provider health monitor if one was configured.
|
|
290
334
|
*/
|
|
@@ -324,13 +368,20 @@ export class LLMClient {
|
|
|
324
368
|
* Create an LLM client from environment variables.
|
|
325
369
|
*
|
|
326
370
|
* When LLM_PROVIDER is not set, auto-detects the provider by checking env vars
|
|
327
|
-
* 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.
|
|
328
374
|
*
|
|
329
375
|
* All providers use OpenAI-compatible APIs. No proprietary provider SDKs.
|
|
330
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
|
+
*
|
|
331
381
|
* Provider defaults:
|
|
332
|
-
*
|
|
333
|
-
*
|
|
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)
|
|
334
385
|
*/
|
|
335
386
|
export function createLLMClientFromEnv() {
|
|
336
387
|
// Auto-detect provider when LLM_PROVIDER is not explicitly set
|
|
@@ -348,18 +399,14 @@ export function createLLMClientFromEnv() {
|
|
|
348
399
|
provider = 'ollama';
|
|
349
400
|
}
|
|
350
401
|
else {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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';
|
|
354
405
|
}
|
|
355
406
|
let apiKey;
|
|
356
407
|
let baseURL;
|
|
357
408
|
let defaultModel;
|
|
358
|
-
if (provider === '
|
|
359
|
-
apiKey = process.env.VULTR_API_KEY;
|
|
360
|
-
baseURL = process.env.VULTR_BASE_URL;
|
|
361
|
-
}
|
|
362
|
-
else if (provider === 'huggingface') {
|
|
409
|
+
if (provider === 'huggingface') {
|
|
363
410
|
apiKey = process.env.HF_TOKEN;
|
|
364
411
|
baseURL = process.env.HF_MODEL_URL;
|
|
365
412
|
}
|
|
@@ -377,12 +424,14 @@ export function createLLMClientFromEnv() {
|
|
|
377
424
|
}
|
|
378
425
|
else if (provider === 'inference-snaps') {
|
|
379
426
|
apiKey = 'inference-snaps'; // inference-snaps ignores the API key
|
|
380
|
-
|
|
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';
|
|
381
430
|
defaultModel = 'gemma3';
|
|
382
431
|
}
|
|
383
432
|
if (!apiKey) {
|
|
384
433
|
throw new Error(`API key not found for provider "${provider}". Set the corresponding env var ` +
|
|
385
|
-
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL,
|
|
434
|
+
`(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL, or HF_TOKEN).`);
|
|
386
435
|
}
|
|
387
436
|
return new LLMClient({
|
|
388
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';
|
|
@@ -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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/services/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/services/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,kBAAkB,GACnB,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconciliation Service - Fact resolution for multi-agent memory.
|
|
3
|
+
*
|
|
4
|
+
* Reads shared facts from a coordination session, groups related facts,
|
|
5
|
+
* deduplicates, and resolves contradictions. Produces reconciled memories
|
|
6
|
+
* for Layer 3.
|
|
7
|
+
*
|
|
8
|
+
* Layer 3 of the multi-agent shared memory architecture.
|
|
9
|
+
*
|
|
10
|
+
* LICENSING BOUNDARY:
|
|
11
|
+
* - `reconcileHeuristic()` is the production path — no external API calls,
|
|
12
|
+
* safe for all tiers including free customers.
|
|
13
|
+
* - `buildReconciliationPrompt()` and `parseReconciliationResponse()` are
|
|
14
|
+
* reference implementations for internal/developer use only. They build
|
|
15
|
+
* a prompt string but DO NOT call any LLM API. If wired to an LLM provider,
|
|
16
|
+
* the caller is responsible for API pricing and usage compliance.
|
|
17
|
+
* - Customer-facing reconciliation MUST use the heuristic path or a
|
|
18
|
+
* self-hosted model (e.g. Ollama). Do not proxy third-party LLM APIs
|
|
19
|
+
* to end users without a commercial API agreement with the provider.
|
|
20
|
+
*/
|
|
21
|
+
export interface SharedFactInput {
|
|
22
|
+
id: string;
|
|
23
|
+
agentId: string;
|
|
24
|
+
content: string;
|
|
25
|
+
factType: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
tags: string[];
|
|
28
|
+
sourceRef?: Record<string, unknown> | null;
|
|
29
|
+
}
|
|
30
|
+
export interface ReconciledMemory {
|
|
31
|
+
content: string;
|
|
32
|
+
type: string;
|
|
33
|
+
sourceFactIds: string[];
|
|
34
|
+
confidence: number;
|
|
35
|
+
}
|
|
36
|
+
export interface Contradiction {
|
|
37
|
+
factIds: string[];
|
|
38
|
+
description: string;
|
|
39
|
+
resolution: string;
|
|
40
|
+
}
|
|
41
|
+
export interface ReconciliationResult {
|
|
42
|
+
canonicalFacts: ReconciledMemory[];
|
|
43
|
+
contradictions: Contradiction[];
|
|
44
|
+
duplicates: string[][];
|
|
45
|
+
summary: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the reconciliation prompt for an LLM.
|
|
49
|
+
* The prompt asks the model to analyze facts from multiple agents and
|
|
50
|
+
* produce a structured reconciliation result.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildReconciliationPrompt(facts: SharedFactInput[], scratchpadContent?: Record<string, unknown>): string;
|
|
53
|
+
/**
|
|
54
|
+
* Parse the LLM response into a structured reconciliation result.
|
|
55
|
+
* Maps 1-based fact indices back to actual fact IDs.
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseReconciliationResponse(response: string, facts: SharedFactInput[]): ReconciliationResult;
|
|
58
|
+
/**
|
|
59
|
+
* Simple heuristic reconciliation (no LLM required).
|
|
60
|
+
* Deduplicates by normalized content and groups by type.
|
|
61
|
+
* Use this as a fallback when no LLM provider is configured.
|
|
62
|
+
*/
|
|
63
|
+
export declare function reconcileHeuristic(facts: SharedFactInput[]): ReconciliationResult;
|
|
64
|
+
//# sourceMappingURL=reconciliation-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciliation-service.d.ts","sourceRoot":"","sources":["../../../src/memory/services/reconciliation-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,eAAe,EAAE,EACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC1C,MAAM,CAuCR;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,eAAe,EAAE,GACvB,oBAAoB,CAsCtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,oBAAoB,CAsCjF"}
|